Hello!
I have a weird issue, and after chatGPT had no idea, I think it may be a bug but before I submit an issue, let's see if someone can help me out.
I have some code that does serial communication. My issue is that if I enter the data in a specific way it completely stops receiving data over serial.
This code expects either a INITMARKER ('g') which would make it start running normally, or a ONEMSGMARKER ('o') which just gives one message to the Arduino without ack or anything like that.
I had an issue of the sending system sometimes sending half the characters, getting interrupted, then sending the other half. So I made my code wait until there are enough characters in the serial buffer before executing. Unfortunately, for whatever reason if I send in a particular way, it never fills the buffer with them.
This works well:
o(oo) send
o send (oo) send
This does not work:
o( send oo) send
o(o send o) send
o(oo send ) send
o send ( send o send o send ) send
In all cases that do not work, whatever characters are sent the first time around are seen in the serial buffer (Serial.available() shows them), but then sending more characters does not increment Serial.available() and the code never executes.
Here is the relevant part of the communication function:
if (Serial.peek() == ONEMSGMARKER){
if (Serial.available() >= 5){
Serial.read(); //discard the peeked character
Serial.println("About to go into the loop");
while (Serial.available()){
recvChar = Serial.read();
if (bitRead(recvChar,POS_SERIAL_RES)){ //if the resrved bit is set, this is not part of the data
Serial.println(F("!Did not expect an ACK/NCK char. Clearing buffer!"));
while (Serial.available()){
Serial.read();
}
return;
}
else if (recvChar == STARTMARKER){
index = 1;
}
else if (index) {
if (recvChar != ENDMARKER) {
if (index > SERIAL_INDEX_MAX){
Serial.println(F("!Message too long!"));
}
message += recvChar << ((index-1)*8);
index++;
}
else { // end marker
index = 0;
serialFromPi = message;
break; //the recvChar loop
}
}
}
}
else{
Serial.print(F("In buffer:"));
Serial.println(Serial.available());
}
}
Here is the entire function. void loop() just calls this and other non serial related functions over and over.
uint8_t talkToPi() {
//state machine variables
static uint8_t state = SERIAL_STARTING;
//timing variables
uint32_t ms = millisec();
static uint32_t prevReplyMS = 0, prevSendMS = 0;
//recieve variables
static uint8_t index = 0;
char recvChar;
static uint16_t message;
//recieve variables are defined for the entire function above
//send variables
static uint16_t prevMessageToPi = 0x4747; //GG
static uint8_t prevMessageAckByPi, uniqueMessagesMissed;
switch (state){
case SERIAL_STARTING:
if(Serial){
state = SERIAL_INITIALIZING;
break;
}
Serial.begin(0); //No baudrate for USB serial
break;
case SERIAL_INITIALIZING:
message = 0; // this is here in case ONEMSGMARKER is sent and the data has the reserved bit set. The function will return and discard the data
if (Serial.peek() == ONEMSGMARKER){
if (Serial.available() >= 5){
Serial.read(); //discard the peeked character
Serial.println("About to go into the loop");
while (Serial.available()){
recvChar = Serial.read();
if (bitRead(recvChar,POS_SERIAL_RES)){ //if the resrved bit is set, this is not part of the data
Serial.println(F("!Did not expect an ACK/NCK char. Clearing buffer!"));
while (Serial.available()){
Serial.read();
}
return;
}
else if (recvChar == STARTMARKER){
index = 1;
}
else if (index) {
if (recvChar != ENDMARKER) {
if (index > SERIAL_INDEX_MAX){
Serial.println(F("!Message too long!"));
}
message += recvChar << ((index-1)*8);
index++;
}
else { // end marker
index = 0;
serialFromPi = message;
break; //the recvChar loop
}
}
}
}
else{
Serial.print(F("In buffer:"));
Serial.println(Serial.available());
}
}
else if (Serial.peek() == INITMARKER){
Serial.read(); //discard the peeked character
state = SERIAL_RUNNING;
}
else if (Serial.peek() != -1 && Serial.availableForWrite() > 32){ // If a bad initialize character(s) is recieved, repeat evrrything back with an error message
Serial.print(F("!Unkown start char from Pi:")); //documentation: what's F
while (Serial.available() > 0 && Serial.availableForWrite() > 1){
recvChar = Serial.read();
Serial.print(recvChar);
}
Serial.println("!");
}
// Send start character if pi has initialized
if (state == SERIAL_RUNNING){
Serial.write(INITMARKER); //should block if the buffer is full. If it doesnt, Pi may never be initialized
prevReplyMS = ms;
}
break;
case SERIAL_RUNNING:
//Serial.println("here!");
// Recieve a packet
if (Serial.available() >= 4){
//Serial.
prevReplyMS = ms;
while (Serial.available()){
recvChar = Serial.read();
//the recieved char may either be ack/nck, start/end marker, or data:
if (bitRead(recvChar,POS_SERIAL_RES)){ //if the resrved bit is set, this is not part of the data
if (recvChar == ACKMARKER || recvChar == NAKMARKER){
prevMessageAckByPi = recvChar;
}
else{
Serial.println(F("!Bad ACK/NCK char!"));
}
}
else if (recvChar == STARTMARKER){
index = 1;
}
else if (index) {
if (recvChar != ENDMARKER) {
if (index > SERIAL_INDEX_MAX){
Serial.println(F("!Message too long!"));
}
message += recvChar << ((index-1)*8);
index++;
}
else { // end marker
index = 0;
//parity check
//parity_even_bit() generates the even parity bit. The parity from the message is removed and a new
//parity is generated, which is compared with the recieved parity.
if (parity_even_bit(message & ~bit(POS_SERIAL_EPARITY)) == bitRead(message,POS_SERIAL_EPARITY)){
if (Serial.availableForWrite() > 32){
Serial.write(ACKMARKER);
serialFromPi = message;
message = 0;
}
}
else {
if (Serial.availableForWrite() > 32){
Serial.write(NAKMARKER); //This sends "NAK" (Negative aknowlegde) character, so the pi repeats
}
}
break; //the recvChar loop
}
}
}
}
// If nothing is recieved, lets do a timeout check:
else if (ms - prevReplyMS > 10000){
//Serial.print(ms);
//Serial.print(prevReplyMS);
Serial.println("!Timeout!");
state = SERIAL_INITIALIZING;
}
//--------------------------------------------------------------
// Sending a packet
/* TO BE DONE. Here's the old code, which may work well or not:
serialToPi = bitClear(serialToPi,POS_SERIAL_EPARITY); //remove old parity bit
serialToPi += parity_even_bit(serialToPi) << 15; //add parity bit to the start
if (prevMessageAckByPi == ACKMARKER){
uniqueMessagesMissed = 0;
if (Serial.availableForWrite() > 32){
if (prevMessageToPi != serialToPi || ms - prevSendMS > SEND_NONUNIQUE_MS){
prevSendMS = ms;
prevMessageToPi = serialToPi;
Serial.write(STARTMARKER);
Serial.write(serialToPi >> 8); //1111-0000-1010-1100 becomes >>>>->>>>-1111-0000
Serial.write(serialToPi); //Only 1010-1100 is accepted from 1111-0000-1010-1100
Serial.write(ENDMARKER);
Serial.write(0x0A); //new line
}
}
else {
#ifndef DEBUGMODE
return SERIAL_FAIL;
#endif;
}
}
else {
if (Serial.availableForWrite() > 32){
prevSendMS = ms;
Serial.write(STARTMARKER);
Serial.write(prevMessageToPi >> 8); //1111-0000-1010-1100 becomes >>>>->>>>-1111-0000
Serial.write(prevMessageToPi); //Only 1010-1100 is accepted from 1111-0000-1010-1100
Serial.write(ENDMARKER);
Serial.write(0x0A); //new line
if (prevMessageToPi != serialToPi){
uniqueMessagesMissed++;
if (uniqueMessagesMissed > 10){
#ifndef DEBUGMODE
return SERIAL_FAIL;
#endif
}
}
}
else {
#ifndef DEBUGMODE
return SERIAL_FAIL;
#endif
}
}
*/
break;
default:
Serial.println(F("!Bad State!"));
}
}