I have built a device based on an ESP07s module and it is attached to a data source that sends data packets every 5 to 10 seconds at 115200 baud speed. The packets are about 700 bytes in size. So they take some 60 ms to transfer. In between the source is silent.
And there is no data sent to the source.
The packets consist of a packet start char (/) followed by number of lines terminated by CRLF and then there is a packet terminator that is ! (exclamation point) followed by a 4 character CRC value.
Reading the data:
I have used the Serial.readBytesUntil() function with a specification of the packet termination character so it will return when that character has been received.
But if something happens on the source so it stops sending anything, how can I then get out of the read loop since the delimiter is not arriving?
If I use the Serial.SetTimeout() function, can this be set once and left in place or does it need to be set before every call to the readBytesUntil() function?
Non-blocking read?
And how can I let the loop function still operate when I am waiting for the data to arrive on serial?
The read will be called from loop() at certain time intervals...
Reading at slower than transmit pace
I do not need to get all of the packets, rather I want to read one packet each minute.
So I need to make the serial port blind until I need to read a packet.
How can that be done?
If I do not read back all incoming bytes will the serial system overflow with non-handled data? Maybe there is a "buffer erase" function that can discard everything in the serial buffer before calling the readBytesUntil() function? But I have not found it...
don't you check for some data available before calling readBytesUntil()?
void
process (
char *buf )
{
}
char buf [80];
void
loop (void)
{
if (Serial.available ()) {
int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
buf [n] = '\0';
process (buf);
}
}
void
setup (void)
{
Serial.begin (9600);
}
how would you use readBytesUntil() to read this last line if it's not terminated with a \n
have you ever heard of TLVs? after reading a start byte, the next couple bytes would be read to determine the size and then that # of byte would be read, verifying that the checksum is zero
Could you please be more specific about this?
I have looked at what I believe to be "the top of the forum" but I don't see where I should go to get this info?
It would be nice to have a way to find it rather than asking, but in this case I could not...
Do you mean that ReadBytesUntil() requires the data read to be ALWAYS terminated by a a newline?
Seems strange to me since then it would make it impossible to use the ReadBytesUntil() with a serial stream with binary data and some special bytes as terminators...
Like in my case when the data ends in a special character not used inside the message itself and then followed by a 4-byte CRC checksum.
It should be read as it arrives starting with the / start char until the ! terminate char and then 4 more chars to get the checksum.
Note that I am trying to improve on a project I downloaded from GitHub and where the serial handling feels iffy.
Basically a loop waiting for / followed by a read until ! where the data are saved in a buffer which is then checked for valid CRC before being processed. Time between each message is 5s and the transfer is very quick at 115400 baud.
But it must not block the remaining functionality inside loop()
Well, unfortunately when I posted the last comment I had very little time left before we were due to go on a multi-day trip. Came back yesterday evening but I read some of it before going and I think I should be able to do some improvements.
But I need to figure out how to not block the main thread loop() when there is no incoming data (most of the time) while staying on when the start char has been detected.
And with a timeout if the sending device stops sending...
That is exactly what Robin's Serial Input Basics code demonstrates. It quickly reads what is available in the software buffer (and stores it in a second buffer) and next continues with the main loop.
Keep a variable to store millis() each time that a character is received; check the duration since the last received character to figure out if there is a timeout.
a more proper way to receive a block of data with a known start char, a CRC at the end, and presumably some way of knowing the size of the block would require a different approach that using readBytesUntil()
the following can be used to avoid blocking
void
process (
char c)
{
}
// -----------------------------------------------------------------------------
void loop()
{
while (Serial.available())
process (Serial.read());
}
// -----------------------------------------------------------------------------
void setup ()
{
Serial.begin(9600);
}
process() should be state driven. needs to
recognize when it is expecting the start byte and continue to read bytes until it sees the start byte when in that state
possibly capture a msg start time
presumably read the # of bytes within the msg or know the size based on type and read that many bytes
recognize when it expects to receive the CRC bytes, handle them appropriately (their value typically makes the final CRC zero) and discard the block if incorrect
monitor the time since msg start and discard what has been received if timed-out
Thanks for the pointer to the how-to pages!
Especially the code to erase the Rx queue.
I have another question here:
If I want to mute the serial port I assume I can do serial.end(), but what I really want is to just pause it until a later calculated time when it should resume receiving again.
If I use serial.end() can I then use serial.begin() to resume or do I need to set all the parameters again (baudrate, stop bits etc)? I.e. are the serial parameters saved across an end()-begin() command pairs?
I have added code to skip all chars preceding the / start char when reporting the data in the buffer, but I would really like to not have anything in the rx buffer when I start reading.
The existing code is too involved to simply add an rx queue delete anywhere.
And I don't want to rewrite it all...
If I did I would wait for the start char then read everything until the end char and the CRC bytes.
And only after checking CRC in the buffer would I parse the data, but the GitHub code reads one line at a time and checks for start and end chars in what it reads to switch state. while decoding all of the lines as they arrive.