Sign in to follow this  
badderjet

"Binary Coded Decimal"?

Recommended Posts

I tried to make a COM radio in C, but when it came to source variables, the SDK said the com frequency's data type is BCD, i. e. binary coded decimal. So what the heck is that?!? :-hmmmAny Help's appreciated.Etienne

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

Gosh Etienne,You are taking me back to my old programmimg days here.{{{{Blowing the cobwebs out}}}}}If I recall correctly, it's something like this.Computers store and retrieve information in 8-bit bytes, or groups of bytes called words (32 bits), or half words. There is always a parity bit used to ensure there are no circuit problems. In the early days, BCD used 7 bits of an 8 bit byte to store data, the 8th bit for parity.The number of bits available for data also constrained the character set size, fewer bits, less characters available. The firmware (CMOS) fetched data based on which format was used. BCD = 7 bits with 1 parity. EBCDIC used 8 bits with a 9th as parity.Is this too confusing?My guess is that C does not output BCD but rather ASCII format or you have defined the variable wrong.Sorry if this explanation doesn't help ... too much water over the dam. :-)Milton

Share this post


Link to post
Share on other sites

Actually binary coded decimal works as follows: each nibble in the word (that is, each group of four bits) is encoded with the binary equivalent of 0-9. Each successive nibble then represents one decimal place. Thus:0001-0010 is 1-2 which is 1 x 10 + 2 x 1 = 12. 0011-0100 0001-0010 is 3x1000 + 8x100 + 1x10 + 2 = 3812. The beauty of it is that you can easily access any decimal place in the word with a simple series of bit shift instructions, a feat which is obviously much harder with true binary. Hope this helps!Regards,Philip.

Share this post


Link to post
Share on other sites

As I think about it, it makes perfect sense to use this format for radios since in FS you want to be able to change any given digit without affecting the rest. BCD allows you to do this with a simple series of AND, bit shift, INC/DEC, and OR operations. Using a long int would require multiplication.

Share this post


Link to post
Share on other sites

Yeah, seems really to make perfect sense, but... Oh well! That sounds quite difficult... I think I just gotta wait a bit until I make radios... Coz I just don't know what to do with such BCD, how to use it in callbacks etc.. Whew, that's sum stuff! :-)Thanks anyway! :-hahEtienne :-wave

Share this post


Link to post
Share on other sites

It isn't too difficult. As far as I know here are some conversions included in sd2gau13.zip for C gauges. For XML I placed some here some time ago. To display a BCD coded frequency in C gauges with MAKE_STRINGs you can take into account that BCD coded numbers are very similar to hexadecimal numbers. So a string callback can look like this:...sprintf(pelement->string,"1%02x.%02x",pelement->source_var[0].var_value.d/100,pelement->source_var[0].var_value.d%100);...The ".d" member because the frequencies (VOR1,VOR2,COM1,COM2 +STDBY) are always stored in this member of the source var. The format specifier "x" to display in hexadecimal code. The above mentioned frequencies are not the whole set, the leading 1 of 1xx.xx MHz isn't stored, and the first two digits represent the whole frequency in MHz, the last two digit the frequency in 10kHz. So the frequency is clipped in two sets, the missing one is placed before it.It might be good to display the frequency first without much modifications to see the following steps easier , try first:sprintf(pelement->string,"%04x",pelement->source_var[0].var_value.d);before you try the other sprintf.In reality the frequencies are actually transferred between intruments not exactly in this fashion, but very similar, BCD coding for each digit on 4-wire lines.Arne Bartels

Share this post


Link to post
Share on other sites

Ah, the advent of modern avionics! I use to test and evaluate aircraft avionics systems. One job had to do with replacing the AN/ARC-51 UHF Radio with the AN/ARC-159V5 UHF Radio. The smart engineers at Collins Radio devised various ARC-159V(X) replacement radios for various older UHF Radios. One of the selling points was no modification to the aircraft wiring.The ARC-51 control box was in the cockpit while the Transeiver was located in an equipment bay. It used BCD from the control box to the transeiver. The number of wires from the control box to the transeiver was approximately one inch in diameter, many of the wires were for switching the frequencies. The ARC-159 used the same connector but few of the wires. Frequencies were changed by using a clock reference and frequency information sent to the new transeiver over just four wires, two for the clock reference and two for the frequency information. The frequency information lines also sent other data to the radio, as well.The AN/ARC-159V1 UHF Radio was an all inclusive UHF Radio built into the cockpit thus eliminating all the exist wiring and weight of the older radios.Just think of the advent of the cell phone. The limiting size is our clumsy big fingers.

Share this post


Link to post
Share on other sites

Oh well, thanks for the additional information, maybe I gotta give it a shot later today.Thank youEtienne

Share this post


Link to post
Share on other sites

I see these explanations about how to interpret a Binary Coded Decimal, but what data type in C can hold these?I'm sorry to bump an old (apparently)topic, but I am working on Navigation Display (using GDI+) and am "pre-coding" the gauge. I would like to know before hand which type to declare this for my buffer.Thanks!

Share this post


Link to post
Share on other sites

See sd2gau23.zip; use execute_calculator_code to get good old decimal and forget all about using/converting BCD!-Dai

Share this post


Link to post
Share on other sites

Thanks, Dai.I glanced through this at work today (I don't remember my password to the forums, so I couldn't get back to you earlier with this), and it looked like that execute_calculator_code is for XML?Is there a C version?--Matt

Share this post


Link to post
Share on other sites

>Thanks, Dai.>>I glanced through this at work today (I don't remember my>password to the forums, so I couldn't get back to you earlier>with this), and it looked like that execute_calculator_code is>for XML?>>Is there a C version?>>--MattThat IS the "C version!"execute_calculator_code is the name of a function(); in the gauges.h file, and will request/receive any XML token variable for use in a C gauge.You can see a full explanation of how this works on my "Panel & Gauge Wiki" here:http://forums.flightsim.com/fswiki/index.p...les_in_C_Gauges

Share this post


Link to post
Share on other sites

Note that the COM and NAV frequencies assume the highest order digit in the instrument (gauge) is 1 (one), it is not recorded in the BCD representation. So for a frequency of 136.25 the recorded BCD is 3625.These are the BITs in a 16 bit number with their order value for a BCD encoded number:8 4 2 1 . 8 4 2 1 . 8 4 2 1 . 8 4 2 1This is 2 bytes and can store a 4 digit BDC16 encoded number, one BCD digit in each half byte. BCO16 is the same as BCD16, BCD32 is 4 bytes (twice as big) for an 8 digit BCD encoded number.Suppose we have a BCD encoded number, 3625, we will then have these BITs:0011 0110 0010 01014th, 3rd, 2nd, 1st digit (from right to left, low order to high order)Well that's just fine, but how do you extract the digits in C:The bitwise AND (&) operator masks the bits you are not interested in.Extract first digit (from right to left):digit1 = source & 15;notes: source AND 15, note that 8+4+2+1=15Extract second digit (from right to left):digit2 = (source >> 4) & 15;notes: source SHIFT RIGHT 4 BITS then AND 15Extract third digit (from right to left):digit3 = (source >> 8) & 15;Extract fourth digit (from right to left):digit4 = (source >> 12) & 15;Same for BCD32, you just keep shifting more BITs each time (shift 16, 20, 24 and 28).So... How do you set the BITs?To set all the BITs at once (as in changing the COM radio settings):result = 0; We always want to start clean, there is a technicality in C and other languages that when you shift BITs you can rotate them or fill with zeros. Starting with zero allows you to do either without thinking too much about unforseen consequences.The following is for setting the 4 digits all at once and must be performed in the given order. The bitwise OR (|) sets the BITs. A different method is needed to change just one BCD digit while retaining the rest of the BCD digits.Set fourth digit (from right to left):result = result | digit4;Set third digit (from right to left):result = (result 8);notes: mask is all BITs = 1 except the BITs we want to clear (third digit - right to left), '!' is a bitwise NOTresult = source & mask; 8); <-- 7 is the value we want to set, SHIFTed into the 3rd digit positionIf I've made a mistake here it's because I did this very early in the morning. And yes, this can make your brain hurt.

Share this post


Link to post
Share on other sites

>That IS the "C version!">>execute_calculator_code is the name of a function(); in the>gauges.h file, and will request/receive any XML token variable>for use in a C gauge.>>You can see a full explanation of how this works on my "Panel>& Gauge Wiki" here:>>http://forums.flightsim.com/fswiki/index.p...les_in_C_GaugesBill, Awesome, thanks! Thanks also for that link to your article; I think that may actually help with something I've wanted to do in a gauge before but wasn't sure how to go about doing it.>Note that the COM and NAV frequencies assume the highest>order digit in the instrument (gauge) is 1 (one), it is not>recorded in the BCD representation.>>etc>>If I've made a mistake here it's because I did this very early>in the morning. And yes, this can make your brain hurt.Thanks for this as well. I've never really gotten the hang of some of this nibbles and bits stuff, even though I work with them at work. I'm a self-taught coder and this stuff does indeed make my brain hurt!

Share this post


Link to post
Share on other sites

No problem. Between Dai's wonderful 103 page C Gauge Handbook (there's really no other way to describe it!), my flightsim.com Wiki, and the "sticky posts" at my flightsim.com "Panel & Gauges" forum, there are more explanations of how to perform such operations.In fact, there are three unique methods described which all perform the same task:1) Arne Bartels BcdDec(); and DecBcd(); functions (pure C code)2) Jean-Luc's (RealityXP) "string method"3) The "execute_calculator_code(); function method to use XML tokens.Quite honestly, all new projects I'm developing now use method #3 to obtain ALL fs variables, which saves me a ton of time during development, since I no longer have to perform so much "conversion kung-fu" on the raw C tokens to massage them into a rational unit system... ;)For example:double adf1_frequency;execute_calculator_code("(A:ADF ACTIVE FREQUENCY:1, KHz)",&adf1_frequency,NULL,NULL);sprintf(pelement->string,"%6.2f",adf1_frequency );

Share this post


Link to post
Share on other sites

I really really like the execute_calculator_code method, but if you're doing a digital LCD or 'rolling tape' kind of gauge you'll still have to extract the digits. You might as well extract the digits directly if you have to extract them at all.Oddly, I've used a similar method to get the digits for a tape gauge using an sprintf to a string variable then extracting the strings's characters to get the individual digits. Sometimes an sprintf conversion saves some work.

Share this post


Link to post
Share on other sites

>Oddly, I've used a similar method to get the digits for a tape>gauge using an sprintf to a string variable then extracting>the strings's characters to get the individual digits.>Sometimes an sprintf conversion saves some work.Well, that's actually the beauty of using sprintf to a char[x] variable. You can 'extract' any digit by using the [index] number... ;)char cString[10] = ""; sprintf(cString, "%07.2f", adf1_frequency); // since the character "0" is ascii code 48, // then subtracting 48 from the character code of // the desired character gives us the numeric equivalent. adf1_freq_high_carry = cString[2] - 48;

Share this post


Link to post
Share on other sites

I've also made the switch to XML execute in most of the new gauges now, for convenience, and somewhat in prevision of FS11 changes (I suspect the data driven model will remain, while the token approach might change more).In order to help, I've also create a set of classes for this. Makes life easier and optimizes XML further in using pre-compiled code:class _xml_var_execute{public: _xml_var_execute() : _source_code(0), _precomp(false) {} ~_xml_var_execute() {if (_precomp && _source_code) {delete [] _source_code; _source_code = 0; _precomp = false;}} void Init(char* source_code, bool precomp =true) { if (!_source_code && source_code) { _source_code = source_code; if (precomp) { PCSTRINGZ pszCode; UINT32 uSize; if (gauge_calculator_code_precompile (&pszCode, &uSize, source_code)) { _source_code = new char[uSize]; memcpy(_source_code, pszCode, uSize); _precomp = true; } } } };protected: char* _source_code; bool _precomp;};class xml_var_dbl : public _xml_var_execute{public: xml_var_dbl(){};public: xml_var_dbl(char* source_code, bool precomp =true) {Init(source_code, precomp);}public: FLOAT64 Lookup() {FLOAT64 var; execute_calculator_code(_source_code,&var,0,0); return var;}};class xml_var_int : public _xml_var_execute{public: xml_var_int(){};public: xml_var_int(char* source_code, bool precomp =true) {Init(source_code, precomp);}public: SINT32 Lookup() {SINT32 var; execute_calculator_code(_source_code,0,&var,0); return var;}};You use these classes like this typically:create your variable:xml_var_dbl xvar_ADF_FREQ;init the variable, handy since you can do it at run time (when gauge load for example, to init on ADF1 or ADF2 like this) if (radio == AdfRadio2) { xvar_ADF_FREQ.Init ("(A:ADF ACTIVE FREQUENCY:2,KHz)"); xvar_ADF_SIGNAL.Init("(A:ADF SIGNAL:2,Number)"); xvar_ADF_RADIAL.Init("(A:ADF RADIAL:2,Degrees)"); } else { xvar_ADF_FREQ.Init ("(A:ADF ACTIVE FREQUENCY:1,KHz)"); xvar_ADF_SIGNAL.Init("(A:ADF SIGNAL:1,Number)"); xvar_ADF_RADIAL.Init("(A:ADF RADIAL:1,Degrees)"); }and then use it:radial = (float) xvar_ADF_RADIAL.Lookup();Hope this helps!(feel free to add this in your Wiki if you think it can help others)

Share this post


Link to post
Share on other sites

Thanks, Jean-Luc! As soon as I digest it myself and can understand how its used, I'll do just that.I'm assuming that another public class would be needed for retrieving string values, since you've only mentioned double and int in your example.

Share this post


Link to post
Share on other sites

Hi Jean-Luc,I'm trying to learn as much C++ as I can these days, so the code you posted seems an interesting example for my proposals.However, after digging a bit, I must say I don't quite understand the advantage of defining a class to handle xml vars' data considering that:-execute_calculator_code is a function that retrieves values from properties ("variables") already defined and instantiated within Panel/aircraft classes.- you can handle any kind of operations with regular C++ variables and functions through this own function in a very simple way.-going through another instantiation of another class should have some cost in performance ?I'm probably missing something :-)Tom

Share this post


Link to post
Share on other sites

The primary purpose of his class is encapsulation.The performance hit should be minimal, unless he writes bad code. ;)The irony is object oriented design isn't primarily for encapsulation, but for reusability and expandability. Something you can't do with hard-coded function calls. Not J-L's fault... FS's fault.

Share this post


Link to post
Share on other sites

Hi,First, it can be used (with precomp=false) as a dynamic "handler" to retrieving any XML var. If can come handy like in the example to have an "xml_adf_freq" var, and init it to either ADF1 or ADF2 in the loop. Then the code just uses xml_adf_freq.Lookup(), whatever it looks up for. Just one use of a class, can be one simpler in C.Now if you look closely, the Init can pre-compile your XML code and store it (default). Since this requires having FS first compile, then copy the compiled code someplace, it is easier and versatile to just new [] the buffer needed, which the class does. In that case, the destructor is handy for cleanup. You can fire and forget. (I new in my class, because I also have a very efficient memory allocator which supercedes C++ new/delete - you can store it anyplace you want). In that case, you init once, and reuse many.The is not a performance hit more than calling exec_calc_code directly and in fact it is faster with precompiled code (default behavior). In the end, it will be executed with the same SDK API. The only drawback is a couple bytes more allocated someplace (either on the heap if you new xml_var_dbl types for example), or in the .data section of the dll. Not much overhead and more convenient to me, but there could be other ways to do as well that can proove being better.As for string, I have not needed to implement them (no use yet on my projects) so they are missing for this reason, and you are right, this should be easy to add a class.In fact, I wanted to have a single class (and not use RTTI of any sort), but function overloading does not work with return type, just with argument types. So if anyone is C++ expert to have a single xml_var class that can return INT or DOUBLE based on on the arguments for example and with the generic lookup() function call, he is more than welcome (and without RTTI i.e. either class stored with a class type var -explicit- or compiler generated -behind the scene a if (type) then else). Otherwise, the cost of if then else can offset the benefit sometimes in inner loops.

Share this post


Link to post
Share on other sites

>So if anyone is C++ expert to>have a single xml_var class that can return INT or DOUBLE>based on on the argumentsThat's what C++ Templates are for, something like this:// function declarationtemplate T myfunc( T arg1 ){ return arg1 + 1; // do something }read more about this techinque here:http://www.codersource.net/cpp_template_function.htmlTemplates are probably the most powerful C++ feature...regards,

Share this post


Link to post
Share on other sites

Yes of course, I could use templates. I do with some other classes too. I wanted something that permits typing less code though LOL, instead ofxml_var myvar;But, if you look closely, in the end, the call to the SDK function uses 3 pointers to string, int or double vars. So it has to differenciate based on function call arguments to the C SDK function. A template would not help to that matter.Look at the function call the class wraps:execute_calculator_code(_source_code,&var,0,0); // doubleexecute_calculator_code(_source_code,0,&var,0); // intit has to come down to RTTI of some sort. Either a member var set to an enum/int to differenciate the function call at runtime, or, implicit compiler generated. In any case, it will end up with a if then else (or switch/case whatever), which I'd like to avoid. I'd prefer a compiler generated direct function call to the right one for the xml_var class type.Any idea?

Share this post


Link to post
Share on other sites

JeanLuc,"Now if you look closely, the Init can pre-compile your XML code and store it (default). Since this requires having FS first compile, then copy the compiled code someplace, it is easier and versatile to just new [] the buffer needed, which the class does"Which XML code are you talking about? There is none involved in execute_calculator function that I know of. In fact, the "XML" char argument passed/retrieved by the function is an ID that points to an ID string member of data structure within PANEL classes. Those classes interact and exchange info with all the set of token vars handled by panels.dll (those are the "real" vars, even settable through Simconnect), so maybe what you want to do is access directly to the tokens? "As for string, I have not needed to implement them (no use yet on my projects) so they are missing for this reason, and you are right, this should be easy to add a class."Well, it happens that the posibility to handle strings through custom defined varsets is one of the most powerful enhancements I've found in the new SDK.Tom

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this