I'm in the process of writing a library to reliably transmit/receive packetized serial data. In this library there is a class method called "available()" that parses incoming data and lets the main code know if a packet has successfully arrived or if any packet corruption has occurred.
Within this "available()" method, I have a finite state machine with its states initialized as:
When I send a packet between two Arduinos using this library, the receiving Arduino successfully parses the entire packet through the "find_checksum state". Once it's done with the "find_checksum" I set the next state to be "find_end_byte", but the next iteration of the method doesn't execute the code associated with "find_end_byte" even though I know the state machine is in that state.
Here is the source code for "available()":
/*
int8_t SerialTransfer::available()
Description:
------------
* Parses incoming serial data, analyzes packet contents,
and reports errors/successful packet reception
Inputs:
-------
* void
Return:
-------
* int8_t - Error code
*/
int8_t SerialTransfer::available()
{
if (port->available())
{
while (port->available())
{
uint8_t recChar = port->read();
Serial.println(state);
switch (state)
{
case find_start_byte://///////////////////////////////////////
if (recChar == START_BYTE)
state = find_payload_len;
break;
case find_payload_len:////////////////////////////////////////
if (recChar <= MAX_PACKET_SIZE)
{
bytesToRec = recChar;
state = find_payload;
}
else
{
state = find_start_byte;
return PAYLOAD_ERROR;
}
break;
case find_payload:////////////////////////////////////////////
if (payIndex < bytesToRec)
{
rxBuff[payIndex] = recChar;
payIndex++;
if (payIndex == bytesToRec)
{
payIndex = 0;
state = find_checksum;
}
}
break;
case find_checksum:///////////////////////////////////////////
uint8_t calcChecksum = findChecksum(rxBuff, bytesToRec);
if (calcChecksum == recChar)
{
Serial.println("next, finding end byte");
state = find_end_byte;
}
else
{
state = find_start_byte;
return CHECKSUM_ERROR;
}
break;
case find_end_byte:///////////////////////////////////////////
Serial.println("finding end byte");
state = find_start_byte;
if (recChar == STOP_BYTE)
return NEW_DATA;
return STOP_BYTE_ERROR;
break;
default:
break;
}
}
}
else
return NO_DATA;
return CONTINUE;
}
Here is the output of the receiving Arduino when it is sent packets of data:
case find_end_byte:///////////////////////////////////////////
Serial.println("finding end byte");
state = find_start_byte;
On entering the find_end_byte case you almost immediately set the state to find_start_byte. Is that intentional or should it only happen when the STOP_BYTE has been received ?
UKHeliBob:
On entering the find_end_byte case you almost immediately set the state to find_start_byte. Is that intentional or should it only happen when the STOP_BYTE has been received ?
Yes, because checking the end byte is the end of the process - whether or not it errors out, the next state must be to find the start byte of the next packet.
I think that the code that you show does not match with the results that you show, or I might be overlooking something :
If you are really sure that is what you have, then it could be memory overflow, or writing to memory locations beyond an array, or another variable called 'state', or a compiler bug, and so on.
@johnwasser, Thanks !
So I did indeed overlook something :-[
Normally I would get a real error and the compiler stops when I declare a variable in a case without brackets. So I did a test:
void setup()
{
Serial.begin(9600);
}
void loop()
{
int i = random( 0, 2);
switch( i)
{
case 0:
Serial.println( "0");
break;
case 1:
int j = random( 0, 1000);
Serial.print( "1,");
Serial.println( j);
break;
default:
Serial.println( "default");
break;
}
delay( 500);
}
It only gives a warning
("warning: jump to case label [-fpermissive]" and "note: crosses initialization of 'int j").
Is the solution to turn on all compiler warnings in the preferences with verbose output for the compiler and check the warnings ?
Koepel: @johnwasser, Thanks !
Is the solution to turn on all compiler warnings in the preferences with verbose output for the compiler and check the warnings ?
I recommend turning the "Compiler warnings:" preference to "All" and keeping it there. The warnings will often point out code that is syntactically valid but semantically questionable.
No need for verbose output.