I'm going to be opensourcing some code I'm working on. I don't need help with the code, I just want to make sure my code is readable and my comments make sense. I have a knack for the esoteric. This code is to control GE G35 Christmas lights using a Netduino controller. Due to the .NET overhead, I've written a custom lower-level driver compiled into the firmware.
Can you follow my code? This is on an embedded processor which is why I'm doing a lot of bit-shifting. It's easier to write this way.
public Int32[,] getData()
{
int maxBulbs = getMaxBulbs();
// Using an abdnormal form of bitpacking here to make the C loop, very tight and efficient.
// The first address of the array is the bulb position on all strings.
// The second address of the array is actually the corresponding bulb information for that bit.
// Within the array, we store a 32-bit int. Each bit in this int, represents a G35 Strand/string
// So at data[0, 0] we have a 32 bit int, this int represents the first bulb on all strings, first data information bit for up to 32 strands.
Int32[,] data = new Int32[getMaxBulbs(), 26]; // number bulbs on a strand, 26 bit bulb info
foreach (G35String gstring in Strings)
{
for (short c_bulb = 1; c_bulb < maxBulbs; c_bulb++)
{
// This is a bit of a shortcut. because we know that G35's just pass the information down
// the pipe and due to the way we are sending data in parallel, if one string has
// more bulbs than another, we just send fake data to the non existent bulb on that string
G35Bulb gbulb = (c_bulb < gstring.bulbs.Length ? gstring.bulbs[c_bulb] : new G35Bulb(0, 0));
// bulb address
data[c_bulb, 0] = (c_bulb & 0x20) << gstring.StringPinAddress;
data[c_bulb, 1] = (c_bulb & 0x10) << gstring.StringPinAddress;
data[c_bulb, 2] = (c_bulb & 0x08) << gstring.StringPinAddress;
data[c_bulb, 3] = (c_bulb & 0x04) << gstring.StringPinAddress;
data[c_bulb, 4] = (c_bulb & 0x02) << gstring.StringPinAddress;
data[c_bulb, 5] = (c_bulb & 0x01) << gstring.StringPinAddress;
// bulb brightness
data[c_bulb, 6] = (gbulb.BulbBrightness & 0x80) << gstring.StringPinAddress;
data[c_bulb, 7] = (gbulb.BulbBrightness & 0x40) << gstring.StringPinAddress;
data[c_bulb, 8] = (gbulb.BulbBrightness & 0x20) << gstring.StringPinAddress;
data[c_bulb, 9] = (gbulb.BulbBrightness & 0x10) << gstring.StringPinAddress;
data[c_bulb, 10] = (gbulb.BulbBrightness & 0x08) << gstring.StringPinAddress;
data[c_bulb, 11] = (gbulb.BulbBrightness & 0x04) << gstring.StringPinAddress;
data[c_bulb, 12] = (gbulb.BulbBrightness & 0x02) << gstring.StringPinAddress;
data[c_bulb, 13] = (gbulb.BulbBrightness & 0x01) << gstring.StringPinAddress;
// Blue
data[c_bulb, 14] = (gbulb.BulbColor >> 8 & 0x8) << gstring.StringPinAddress;
data[c_bulb, 15] = (gbulb.BulbColor >> 8 & 0x4) << gstring.StringPinAddress;
data[c_bulb, 16] = (gbulb.BulbColor >> 8 & 0x2) << gstring.StringPinAddress;
data[c_bulb, 17] = (gbulb.BulbColor >> 8 & 0x1) << gstring.StringPinAddress;
// Green
data[c_bulb, 18] = (gbulb.BulbColor >> 4 & 0x8) << gstring.StringPinAddress;
data[c_bulb, 19] = (gbulb.BulbColor >> 4 & 0x4) << gstring.StringPinAddress;
data[c_bulb, 20] = (gbulb.BulbColor >> 4 & 0x2) << gstring.StringPinAddress;
data[c_bulb, 21] = (gbulb.BulbColor >> 4 & 0x1) << gstring.StringPinAddress;
// Red
data[c_bulb, 22] = (gbulb.BulbColor & 0x8) << gstring.StringPinAddress;
data[c_bulb, 23] = (gbulb.BulbColor & 0x4) << gstring.StringPinAddress;
data[c_bulb, 24] = (gbulb.BulbColor & 0x2) << gstring.StringPinAddress;
data[c_bulb, 25] = (gbulb.BulbColor & 0x1) << gstring.StringPinAddress;
}
}
return data;
}
In the C++ driver, I can blast all the registers I need like this in parallel:
// LED Address
sendBits(data[i][0]);
sendBits(data[i][1]);
sendBits(data[i][2]);
sendBits(data[i][3]);
sendBits(data[i][4]);
sendBits(data[i][5]);
void sendBits(uint16_t gpioPins, uint32_t data)
{
*_BSRRL = gpioPins;
delayMicroseconds(DELAYSHORT); // 10us
*_BSRRH = gpioPins;
delayMicroseconds(DELAYSHORT); // 10us
*_BSRRL = ~data;
delayMicroseconds(DELAYSHORT); // 10us
*_BSRRL = gpioPins;
}