C# Byte[] to BCD and BCD to INT

28,168

Solution 1

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.

Solution 2

Each byte is two decimal digits, one in each nibble. If you show the bytes as hex, you can read the number easily.

0x08 0x27 0x42 0x17 0x75 = 827,421,775

You can get the high and low nibbles like this:

int high = currentByte >> 4;
int low = currentByte & 0xF;

Convert each byte into number like this:

int number = 10 * high + low;

But remember that each byte is 100 times bigger then the next byte.

With quantity having 3 decimal places, just divide the final number by 1,000 to get the actual value.

Solution 3

CORRECT code:

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

You can also create a custom extension to a byte[] by creating a public static class:

public static class BitConverterExtension
{
    public static UInt64 FromBCDToExtUInt64(this byte[] b, byte[] bcds, uint nBytes, uint startOf)
    {
        UInt64 result = 0;
        uint i = 0;

        for (i = 0; i < nBytes; i++)
        {
            result *= 100;
            result += (UInt64)(10 * (bcds[startOf + i] >> 4));
            result += (UInt64)(bcds[startOf + i] & 0xf);
        }

        return (result);

    }
}

Solution 4

i wrote this code and works for me:

 public uint BCD5ToInt(byte [] bcd)
{
uint outInt=0;

   for (int i = 0; i < bcd.Length; i++)
   {
       int mul = (int)Math.Pow(10,(i*2));
       outInt += (uint) (((bcd[i] & 0xF)) * mul);
       mul = (int)Math.Pow(10, (i * 2) + 1);
       outInt +=(uint)( ((bcd[i] >> 4) ) * mul);
   }

   return outInt;
}

This is reverse code:

  // Convert an unsigned integer into 5 bytes of 
    public byte[] IntToBCD5(uint numericvalue, int bytesize = 5)
    {
        byte[] bcd = new byte[bytesize];
        for (int byteNo = 0; byteNo < bytesize; ++byteNo)
            bcd[byteNo] = 0;
        for (int digit = 0; digit < bytesize * 2; ++digit)
        {
            uint hexpart = numericvalue % 10;
            bcd[digit / 2] |= (byte)(hexpart << ((digit % 2) * 4));
            numericvalue /= 10;
        }
        return bcd;
    }

And this is test code:

 public void test()
    {
        uint firstInt = 987654321;
        var array = IntToBCD5(firstInt);
        var outInt = BCD5ToInt(array);
        MessageBox.Show(outInt.ToString());
    }
Share:
28,168
Admin
Author by

Admin

Updated on January 10, 2020

Comments

  • Admin
    Admin over 4 years

    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.