C# Byte[] to BCD and BCD to INT

xFireTR picture xFireTR · Jul 28, 2012 · Viewed 26.7k times · Source

I have a Hex file created by CashRegister Machine. I have to read this file in.

File uses formatting detailed below. It is like socket packets.

Code Data : 2 Byte
PLU Code Data: 7 Byte
Unit Price Data: 5 Byte
Quantity Data: 5 Byte
Total Amount Data: 5 Byte
PLU Name Data: 18 Byte
Tax Rate Data: 1 Byte
Length: 24 + 19 Byte

  • PLU code format is BCD
  • Unit price 1-9999999999 (BCD)
  • quantity 1-9999999999 (BCD last 3 numbers should be decimal)
  • total amount 1-9999999999 (BCD)

I read in the hex file with a binary reader and then insert int the Unit Price byte array.

byte[] bytes = { data[21], data[22], data[23], data[24], data[25] }; // BCD Byte Array

This array is Unit Price. But how can I then convert this number to decimal. And the information says that for quantity : BCD last number should be decimal--what does this mean? Thanks.

Answer

A BCD number encodes a value from 0-9 into 4 bits. In packed BCD (probably what you're dealing with), a byte is used to contain two values 0-9, one in each nibble (4 bits) of the byte. To convert to an int, you have to do a little bit fiddling. For example, the following would convert an array of BCD bytes into an int, which can hold up to 9 digits. Use long if you have more than 9 bcd digit of input.

// assume byte[] bcds is input
int result = 0;
foreach(byte bcd in bcds) {
    result *= 100;
    result += (10 * (bcd >> 4));
    result += bcd & 0xf;
}

This assumes that each byte is stored as big-endian BCD, where the most significant digit is in the most significant nibble of the byte. This is what is described in the Wikipedia page for BCD as the more common implementation. If you are dealing with little-endian BCD, the conversion code within the for loop would be

    result *= 100;
    result += (10 * (bcd & 0xf));
    result += bcd >> 4;

You also need to ensure you have the correct endianness of your array, i.e., does the first byte in the array contain the most significant two digits, or the least significant two digits. For example, the number 123456 would fit into 3 bytes using packed BCD. Is 12 in byte[0] or byte[2]? You would need to adjust the loop above to reverse the order if your endianness is different than my assumption. I'm assuming 12 is in byte[0] (big endian, with the most significant digits in the leftmost byte).

As for the quantity described as BCD and decimal, I would need to see actual values to understand what they're talking about.