Spenduku
Spenduku

Reputation: 417

Combining 17bit data into byte array

I'm having a bit of an issue with trying to move groups of 17bit data in to a byte array. I don't want to have to go through step-by-step, but I can't figure out a logical loop.
I need it this way because I'm meant to calculate a checksum by adding up the all the byte values after combining them like this.
So here is what I am struggling with.

I have 16 byte arrays. The first 3 bytes of the array contain the 17 bits I'm after. (8 bits from [0], 8 bits from [1], and the MSB from [2].)

I need to move these 16 17bit values to one separate byte array.

The first one is easy:

int index = 0;
myArray[index++] = driverData[driver][0];            //First byte
myArray[index++] = driverData[driver][1];            //Second byte
myArray[index] = (driverData[driver][2] & 0x80) << 7;  //First bit of the third byte.

From here though it gets harder to attempt any kind of loop to move these over.

driver++;<br>
//Take the 7 MSBs from the data array.
myArray[index++] |= (byte)(driverData[driver][0] & 0x7e >> 1);
//This leaves a single bit left over on driverData[driver][0].
myArray[index] = (byte)(driverData[driver][1] & 0x1 << 7);

I think you get the picture. Am I doing this all wrong? Can anyone point me in the right direction?

Upvotes: 3

Views: 364

Answers (3)

Spenduku
Spenduku

Reputation: 417

OK, so this looks to be working. I probably need to test it more, but this seems to be giving me the result I expect so far. I'm sure I could do this better somehow.

// ... //
void foo()
{
    //Lets start by getting all the 17bit values from each driver for the board.
    int bitIndex = 7;
    int byteIndex = 0;
    int stopIndex = chipIndex + GetChipCount();
    //Now we start the shiftyness.
    for (int driver = chipIndex; driver < stopIndex; driver++) {
        int userBits =
            (driverData[driver][0] & 0xff) << 9 | (driverData[driver][1]
                               & 0xff)
            << 1 | (driverData[driver][2] & 0x80) >> 7;
        AddBitsToArray(userBits, ref bitIndex, ref byteIndex);

    }
}

/// <summary>
/// Takes the 17 bits, and adds them to the byte array.
/// </summary>
private void AddBitsToArray(int userBits, ref int bitIndex, ref int byteIndex)
{
    int bitCount = 17;
    while (bitCount > 0) {
        //First 8 bytes.
        checksumBytes[byteIndex] |=
            (byte) (((userBits & bitValue(bitCount - 1)) >>
                 (bitCount - 1)) << bitIndex);
        //Move up the bit index to be written to.
        bitIndex--;
        //Decrement the number of bits left to shift.
        bitCount--;
        //If we have gone past the 8th bit, reset the bitIndex and increment the byteIndex.
        if (bitIndex >= 0)
            continue;
        bitIndex = 7;
        byteIndex++;
    }
}

/// <summary>
/// Returns the value of a single bit at the given index.
/// </summary>
private int bitValue(int bitIndex)
{
    return (int)(Math.Pow(2, bitIndex));
}

Upvotes: 2

JYelton
JYelton

Reputation: 36512

Here is what I came up with. The first part of the method is just setting up some fake input data, so remove that and add arguments as needed. The OutputData array is unnecessarily large but I didn't spend time to calculate its actual length.

I used 170 as the input value which is 10101010 and was helpful in validation.

private void BitShift17()
{
    const int NumChunks = 16;
    byte[] DriverData = new byte[]
        {
            170,
            170,
            170
        };
    byte[][] InputData = new byte[NumChunks][];
    for (int n = 0; n < NumChunks; n++)
        InputData[n] = DriverData;

    byte[] OutputData = new byte[NumChunks * 3]; // Unnecessarily large

    int OutputIndex = 0;
    int BitPosition = 0;
    for (int Driver = 0; Driver < InputData.Length; Driver++)
    {
        for (int InputIndex = 0; InputIndex < 3; InputIndex++)
        {
            byte InputByte = InputIndex == 2 ? (byte)(InputData[Driver][InputIndex] & 128) : InputData[Driver][InputIndex];
            if (BitPosition == 0)
            {
                OutputData[OutputIndex] = InputByte;
                if (InputIndex == 2)
                    BitPosition++;
                else
                    OutputIndex++;
            }
            else
            {
                if (InputIndex == 2)
                {
                    OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
                    BitPosition++;
                }
                else
                {
                    OutputData[OutputIndex] |= (byte)(InputByte >> BitPosition);
                    OutputIndex++;
                    OutputData[OutputIndex] = (byte)(InputByte << 8 - BitPosition);
                }
            }
        }
        if (BitPosition > 7) BitPosition = 0;
    }
}

Upvotes: 1

Variable Length Coder
Variable Length Coder

Reputation: 8116

Sounds like you have a prime number loop large enough to make coding the individual cases a bad idea. This is a classic packing problem. You need a loop that iterates through your destination, and some inner code that gets more bits to pack. Your packing code should know how many bits are available to it from the last iteration, how many it needs, and should be able to increment the source pointer if it doesn't have enough.

Upvotes: 2

Related Questions