Communication Protocol

Tom and I met at my house and cleaned up the commutation protocol implementation for the ArduIMU glove firmware and Glover.

Data is send in packets where the first byte defines the packet type, the last byte is an XOR checksum and all bytes in between are the payload.  Each packet type has a predetermined fixed length.

For example, an LED command packet consists of the following 5 bytes:

  1. ‘L’ (packet header)
  2. Red value (8-bit unsigned integer)
  3. Green value (8-bit unsigned integer)
  4. Blue value (8-bit unsigned integer)
  5. XOR checksum

Example code to send this packet:

void sendLEDData(const unsigned char r, const unsigned char g, const unsigned char b) {
    char packet[5];
    int packetLength = 0;
    packet[packetLength++] = 'L';
    packet[packetLength++] = r;
    packet[packetLength++] = g;
    packet[packetLength++] = b;
    packet[packetLength++] = calcChecksum(packet, packetLength);
    Serial.write((uint8_t*)packet, packetLength);
}

char calcChecksum(const char* const packet, const int packetLength) {
    int i = 0;
    char checksum = 0;
    while(i < packetLength) {
        checksum ^= packet[i++];
    }
    return checksum;
}

Example code to receive this packet:

#define LED_PACKET_LENGTH 5
#define MAX_PACKET_LENGTH 5

char rxBuf[256];
unsigned char rxBufIndex;

void doTasks() {
    while(Serial.available() > 0) {
        static bool inSync = false;
        static int byteCount = 0;

        // Add new byte to buffer
        rxBuf[rxBufIndex++] = Serial.read();

        // Check if out of sync
        if (++byteCount > MAX_PACKET_LENGTH) {
        byteCount = MAX_PACKET_LENGTH;  // prevent overflow
            inSync = false;
        }

        // Decode LED packet
        if (rxBufIndex >= LED_PACKET_LENGTH) {
            if ((inSync ? rxBuf[0] : rxBuf[rxBufIndex - LED_PACKET_LENGTH]) == 'L') {
                if (calcChecksum(LED_PACKET_LENGTH) == 0) {
                    unsigned char red   = (unsigned char)rxBuf[rxBufIndex - (LED_PACKET_LENGTH - 1)];
                    unsigned char green = (unsigned char)rxBuf[rxBufIndex - (LED_PACKET_LENGTH - 2)];
                    unsigned char blue  = (unsigned char)rxBuf[rxBufIndex - (LED_PACKET_LENGTH - 3)];
                    I2CBus::setRGB(red, green, blue);
                    rxBufIndex = 0;
                    byteCount = 0;
                    inSync = true;
                }
            }
        }
    }
}

char calcChecksum(const int packetLength) {
    unsigned char tempRxBufIndex = rxBufIndex - packetLength;
    unsigned char checksum = 0;
    while(tempRxBufIndex != rxBufIndex) {
        checksum ^= rxBuf[tempRxBufIndex++];
    }
    return checksum;
}

Leave a Reply