faster-serialport
v2.3.0
Published
This is a stripped down, more performant version of [node-serialport](https://github.com/serialport/node-serialport). Actually works normally with Electron.
Readme
Faster SerialPort
This is a stripped down, more performant version of node-serialport. Actually works normally with Electron.
Supports macOS, Linux, and Windows.
How it works
The serial I/O is implemented in Go using go.bug.st/serial,
compiled to a C static archive (go build -buildmode=c-archive). A thin
node-addon-api (C++) layer links that
archive and exposes it to lib/index.js.
lib/index.js ──▶ lib/bindings.js ──▶ faster-serialport.node (C++) ──▶ libserial.a (Go) ──▶ go.bug.st/serialBuilding from source
Requires a Go toolchain (1.21+), a C++ compiler, and Node's build tools.
npm install # runs `npm run build` (build:go + build:addon)npm run build:gocompilesgo-serial/intobuild-go/libserial.anpm run build:addonrunsnode-gyp rebuildto compilesrc/addon.ccand link the archive
Notes / limitations
- Software/hardware flow control options (
rtscts,xon,xoff,xany) are accepted for API compatibility but are not applied —go.bug.st/serialdoes not expose flow-control configuration. eventsCallback(err, arg)is fired on Windows only, driven by a nativeWaitCommEventloop. On a line-status changearg.eventholds the raw Win32EV_*mask (e.g.64=EV_BREAK); when the device goes away the callback receives anErrorwitharg.errorCodeset (e.g.5=ERROR_ACCESS_DENIED). On macOS/Linux there is no comm-event equivalent, so the callback never fires — a disconnect still surfaces as an error from the nextread/write. The Windows path reads the portHANDLEout ofgo.bug.st/serialvia reflection (its private struct layout), so it must be re-checked when that dependency is upgraded.- On Windows the Go archive (GNU
ar) must be linked with a toolchain that can consume it; this path is configured inbinding.gypbut has not been validated on this platform.
API
import FasterSerialPort from "faster-serialport";
const deviceInfos = await FasterSerialPort.list();
const deviceInfo = deviceInfos.filter(d =>
d.path.indexOf(search) === -1 ||
d.manufacturer.indexOf(search) === -1 ||
d.serialNumber.indexOf(search) === -1 ||
d.pnpId.indexOf(search) === -1 ||
d.locationId.indexOf(search) === -1 ||
d.vendorId.indexOf(search) === -1 ||
d.productId.indexOf(search) === -1
)[0];
const device = new FasterSerialPort(deviceInfo.path, {
autoOpen: false,
baudRate: 9600,
dataBits: 8,
parity: "none",
stopBits: 1,
});
await device.open();
device.setTimeout(500); // return prematurely from any operation that takes longer than 500ms
function writeData() {
const data = Buffer...
// blocks until write has finished or timeout expires.
// If timeout expires, will throw in format "Timeout writing to port: %d of %d bytes written"
await device.write(data);
}
function waitForKnownDataSize() {
// blocks until the number of bytes specified are read or the timeout expires.
// If timeout expires, will return what ever data has been read.
// Will not throw if timeout expires
const data = await device.read(256);
if(data.length !== 256) throw new Error("missing data");
}
function pollForAnyData() {
device.setTimeout(10);
while(true) {
const data = await device.read(256);
if(data.length > 0) {
device.setTimeout(500);
return data;
}
}
}Credits
This package would not be possible without the folks over at node-serialport. This started out as a fork of their package and has morphed into something new.
