The Serial.readBytesUntil() function would be perfect for my project. Unfortunately the devices I am dealing with use an uncommon terminator value, namely 0xfd. Unfortunately the readBytesUntil() function expects a char as terminator, but then proceeds to compare the latest received byte with type int .
0xfd received over the serial line and treated as int is 253. 0xfd received as char parameter in the function call is cast to a signed char value of 0xfffd or 0xfffffffd, depending on architecture.
Thus the compare always fails. This applies to all terminator chars with the high bit set, i.e. all character values from 0x80 to 0xff.
Is there any way to overcome this limitation, except patching the library?
No, I cannot change the terminator char, it's given by the manufacturer f the devices.
But you don't have to use the Serial.readBytesUntil() function. You can write your own
if a byte is available then read it
if it is not the terminator then put the byte in the array and increment the array index variable
keep doing this until you receive the terminating character
I have done this (reading single bytes, scanning for the terminator) since many years, but on other platforms. Now, starting with Arduino I found this nice readBytesUntil() function and wanted to use it.
Yes, the readBytesUntil() function reads bytes. Agreed.
But the terminator is handled as a signed char, not a byte.
Thus the comparison fails reliably 100% of the time if the terminator is in the rnage 0x80 to 0xff.
I justwanted to understand if this is a known shortcoming and if there is a workaround, other than writing your own
Ok, I will write my own serial receive function, again
I second your view of ReadBytesUntil(), also due to the fact that it incorporates a timeout which per default is 1000 msec ... You have much more control if you collect the data by your own ...
Variable length, but fixed frame format. Length varies from 3 to 255 bytes payload.
Frame always starts with the same bytes, always ends with the terminator, protocol definition ensures that start/end bytes cannot occur in the data stream.
But nevermind, I have now written a small receive routine, as you and others suggested. I just thought that I could use a nice and shiny function which does exactly what I need... alas...
Yeah, I think it's a mistake, or at least an omission in the documentation. Would have saved me some time, but I learned a lot
Using the terminator 0xfd as signed char leads the compiler to expand this value to 0xfffd (or 0xfffffffd). It starts as an 8 bit negative and the sign get's extended when the cast happens. That's a quite common pitfall in C as I understand it. The real culprit is handling the two sides of the comparison with different types - int vs. signed char.
I tried most useful data types for this char, charn (which is signed by default), unsigned char, byte, int, all to no avail. The value gets casted to char (signed) and sign expanded...
Anyway, as I said to UKHeliBob - I already wrote my own receive handler, as you suggested.
The deciding factor is the cast at entry to the function. No matter how I represent the value in the function call, it get's converted to a signed char, the sign gets expanded to int size.
Well, I don't blame anybody, that's how it is. I have benefited from open source hard and software all my life and know the procedures. Sometimes there are just more important things.