0

The Problem

I have a integer array of 16 'options', the data for which stored in an array of 10 bytes. That means that each option takes up a certain number of bits and some options share bytes with others.

B, T, P, I, 2, 3, e, S, p, O, t, E, U, V, m and M are the options. The Xs are unused bits. The lower and upper case represent separate options. It is structured like this:

Byte 00: BBBB BTTT     
Byte 01: TPPP PPII       
Byte 02: III2 2222       
Byte 03: 2333 333e       
Byte 04: eeee eSSS       
Byte 05: SSSS Sxpp       
Byte 06: ppOO OOOx       
Byte 07: tttE EEEE       
Byte 08: EEUU VVVm       
Byte 09: mmmM Mxxx

My aim is to read those 10 bytes and get the values for those 16 options from the data stored across the bytes. The values of the bytes, in hexadecimal, are as follows:

D6
27
AD
B6
9B
10
0A
58
0C
00

My attempts at solving it

I've tried two methods so far to retrieve the desired values. The first was bit shifting, for example:

option[0] = optionByte[00] >> 3;
option[2] = (optionByte[01] << 1) >> 2;
option[11] = optionByte[07] >> 5;

This worked for the options which are only stored within a single byte and gave me the desired values, which were:

Option 0: 26
Option 2: 9
Option 11: 2

I didn't think this would be possible for options which are split across more than one byte, so instead, I tried creating a bit array from the byte array, translating it into a string of binary numbers representing the bits, then reading the string by the number of bits the option takes up, to create the binary number and convert it to decimal. Here is the function I wrote to perform this action:

    public byte[] headerBytes = new byte[10];
    public int[] headerSettings = new int[16];

    public void readHeader()
    {
        int bits = 0;
        int sIndex = 0; // Starting point to read from
        string hBinary = string.Empty;
        BitArray headerBits = new BitArray(headerBytes);
        
        // Translate bit array to string of Binary digits
        foreach (var bit in headerBits)
        {
            hBinary += Convert.ToInt16(bit).ToString();
        }

        // Convert option values to decimal from Binary values
        for (int i = 0; i < 16; i++)
        {
            string hBinarySplit = string.Empty;
            switch (i) // Set the number of bits to read depending on the option/loop iteration
            {
                case 0: bits = 5; break;
                case 1: bits = 4; break;
                case 2: bits = 5; break;
                case 3: bits = 5; break;
                case 4: bits = 6; break;
                case 5: bits = 6; break;
                case 6: bits = 6; break;
                case 7: bits = 8; break;
                case 8: bits = 5; break;
                case 9: bits = 5; break;
                case 10: bits = 3; break;
                case 11: bits = 7; break;
                case 12: bits = 2; break;
                case 13: bits = 3; break;
                case 14: bits = 4; break;
                case 15: bits = 2; break;
            };

            if (i == 8 || i == 10)
                sIndex += 1; // Ignore unused bits in bytes 5 and 6

            // Create binary sub-value for option
            hBinarySplit += hBinary.Substring(sIndex, bits);
            
            // Advance point in main string to read from
            sIndex += bits;

            // Set option value to decimal from Binary sub-value
            headerSettings[i] = Convert.ToInt16(hBinarySplit, 2);
        }
    }

This function ran error-free, but returned incorrect option values. The values I was expecting in decimal, are:

B: 26
T: 12
P: 09
I: 29
2: 27
3: 27
e: 19
S: 98
p: 00
O: 05
t: 02
E: 96
U: 00
V: 03
m: 00
M: 00

The function returned the following values to the integer array:

B (int 00) : 13
T (int 01) : 07
P (int 02) : 25
I (int 03) : 05
2 (int 04) : 42
3 (int 05) : 54
e (int 06) : 59
S (int 07) : 33
p (int 08) : 02
O (int 09) : 16
t (int 10) : 01
E (int 11) : 81
U (int 12) : 02
V (int 13) : 00
m (int 14) : 00
M (int 15) : 00

Summary

I have a feeling there may be something missing from the function which was the reason for the wrong values being returned.

Please could anyone advise a fix for the function, or if the initial bit-shifting method I tried is more efficient, how to do it when the bits are spread across multiple bytes?

Jeorge535
  • 33
  • 6

2 Answers2

1

Turns out I overlooked one small fact. The BitArray class stores the bits from least to most significant. That's why the function was returning the wrong values to the integer array. Reversing each group of 8 bits in the hBinary string solved it and the function now returns the expected values.

Jeorge535
  • 33
  • 6
-1

Not an answer, but would be clearer then in a comment:
Can you combine the bytes into an array?
If so, then:

bytes=byte1+byte2+...+byte9;
mask="BBBBBTTTTPPPPPIIIII222222333333eeeeeeSSSSSSSSxppppOOOOOxtttEEEEEEEUUVVVmmmmMMxxx";
options={};
for(i=0; i<mask.length; i++) {
  if(options[mask[i]]==undefined) options[mask[i]]="";
  options[mask[i]]+=bytes[i];
};

Then you can retrieve option bit values (as a string) by using:

options["B"];
options["3"];

Then raise 2 to the power of the position of the bits and add to sum if bit is 1.

iAmOren
  • 2,760
  • 2
  • 11
  • 23