Reputation: 909
I am trying to write Node.js script that uses the serialport
npm package to read and write data to COM5
serial port, which is connected to a device using RS-232 cable. This device is automatically transmitting the data it has.
To retrieve the data stored inside the device, I need to send, first, one byte 0x80 (uInt8
) to the device and expect to receive 81 as a hex number from the device. Second, I need to send another byte 0x81 (uInt8
) and then expect to receive all stored data (around 130000 bytes) as lines.
There is no way how to retrieve the whole stored data only by two bytes, one after another. Communication with the device can only be done by bytes.
I tried the following code:
import SerialPort from 'serialport';
const sp = new SerialPort.SerialPort({path: "COM5", baudRate: 115200});
const buff = Buffer.allocUnsafe(1);
buff.writeUInt8(0x80, 0);
sp.write(buff, function (err){
if (err){
return console.log("Error on write: ", err.message);
}
console.log("Port.write: ", buff);
});
sp.on('readable', function () {
var arr = new Uint8Array(sp._pool);
console.log('Data:', arr);
});
When running my script (using node myScript.mjs
), I see the following:
PortWrite: <Buffer 80>
Data: Uint8Array(65536) [
0, 30, 167, 106, 127, 2, 0, 0, 32, 31, 170, 106,
127, 2, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0,
16, 84, 18, 76, 196, 0, 0, 0, 100, 84, 18, 76,
196, 0, 0, 0, 184, 84, 18, 76, 196, 0, 0, 0,
160, 84, 18, 76, 196, 0, 0, 0, 244, 84, 18, 76,
196, 0, 0, 0, 72, 85, 18, 76, 196, 0, 0, 0,
240, 120, 18, 76, 196, 0, 0, 0, 68, 121, 18, 76,
196, 0, 0, 0, 152, 121, 18, 76, 196, 0, 0, 0,
240, 120, 18, 76,
... 65436 more items
]
The program doesn't exit until I hit Ctrl+c
. I am not sure what ps._pool
does but it seems the output is not correct but looks like giving something at random.
I am new to Node.js. I am also not sure how to add an argument TimeOut
of 10 seconds in the sp
object.
I tried to use Matlab, for testing, and I could retrieve the data successfully.
I tried Python too but didn't work for me - PySerial package is reading serial data before writing?.
Upvotes: 5
Views: 2130
Reputation: 11440
I believe you are listening for your data incorrectly. SerialPort is a form of a stream called a duplex which are both readable and writable. To listen for new data on a stream it is common practice to listen for the data
event.
Also worth noting in Javascript when variables start with an underscore, such as _pool
it usually means its a private variable which isn't generally suppose to use. See this SO question for more info
Simply rewriting sp.on('readable', function () {
part to be
sp.on('data', function(buffer) {
console.log(buffer);
});
Should make you start seeing the data your expecting.
To test this I wrote up the scenario you outlined but only wrote 10,000 bytes after 0x81 to test.
Please don't take this as great way to work with streams in JS. This was my attempt at doing it "lightweight" and there's probably better ways to write this
const {SerialPort} = require('serialport');
const sp = new SerialPort({path: "COM2", baudRate: 115200});
function Deferred(data) {
this.data = data;
this.resolve = null;
this.reject = null;
this.reset = () => {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this));
}
this.reset();
}
async function run() {
let readBuffer = Buffer.alloc(0);
let nextReadDeferred = new Deferred();
sp.on('data', function(newData) {
readBuffer = Buffer.concat([readBuffer, newData], newData.length + readBuffer.length)
console.log('Got new data: ' + newData.length + ' buffer length is ' + readBuffer.length);
nextReadDeferred.resolve(readBuffer);
nextReadDeferred.reset();
});
console.log('Start 0x80')
sp.write(Buffer.from([0x80]), e => { if(e) throw e; });
await nextReadDeferred.promise;
if(0x81 === readBuffer[0]) {
// clear the buffer in prep of getting our data
readBuffer = Buffer.alloc(0);
console.log('Send 0x81 to start data flow')
sp.write(Buffer.from([0x81]), e => { if(e) throw e; });
console.log('Starting to receive data. Not sure how to know when were done?');
// Dont know what to do here, I dont think the serial port closes. Maybe we are supposed to just expect a duration
// of no data transfer? I dont know a whole lot about COM communication
} else {
console.warn('Expected 0x81 but got', readBuffer)
}
}
run();
Output:
$ node index.js
Start 0x80
Got new data: 1 buffer length is 1
Send 0x81 to start data flow
Starting to receive data. Not sure how to know when were done?
Got new data: 1024 buffer length is 1024
Got new data: 4096 buffer length is 5120
Got new data: 1024 buffer length is 6144
Got new data: 3856 buffer length is 10000
To test this I used eterlogic for a virtual com port backed with a TCP server and the following Node code to be my "device"
const s = require('net').Socket();
s.connect(5555, '127.0.0.1');
s.on('data', function(d){
console.log('Got', d);
if(d.equals(Buffer.from([0x80]))) {
s.write(Buffer.from([0x81]));
} else if(d.equals(Buffer.from([0x81]))) {
s.write(Buffer.alloc(10000, 1));
}
});
Upvotes: 1