Send message and wait for response in node serialport

2.8k views Asked by At

I have a device which connects to computer via USB using serial interface. I can properly "talk" to it using npm-serialport with the following code:

const SerialPort = require('serialport');
const ReadLine = require('@serialport/parser-readline');

function handleResponse(data) {
  console.log('Rx', data);
  console.log();
}

SerialPort.list()
  .then(async portInfos => {
    portInfos.filter(pinfo => pinfo.manufacturer === 'FTDI')
      .forEach(async portInfo => {
        const port = new SerialPort(portInfo.path).setEncoding('ascii');

        const parser = port.pipe(new ReadLine({
          delimiter: '\r\n',
          encoding: 'ascii',
        }));
        parser.on('data', handleResponse);

        port.open();

        const serialMessage = api.createReadMessage(SERIAL);
        const batteryMessage = api.createReadMessage(BATTERY);

        for (const m of [serialMessage, batteryMessage]) {
          console.log('Tx', m.trim());
          port.write(m);
        }
      });
  });

My intention would be to get this output:

  Tx :0A0300070004E8
  Rx :0A030800000467000000017F
  
  Tx :0A03000B0002E6
  Rx :0A03040064006427

But instead I get this one:

  Tx :0A0300070004E8
  Tx :0A03000B0002E6
  Rx :0A030800000467000000017F
  
  Rx :0A03040064006427

This happens because the second Tx message is sent before the first Rx message is received, since reception is asynchronous / event-driven.

What I am looking for is this:

function sendAndReceive(messageToSend, port) {
  port.write(messageToSend);
  const response = port.readLine(); // BLOCKING, PERHAPS WITH TIMEOUT EXCEPTION;
  return response;
}

for (const m of [serialMessage, batteryMessage]) {
  console.log('Tx', m.trim());
  const response = sendAndReceive(m);
  console.log(response);
}

I looked for some "readliney" packages on npm (node-byline, linebyline, and also the native readline module), but all of them seem to rely on stream.on event, and that is not what I want (serialport-readline parser does exactly that, already).

Is there any function compatible with the Stream api that allows me to do this?

1

There are 1 answers

0
Hassan On

It looks like you can poll SerialPort.read() to implement blocking reads. Here's some untested pseudo code :

function sendAndReceive(messageToSend, port) {
  port.write(messageToSend);
  let response = '';
  while(true) {
    response = port.read(); // BLOCKING, PERHAPS WITH TIMEOUT EXCEPTION;
    if(response != null) {
      break;
    }
    sleep(1000);
  }
  return response;
}

function sleep(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms)
  })
}

Inspired from this issue : https://github.com/serialport/node-serialport/issues/1996