Node-red-node-serialport Buffer Length


I'm using the node-red-node-serialport to send / receive using a CC2530 and CC2531 TI serial device. The device sends bytes with the following frame format:
Byte 1 - SOF (0xFE)
Byte 2 - Length of message
Byte 3 - Command 0 (What type of message it is)
Byte 4 - Command 1 (message type)
Bytes 5->n - Data (n = number of Data bytes)
End Byte - XOR

I have set the serial node to "Optionally wait for a start character" of 0xFE and split after a silence of 0.5ms. This generally works OK but sometimes the serial receives more bytes than the message length because bytes can be received at different speeds.
I have had best success with using an end marker. The only issue with using a byte as the end marker is there is always a chance the message could contain the end marker byte.
Ideally I would like to use the second byte which contains the length of the message. Basically the second byte + 3 = the total length of the message.

I see in the node notes that if I use split input into fixed lengths I get the Tip: "In count mode msg.count can override the configured count as long as it smaller than the configured value."

I'm not sure if I can somehow use the second receive byte (length byte + 3) to tell the serial node to split the message using the message length. It would be a good feature to improve the quality of serial node using a length byte.

Are you able to modify your device to use something standard like ETX as an end marker? or a LF or CR?

Essentially use a character you know will NOT appear in the data as the end marker?

Is there really only 0.5ms (ie 1/2000 seconds) gap between the received messages? If the device sent out messages with a larger gap then you should be able to use that reliably.

I have been researching if I can use some sort of other character to split the messages. If I use ETX (hex 0x03), the data could contain 0x03. CR \r is hex 0x0d and new line \n - 0x0a. Which are all valid hex values which can be in the message. I can change the last character if I have to but would rather not, that means using another microcontroller connected to the CC2530 to receive and forward messages to Node Red.

I have tested a number of different split silence times, and had varying results. I only got consistent results when I used an end character. I could have another look at the datasheet but I tested a range of values. If it is a standard message which is received by the transceiver and sent through the serial it is received ok using split by silence mode. It is mostly when I send a request to the CC2530 through serial and receive more than one return messages that they seem to be inconsistent and overrun the message lengths.

Thank you

Do you always know that eventually there will be a larger gap? If so then set the silence time so as to split on the larger gap, when any sequence of messages is complete, and accept the fact that sometimes you will get more than one message in a buffer. Then split the buffer in node red using the start char and buffer length, with the end char as a confirmation that you have a complete buffer.

1 Like

I may need to split the messages using the split by silence method in the serial node. Then use a function node using the startmarker and length byte to further split the combined buffers. I will do some testing. Thanks for the suggestion.
I'm still not sure what this statement meant : Tip: "In count mode msg.count can override the configured count as long as it smaller than the configured value. Maybe there is a way to count the bytes in and split using a variable based off the length byte?

Hi - it means that (for the serial request node) - if you configure it to expect say 50 chars - then as part of your request you can say - actually no I only want 20 ... but it is part of the request so doing what you want is not really possible as yo would need to set the start char - ask for 2 - then ask for x more - but that second request would also want the start char.

Is it possible to split on more than one character with the serial node like you can with the TCP node? then perhaps the OP could use a combination of characters that would not normally be sent e.g. ETX * EOT

It would be great if the serial node can split on more than one character.

I modified the serial node java script codes to add splitting on more than one character, since my case is more complicated (the messages coming in have variable length).

happy to look at that as a pull request if you like.

If the OP had control of the sending device then he could ensure there is always an appropriate silence period between messages.

I can't edit the firmware on the cc2531. But I have connected a micro controller to receive then forward the messages to node red. So I can add extra end markers. I would prefer to just use the cc2531 stand alone. I have setup a node red interface based around receiving the byte frame format delivered by the cc2531.

Surely even if the message that arrives is too long you can still split it based on the length byte and then forward on two messages for processing?

I agree with Dave, what is the problem with waiting for completion of the group of messages and then splitting it up? I thought you suggested earlier that you were going to try that. The splitting code should be very simple to implement.

Ok I will implement somthing based on your advice and post the results. I't will be in a couple of weeks time.
Thanks for your help

Sorry for late reply. I only changed one line at 25-serial.js and it is hard coded :joy:
So I don't think it is worth a pull.
Here is the line that I changed and hopefully it is helpful:
if ((c === splitc[0]) || (i === bufMaxSize))
This line is changed into (assume that you want to match both 0x55 and the split character:
if (( c === splitc[0] && buf[i-2] === 0x55 ) || (i === bufMaxSize))

ah - right - indeed not exactly a general solution :-)... thanks


Just following up with the solution.
In the serial node I still used 0xFE as the start marker and I increased the Silence time to 5ms.
I have then created a function node which splits the input buffer if multiple messages are received. It uses a index variable and a while loop to forward the individual messages.

Thank you for the suggestions.

var buf = msg.payload;
var buf = msg.payload;
var index = 0; // Where to start in the buffer

while (buf[index] == 0xFE){

var Len = buf[index + 1];
var PayloadLength = Len + 5; // This is the total message lenth and includes the SOF, Len, Com0, Com1 and FCS
var Payload = [];

for(var i=0;i<PayloadLength;i++) {                  
    Payload.push(buf[index + i]);  
msg.payload = Buffer.from(Payload);

index += PayloadLength;