Arduino/C++ byte manipulation

Consider this scenario, I have a single byte of data; I have to use the 8 bits it is composed of to generate 4 extra bits from it.

Now, my problem is that I have to store this data somewhere while I operate on it and then return the final answer in byte form.

eg. 1 byte of 8 bits becomes 12 bits. Thus 2 bytes results in 24 bits which I want to transfer in packets of 3 bytes.

01001101 becomes this with added bits: _ _ 0 _ 1 0 0 _ 1 1 0 1

What would be the most efficient way to accomplish this?

• Could you explain a bit more? Is it always the same bits that are moved to the same new location? What values do the underscores (_) get? Mar 16, 2015 at 20:04
• Yes, the same bits are moved to the same new locations and the underscores are filled with bits which are calculated from the rest of the bits present in the received byte. (After performing a few simple operations on them) Mar 16, 2015 at 20:17

Sometimes the brute-force way is also the most efficient. Just copy the bits one at a time from the corresponding source variable to the destination variable:

``````int merge_bits (int old_bits, int new_bits)
{
int retval = 0;
if (old_bits & 0x01) retval |= 0x001;
if (old_bits & 0x02) retval |= 0x002;
if (old_bits & 0x04) retval |= 0x004;
if (old_bits & 0x08) retval |= 0x008;
if (new_bits & 0x01) retval |= 0x010;
if (old_bits & 0x10) retval |= 0x020;
if (old_bits & 0x20) retval |= 0x040;
if (old_bits & 0x40) retval |= 0x080;
if (new_bits & 0x02) retval |= 0x100;
if (old_bits & 0x80) retval |= 0x200;
if (new_bits & 0x04) retval |= 0x400;
if (new_bits & 0x08) retval |= 0x800;
return retval;
}
``````

On most microprocessors, this will compile into just a few instructions per statement.

This is also arguably more maintainable than a complex series of shift and mask operations.

Assuming the incoming bytes are guaranteed to come in even numbers, and your output is in little-endian order, you could do something like this:

``````void process_and_send_bytes(uint8_t data_in)
{
uint16_t some_12_bit_function(uint8_t);  // processing function
void send_byte(uint8_t);                 // sending function
static uint8_t data_on_old = 0;
static bool has_data_on_old = false;
uint16_t processed_data = some_12_bit_function(data_in);
if (has_data_on_old) {
send_byte(processed_data << 4 | data_on_old);  // two pieces
send_byte(processed_data >> 4);      // high 8 bits
has_data_on_old = false;
}
else {
send_byte(processed_data);           // send low 8 bits
data_on_old = processed_data >> 8;   // save higher 4 bits
has_data_on_old = true;
}
}
``````

Basically, when you get the first byte, this function outputs one byte and keeps 4 bits on hold. When you get the next byte, this outputs the 4 bits that where on hold, together with the new 12 bits, as two 8-bit packets.

• It looks like we each picked a different part of the question to answer! :-) Mar 16, 2015 at 20:50

I haven't tested this in any way whatsoever, but you could use a 32-bit integer as a buffer to store the bytes as you process them. Then, any multiples of 8 bytes that end up in the buffer can be passed on to wherever they are needed.

The first byte that comes in you process and push all 12 bits into the 32-bit integer - increment a counter by 12. You now have 12 bits in the buffer variable.

Then while the number of bits in the buffer is at least 8 bits you grab the upper-most 8 bits and pass them on to wherever they are going. Decrement the counter by 8 for each iteration. You have now sent 1 byte and you have 4 bits left in the buffer.

The next byte that comes in you push the new 12 bits into the buffer. The counter, increased by 12, is now 16.

16 is greater than or equal to 8, so send out the upper 8 bits of the 16 and decrement the counter by 8.

8 is greater than or equal to 8, so send out the upper 8 bits of the 8 and decrement the counter by 8.

Counter is now 0, so nothing else to send. Back to the beginning again.

Something like:

``````void processByte(uint8_t in) {
static uint32_t buffer = 0;
static uint8_t validBits = 0;
buffer <<= 12; // Make room for 12 new bits.
buffer |= (first processed bit << 11);
buffer |= (second processed bit << 10);
buffer |= ((in & 0x80) << 2);
buffer |= (third processed bit << 7);
buffer |= ((in & 0x70) << 1);
buffer |= (fourth processed bit << 4);
buffer |= (in & 0x0F);
validBits += 12;

while (validBits >= 8)
validBits -= 8;
executeByte((buffer >> validBits) & 0xFF);
}
}
``````