I was looking at some of the code in the Arduino runtime library today, and I saw something that looked a bit fishy to me. In the following code, it occurred to me that there could be a bug when rx_buffer_head wraps around from 127 back to 0:
int serialAvailable()
{
return (rx_buffer_head - rx_buffer_tail) % RX_BUFFER_SIZE;
}
In that case, it occurred to me that you could have rx_buffer_head==0, and rx_buffer_tail==127. Then serialAvailable() would return (0 - 127) % 128 == -127. Or at least, that's the mod operator works on most computers I am used to.
So I decided to test this out with a program before making a fool of myself!

I wrote the following code and ran it.
extern volatile int rx_buffer_head, rx_buffer_tail;
void setup()
{
Serial.begin (9600);
}
void loop()
{
cli(); // disable interrupts, to make absolutely sure we get consistent numbers
int avail = Serial.available();
int head = rx_buffer_head;
int tail = rx_buffer_tail;
sei(); // enable interrupts again
if (avail) {
Serial.print (" h=");
Serial.print (head);
Serial.print (" t=");
Serial.print (tail);
Serial.print (" a=");
Serial.print (avail);
Serial.println();
Serial.read(); // read and discard one byte
}
}
While running this code, I kept sending the Arduino board one character at a time over the serial port. Here is the output, with a lot of unnecessary lines removed:
h=1 t=0 a=1
h=2 t=1 a=1
h=3 t=2 a=1
h=4 t=3 a=1
h=5 t=4 a=1
h=6 t=5 a=1
h=7 t=6 a=1
h=8 t=7 a=1
h=9 t=8 a=1
h=10 t=9 a=1
h=11 t=10 a=1
h=12 t=11 a=1
// ... over 100 lines deleted for brevity's sake ...
h=122 t=121 a=1
h=123 t=122 a=1
h=124 t=123 a=1
h=125 t=124 a=1
h=126 t=125 a=1
h=127 t=126 a=1
h=0 t=127 a=129 // <=== *** RED ALERT *** should have said a=1
h=1 t=0 a=1
h=2 t=1 a=1
h=3 t=2 a=1
h=4 t=3 a=1
h=5 t=4 a=1
h=6 t=5 a=1
h=7 t=6 a=1
h=8 t=7 a=1
As predicted, you get the wrong value returned by serialAvailable() whenever rx_buffer_head < rx_buffer_tail. The reason it wasn't negative is because I am calling Serial.available(), which calls serialAvailable(), then typecasts the negative value to an unsigned byte.
To fix this problem, the function serialAvailable needs to be modified as follows:
int serialAvailable()
{
return (RX_BUFFER_SIZE + rx_buffer_head - rx_buffer_tail) % RX_BUFFER_SIZE;
}
After applying this fix and running again, now I see correct behavior:
// ... blah blah blah
h=124 t=123 a=1
h=125 t=124 a=1
h=126 t=125 a=1
h=127 t=126 a=1
h=0 t=127 a=1 // <=== Yes! It works!
h=1 t=0 a=1
h=2 t=1 a=1
h=3 t=2 a=1
I just thought I would mention this so that
- It could be fixed for Arduino 0008.
- People could edit their own copy of Arduino 0007 and fix it themselves, or
- They could be very careful calling Serial.available(), knowing it can return incorrect values.