You don't need to revert to sending single bytes. Line oriented
protocols work well with both Arduino and Node.js. The only difficulty
is that you have to decide what line terminators you want to use, and
then consistently use them.
I tend to use CR for the PC → Arduino stream and CRLF for Arduino
→ PC. Using different line terminators is kind of odd, but this
convention plays well with terminal emulators: the emulator usually
sends CR when you hit <Enter>
, and expects CRLF in return. Also,
Arduino's Print::println()
sends CRLF.
Here is a simple test demonstrating this convention. Node.js side:
var SerialPort = require('serialport'),
port = new SerialPort('/dev/ttyACM0', {
baudRate: 9600,
parser: SerialPort.parsers.readline('\r\n')
});
port.on('open', () => setInterval(() => port.write('Test\r'), 1000));
port.on('data', console.log);
Notice the different line terminators in readline()
and write()
.
The Arduino side:
void setup() {
Serial.begin(9600);
}
void loop() {
static char buffer[128];
static size_t pos;
if (Serial.available()) {
char c = Serial.read();
if (c == '\r') { // line terminator
buffer[pos] = '\0'; // terminate the string
Serial.print(F("Arduino received: "));
Serial.println(buffer); // echo received message
pos = 0; // reset buffer position
} else if (pos < sizeof buffer - 1) { // regular character
buffer[pos++] = c; // buffer it
}
}
}
Here you may notice that Arduino has no equivalent of
parsers.readline()
, so I had to implement it (comparing the incoming
character to '\r'
). Note that explicit buffering of the incoming
message is a standard way of handling line-oriented protocols on
Arduino. Stream::readString()
does not work well for this purpose, as
it waits for incoming bytes until it times out.
Stream::readStringUntil()
may work better, but I prefer to avoid it
just because it returns a String
, which relies on heap allocation.
Serial.println()
plays well with serialport'sreadline("\r\n")
. – Edgar Bonet Apr 20 '17 at 15:43