Hello everyone. I'm hoping you can help me with something I've been fighting with for a week. It's a fairly big project, so I'll try to summarize as best I can and peel out the relevant code for review.
**The issue: **I'm getting all sorts of data corruption in my Android->Arduino data transfers, though the same algorithm works fine for Arduino->Android data transfer.
Hardware: I have a vehicle-mounted Arduino Uno that controls my air bag suspension, interfacing with a bespoke Android app via a HC05 Bluetooth module on the Arduino.
**Intended operation: **Upon a successful connection, the Android app sends to the Arduino a series of 8 unique ID+value data sets in rapid succession, broken up by start/end tokens, and validated by checksums. Each data set is sent twice to allow for one error.
**Actual behavior: **The first two data sets (four id+Value pairs) are successfully read, then the data corruption sets in and no further data passes my error checks as a complete set. Some bytes in the subsequent data are successful, but never a full set of start token, id, value, checksum, and end token. Some corrupted numbers are being read as 8-bit values, but this shouldn't be possible given the way I'm formatting my data.
**Attempted fixes: **I thought this might be a problem with the serial buffer length, so I doubled the buffer size and slowed the Android transfer frequency to once per 100ms. This had no effect.
Additional information: This communication scheme is a revision of a previous (successful) string-parsing communication scheme. The previous scheme was limited to positive numbers only with values less than 128 due to Android/Java's lack of unsigned bytes and Arduino's insistence on them. This new scheme is an attempt to fix that.
I'm currently breaking up signed integers into two 7-bit values to communicate over serial (Java doesn't seem to allow bit masking on the sign bit, so 7 bits is all I get). I use the first of those 7 bits as an indication of byte-pair ordering (1 for first byte, 0 for second byte), and I use the second bit of the first byte as a sign bit. This leaves 11 bits for data.
Relevant Arduino code (full code below):
void receiveData() {
static bool firstbyte_done = false, id_done = false, value_done = false, checksum_done = false;
static int id, value, checksum;
static byte firstbyte;
byte readbyte;
int readint;
while (bt_serial.available() > 0 and dataSetReady == false) {
readbyte = bt_serial.read();
Serial.print("readbyte ");
Serial.println(readbyte, BIN);
//first byte checks out
if ((not firstbyte_done) and (readbyte & 0b01000000)) {
firstbyte = readbyte & 0b00111111;
Serial.print("firstbyte ");
Serial.println(firstbyte, BIN);
firstbyte_done = true;
return;
//second byte checks out
} else if ((firstbyte_done) and not (readbyte & 0b01000000)) {
readint = ((int)firstbyte << 6) + (int)(readbyte & 0b00111111);
Serial.print("READINT ");
Serial.print(readint, BIN);
Serial.print(" ");
Serial.println(readint & 0b0000011111111111); //abs val
//convert to signed int, using 3rd MSB of first byte as sign bit
if (readint & 0b0000100000000000) { readint = (readint & 0b0000011111111111) * -1; }
firstbyte_done = false;
//bad byte received
} else {
Serial.println("BAD BYTE PAIR RECEIVED");
firstbyte_done = false;
return;
}
switch (readint) {
case START_MARKER:
id_done = false;
value_done = false;
checksum_done = false;
//Serial.println("START_MARKER");
break;
case END_MARKER:
if (id_done and value_done and checksum_done
and id <= 100 and (id + value == checksum)) {
receivedData[0] = id;
receivedData[1] = value;
dataSetReady = true;
//Serial.println("END_MARKER");
} else {
if (id + value != checksum) { Serial.println("CHECKSUM ERROR"); }
id_done = false;
value_done = false;
checksum_done = false;
}
break;
default:
if (value_done) { //expecting checksum
checksum = readint; //check for overflow? not really required if id<=100
checksum_done = true;
} else if (id_done) { //expecting value
value = (int)readint;
value_done = true;
} else { //expecting id
id = (int)readint; //can't be negative since MSB already stripped
id_done = true;
}
break;
}
}
}