Safe to read from Serial1 during reception?

It sounds like there are some misc bugs in handling Serial1 in DeviceOS. I am experiencing some intermittent problems, still sorting it out.

I’m asking as a general question…

If a packet is arriving on Serial1, and let’s say it is 10 or 30 bytes long or something. Then let’s say I poll Serial1.available() and it reads when only 5 bytes have arrived, then I go start reading those into a local array by looping Serial1.read(), but at the same time, other bytes are still arriving… does this cause a problem?

Generally I would expect this is safe, but if there is a chance the packet could be corrupted I’ll need another strategy to make sure the entire packet has arrived before reading any of it. The packets will always be less than the 64 max.

I will not be sending anything out the Serial1 transmit during this time if that plays into it. (I think I’ve seen notes where the two buffers can become corrupted with each other).

Second side question… if loop() is blocked by a delay(), will received Serial1 bytes still arrive to the internal buffer in the background? I tested this briefly and it looks like they did arrive, but the function was still somewhat buggy for other reasons, wasn’t sure if this could be causing it.

Thanks.

How are you polling Serial1.available()? Using a while loop rather that an if statement with a for loop would ensure that you would continue to catch bytes as they arrived. An if statement with a for loop would only catch bytes that are already available in the buffer.

The while loop technique would look something like this:

char localBuffer[256];
char *localPtr = localBuffer;

while (Serial1.available()) {
    *localPtr++ = Serial1.read();
}

*localPtr = '\0';

if (strlen(localBuffer)) {
  Serial.printlnf("Got %s", localBuffer);
}

Why would you wait for the entire packet to arrive before reading it? Quickly reading from Serial1 into a local buffer and then checking if that buffer contains a valid packet would make more sense because there would be a lower chance of losing unread bytes.

It’s my understanding that since the Serial1 buffer is a hardware buffer, bytes will continue to be received if the application is blocked.

Great feedback and questions, thank you.

Normally I work on PIC processors where I would have an interrupt immediately grab each arriving character.

In Particle, I presently have what you basically describe… I call a “service_uart_rx()” function from loop(), but that can possibly run during the middle of packet reception.

This function contains a single while(Serial1.available()), inside of which, I use Serial1.read() to read each byte into an array.

This isn’t running smoothly not sure the cause yet. I’ve got some garbage bytes, it doesn’t stop at the end of the packet as expected, etc. Probably errors in my code, too much to post here and I’ll figure it out, but wanted to make sure it wasn’t my method of reading causing the problems before investigating further.

My packet can have raw data, so I can’t rely on an escape character. The second byte has the expected packet length, so I watch this until the correct length arrives.

To avoid hanging on a partial packet, I’ve tried to use Particle software timers, but something is happening either in the timer or the Serial1 handler that freezes the Particle device. The cyan continues breathing, but the blinking LED from my loop stops, and I cannot re-upload firmware because it won’t go into DFU mode. I have to physically remove it from my target board then cycle power to the Particle then I can re-program it.

As long as I don’t receive anything back on serial, this doesn’t happen.

I’m going to re-structure things so each transmit fully awaits for a complete receive before moving on so I don’t have loops tripping over each other and use a soft timeout as you suggested on my other thread. (thanks for that also btw).

Thanks!

1 Like

The RX and TX buffers for UART are entirely separate arrays, so they won’t interfere with eachother.
What you recall there is probably about the shared publish/subscribe buffers for the cloud communication.

When you get garbled data via RX it could be due to EMI on the RX lines or (more likely) a non-clean RX buffer.
If your data arrives asynchronously you need some means to synchronise your reading to the start of a packet flushing out everything that may be present in the RX buffer before that.

Once you know you started off with a clean RX buffer and at the start of a packet, you could try Serial1.readBytes(buffer, length) to read a given number of bytes reliably.

1 Like