In this great post - Serial Input Basics - updated - Introductory Tutorials - Arduino Forum - as I'm sure you know, there's a great explanation on the basics of serial communication. However there's a part of the code that I wish to understand, and I apologize if you feel that it has been explained properly elsewhere but I was not able to find it.
// Example 2 - Receive with an end-marker
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}
The part I don't understand is:
if (ndx >= numChars) {
ndx = numChars - 1;
}
What i don't understand is that if the ndx variable is equal to or above 32 it gets set to 32-1. Would that not mean that the next data to be put into the array, if it is not the endmarker, will overwrite data previously put into the array?
I am hoping to understand so I hope you can help me and I thank you in advance
Would that not mean that the next data to be put into the array, if it is not the endmarker, will overwrite data previously put into the array?
Yes that is what happens. The last byte in the array gets overwritten. Because if you write to memory beyond the end of the array into memory that you do not "own" very bad things can happen. So loosing the extra bytes is a better alternative.
If you want to read longer data packets, you can increase the numChars variable to what you need. Or if your data packets are smaller you can reduce the numChars variable to save memory.
Yes that is what happens. The last byte in the array gets overwritten. Because if you write to memory beyond the end of the array into memory that you do not "own" very bad things can happen. So loosing the extra bytes is a better alternative.
If you want to read longer data packets, you can increase the numChars variable to what you need. Or if your data packets are smaller you can reduce the numChars variable to save memory.
Ahh I see, so am I correct in my understanding that it is a safety measure? The data in the array will be corrupted but it is better than the alternative? @groundFungus
It is not a problem in my case since I will never exceed the 32 bytes, but it's still nice to know what exactly the code does.
if (ndx >= numChars)
{
// YIKES! The index has gone off the end of the buffer!
// Not much we can do here but throw away that last character to leave room for the terminating NULL.
// If this happens to you, it might be time to increase the size of your input buffer.
ndx = numChars - 1;
}
The original sketch developer could use the following '2-line codes' instead of 'so many lines of codes' as the terminating character (\n), number of data bytes to receive (32), and array name (receivedChars[]) are given. Is there any relative merits and demerits?
byte m = Serial.readUntilBytes('\n', receivedChars, 32);
receivedCars[m] = '\0'; //null character
The readBytesUntil function blocks until the terminator is received. The serial input basics code does not block, it reads bytes as they arrive. There is your difference.
receivedCars[m] = '\0'; //null character
If the function reads 32 bytes the '\0' would go into receivedChars[32].
groundFungus:
The readBytesUntil function blocks until the terminator is received.
Even the character \n does not arrive at all, the function will still terminate if 'programmable timeout period' is elapsed or 'requested number of data bytes' are received.
GolamMostafa:
Even the character \n does not arrive at all, the function will still terminate if 'programmable timeout period' is elapsed or 'requested number of data bytes' are received.
but it's blocking - you might have other things to do in the mean time.
That's one of the point of the Serial Input Basics tutorial, don't try to second guess the timing of data arrival in an asynchronous protocol, just handle what's coming until you have a well formed message and then deal with it.