I have detected a problem with Serial.read(). It behaves differently with an Arduino Nano ESP32 and IDE 2.3.2 than I am used to. An ATmega2560 and IDE 2.3.2 behaves as usual. Likewise ATmega2560 and IDE 1.8.19.
When I read with Serial.read(), I get question marks in the serial monitor. Normally, if no data comes in, a -1 should be returned and my if() query should be skipped. Only when I also use Serial.available() does everything work correctly. Line 27 and 39.
Does anyone have an explanation for this?
Additional question. Why do I not see the START output in setup() in the serial monitor with Arduino Nano ESP32?
Stream &stream {Serial};
constexpr uint8_t BUFFER_SIZE {5};
struct ReceiveData {
char buffer [BUFFER_SIZE + 1]; // + Null-Terminator
size_t index {0};
};
ReceiveData rx;
void setup()
{
Serial.begin(115200);
stream.println("\nSTART\n");
}
void loop()
{
if (readSerial(rx, BUFFER_SIZE)) {
//
}
}
bool readSerial (ReceiveData &data, const uint8_t LENGTH)
{
bool status {false};
//if (stream.available()) {
char c = stream.read();
if (c == '\r' || c == '\n') { // if CR or LF is read in,
data.buffer[ data.index] = '\0'; // then termination
data.index = 0;
status = true; // character completely read in
}
else if ( (c >= 32) && ( data.index < LENGTH) ) { // if there is still space in the buffer,
data.buffer[data.index++] = c; // save characters and increment index
stream.print(F("read c: ")); stream.println(c);
}
//}
return status;
}
That is too simple. That would be a workaround and does not eliminate the problem.
My question would be why does read() behave differently? available() gives me the number of characters in the buffer. I do not need this information. Almost nobody needs it. I must be able to rely on the fact that read() returns a clean -1 if there are no characters. The question is, why is no -1 returned?
You need to understand the need of the Serial.available() function.
Assume Bd = 960, frame length = 10, No line ending option. One character (one frame) takes about 42 us ((1/9600)*10) time to arrive From Serial Monitor to Nano ESP32.
When a character arrives at the UART Port of NANO, the NANO is interrupted and the 8-bit character code (START and STOP bits are discarded) is automatically stored in a FIFO type Buffer.
Now, if you tell the MCU via your Serial.read() function to read a character from that FIFO Buffer, most probably, the function will not find a character in the Buffer as the character has not yet arrived because of 42 us transmission delay. That is what has happened in your case.
So, in order to be sure that Serial.read() function does not fail, one should check first that at least one charater has arrived/stored in the Buffer and then issue the read() method. The Serial.available() function does check the presence of at least one charcater in the Buffer.
void loop()
{
byte n = Serial.available(); //check that at least one character is in Buffer
if(n != 0)
{
char ch = Serial.read();
Serial.println(ch);
}
}
That's the point. read() reads from the buffer. If the buffer is empty, I expect -1. I don't see a problem with your 42µs. As long as the FIFO does not overflow, nothing bad should happen.
The definition of char in the Preferences Library is different from that in the core.
I have looked all over the ESP idf and the esp arduino core, and can not find the fundamental type definition for char as uint8_t but it is indeed unsigned on the ESP8266 and ESP32.
My guess is that @oqibidipo knows where the type definition is to be found.
@Doc_Arduino I don't think it is so much whether it is signed or unsigned I think it is a matter of using the int data type to get the correct return value.
Let's hold on for a moment.
I had assumed char as signed char because that's what I'm usually used to. I checked this with the type traits query, char is really unsigned The Cpp language standard defines signed char and unsigned char. char is not defined, it can be signed or unsigned. With another test I checked the value range, which is between 0 ... 255, so char practically corresponds to byte or uint8_t. Exactly as oqibidipo has written.
So far so good.
And now comes the ESP documentation. preferences and tells me that char corresponds to an int8_t.
If there is a discrepancy between the core and the documentation, then there is either an error in the core or in the documentation. This will lead other people into problems, independent of what char is used for. You actually rely on the documentation and don't start checking the documentation every time.
I continue programming with int as the read() return type and cast to char. Only what char is really supposed to be needs to be clarified and corrected.
yes, good. I can also use available().
However, I must again emphasize that the query is basically not necessary.
The real problem is with char.
However, a problem was discovered with the value range of char which needs to be clarified. I think this is important to understand.
I have to be clearer now. Why doesn't anyone read what I write and what the documentation says? What's so difficult to understand?
The ESP documentation says that char = int8_t.
Either the core or the documentation needs to be corrected. Depending on what the target data type should really be.
For ATmega/AVR char also corresponds to int8_t and matches with its documentation.