@jason2866/serialport-bindings-cpp 0.0.0-development → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/darwin.d.ts +38 -0
- package/dist/darwin.js +148 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +10 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +47 -0
- package/dist/linux-list.d.ts +3 -0
- package/dist/linux-list.js +114 -0
- package/dist/linux.d.ts +45 -0
- package/dist/linux.js +150 -0
- package/dist/load-bindings.d.ts +11 -0
- package/dist/load-bindings.js +16 -0
- package/dist/poller.d.ts +39 -0
- package/dist/poller.js +103 -0
- package/dist/serialport-bindings.d.ts +1 -0
- package/dist/serialport-bindings.js +10 -0
- package/dist/unix-read.d.ts +16 -0
- package/dist/unix-read.js +55 -0
- package/dist/unix-write.d.ts +12 -0
- package/dist/unix-write.js +56 -0
- package/dist/win32-sn-parser.d.ts +1 -0
- package/dist/win32-sn-parser.js +17 -0
- package/dist/win32.d.ts +34 -0
- package/dist/win32.js +162 -0
- package/package.json +2 -2
- package/prebuilds/darwin-x64+arm64/@jason2866+serialport-bindings-cpp.node +0 -0
- package/prebuilds/linux-x64/@jason2866+serialport-bindings-cpp.node +0 -0
- package/prebuilds/win32-x64/@jason2866+serialport-bindings-cpp.node +0 -0
- package/src/serialport_win.cpp +12 -4
package/dist/darwin.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BindingPortInterface } from '.';
|
|
2
|
+
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
|
3
|
+
import { Poller } from './poller';
|
|
4
|
+
export interface DarwinOpenOptions extends OpenOptions {
|
|
5
|
+
/** Defaults to none */
|
|
6
|
+
parity?: 'none' | 'even' | 'odd';
|
|
7
|
+
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 1 */
|
|
8
|
+
vmin?: number;
|
|
9
|
+
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 0 */
|
|
10
|
+
vtime?: number;
|
|
11
|
+
}
|
|
12
|
+
export type DarwinBindingInterface = BindingInterface<DarwinPortBinding, DarwinOpenOptions>;
|
|
13
|
+
export declare const DarwinBinding: DarwinBindingInterface;
|
|
14
|
+
/**
|
|
15
|
+
* The Darwin binding layer for OSX
|
|
16
|
+
*/
|
|
17
|
+
export declare class DarwinPortBinding implements BindingPortInterface {
|
|
18
|
+
readonly openOptions: Required<DarwinOpenOptions>;
|
|
19
|
+
readonly poller: Poller;
|
|
20
|
+
private writeOperation;
|
|
21
|
+
fd: null | number;
|
|
22
|
+
constructor(fd: number, options: Required<DarwinOpenOptions>);
|
|
23
|
+
get isOpen(): boolean;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
read(buffer: Buffer, offset: number, length: number): Promise<{
|
|
26
|
+
buffer: Buffer;
|
|
27
|
+
bytesRead: number;
|
|
28
|
+
}>;
|
|
29
|
+
write(buffer: Buffer): Promise<void>;
|
|
30
|
+
update(options: UpdateOptions): Promise<void>;
|
|
31
|
+
set(options: SetOptions): Promise<void>;
|
|
32
|
+
get(): Promise<PortStatus>;
|
|
33
|
+
getBaudRate(): Promise<{
|
|
34
|
+
baudRate: number;
|
|
35
|
+
}>;
|
|
36
|
+
flush(): Promise<void>;
|
|
37
|
+
drain(): Promise<void>;
|
|
38
|
+
}
|
package/dist/darwin.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DarwinPortBinding = exports.DarwinBinding = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const load_bindings_1 = require("./load-bindings");
|
|
9
|
+
const poller_1 = require("./poller");
|
|
10
|
+
const unix_read_1 = require("./unix-read");
|
|
11
|
+
const unix_write_1 = require("./unix-write");
|
|
12
|
+
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
|
13
|
+
exports.DarwinBinding = {
|
|
14
|
+
list() {
|
|
15
|
+
debug('list');
|
|
16
|
+
return (0, load_bindings_1.asyncList)();
|
|
17
|
+
},
|
|
18
|
+
async open(options) {
|
|
19
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
20
|
+
throw new TypeError('"options" is not an object');
|
|
21
|
+
}
|
|
22
|
+
if (!options.path) {
|
|
23
|
+
throw new TypeError('"path" is not a valid port');
|
|
24
|
+
}
|
|
25
|
+
if (!options.baudRate) {
|
|
26
|
+
throw new TypeError('"baudRate" is not a valid baudRate');
|
|
27
|
+
}
|
|
28
|
+
debug('open');
|
|
29
|
+
const openOptions = Object.assign({ vmin: 1, vtime: 0, dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
|
30
|
+
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
|
31
|
+
return new DarwinPortBinding(fd, openOptions);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The Darwin binding layer for OSX
|
|
36
|
+
*/
|
|
37
|
+
class DarwinPortBinding {
|
|
38
|
+
constructor(fd, options) {
|
|
39
|
+
this.fd = fd;
|
|
40
|
+
this.openOptions = options;
|
|
41
|
+
this.poller = new poller_1.Poller(fd);
|
|
42
|
+
this.writeOperation = null;
|
|
43
|
+
}
|
|
44
|
+
get isOpen() {
|
|
45
|
+
return this.fd !== null;
|
|
46
|
+
}
|
|
47
|
+
async close() {
|
|
48
|
+
debug('close');
|
|
49
|
+
if (!this.isOpen) {
|
|
50
|
+
throw new Error('Port is not open');
|
|
51
|
+
}
|
|
52
|
+
const fd = this.fd;
|
|
53
|
+
this.poller.stop();
|
|
54
|
+
this.poller.destroy();
|
|
55
|
+
this.fd = null;
|
|
56
|
+
await (0, load_bindings_1.asyncClose)(fd);
|
|
57
|
+
}
|
|
58
|
+
async read(buffer, offset, length) {
|
|
59
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
60
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
61
|
+
}
|
|
62
|
+
if (typeof offset !== 'number' || isNaN(offset)) {
|
|
63
|
+
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
|
64
|
+
}
|
|
65
|
+
if (typeof length !== 'number' || isNaN(length)) {
|
|
66
|
+
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
|
67
|
+
}
|
|
68
|
+
debug('read');
|
|
69
|
+
if (buffer.length < offset + length) {
|
|
70
|
+
throw new Error('buffer is too small');
|
|
71
|
+
}
|
|
72
|
+
if (!this.isOpen) {
|
|
73
|
+
throw new Error('Port is not open');
|
|
74
|
+
}
|
|
75
|
+
return (0, unix_read_1.unixRead)({ binding: this, buffer, offset, length });
|
|
76
|
+
}
|
|
77
|
+
async write(buffer) {
|
|
78
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
79
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
80
|
+
}
|
|
81
|
+
debug('write', buffer.length, 'bytes');
|
|
82
|
+
if (!this.isOpen) {
|
|
83
|
+
debug('write', 'error port is not open');
|
|
84
|
+
throw new Error('Port is not open');
|
|
85
|
+
}
|
|
86
|
+
this.writeOperation = (async () => {
|
|
87
|
+
if (buffer.length === 0) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
await (0, unix_write_1.unixWrite)({ binding: this, buffer });
|
|
91
|
+
this.writeOperation = null;
|
|
92
|
+
})();
|
|
93
|
+
return this.writeOperation;
|
|
94
|
+
}
|
|
95
|
+
async update(options) {
|
|
96
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
97
|
+
throw TypeError('"options" is not an object');
|
|
98
|
+
}
|
|
99
|
+
if (typeof options.baudRate !== 'number') {
|
|
100
|
+
throw new TypeError('"options.baudRate" is not a number');
|
|
101
|
+
}
|
|
102
|
+
debug('update');
|
|
103
|
+
if (!this.isOpen) {
|
|
104
|
+
throw new Error('Port is not open');
|
|
105
|
+
}
|
|
106
|
+
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
|
107
|
+
}
|
|
108
|
+
async set(options) {
|
|
109
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
110
|
+
throw new TypeError('"options" is not an object');
|
|
111
|
+
}
|
|
112
|
+
debug('set', options);
|
|
113
|
+
if (!this.isOpen) {
|
|
114
|
+
throw new Error('Port is not open');
|
|
115
|
+
}
|
|
116
|
+
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
|
117
|
+
}
|
|
118
|
+
async get() {
|
|
119
|
+
debug('get');
|
|
120
|
+
if (!this.isOpen) {
|
|
121
|
+
throw new Error('Port is not open');
|
|
122
|
+
}
|
|
123
|
+
return (0, load_bindings_1.asyncGet)(this.fd);
|
|
124
|
+
}
|
|
125
|
+
async getBaudRate() {
|
|
126
|
+
debug('getBaudRate');
|
|
127
|
+
if (!this.isOpen) {
|
|
128
|
+
throw new Error('Port is not open');
|
|
129
|
+
}
|
|
130
|
+
throw new Error('getBaudRate is not implemented on darwin');
|
|
131
|
+
}
|
|
132
|
+
async flush() {
|
|
133
|
+
debug('flush');
|
|
134
|
+
if (!this.isOpen) {
|
|
135
|
+
throw new Error('Port is not open');
|
|
136
|
+
}
|
|
137
|
+
await (0, load_bindings_1.asyncFlush)(this.fd);
|
|
138
|
+
}
|
|
139
|
+
async drain() {
|
|
140
|
+
debug('drain');
|
|
141
|
+
if (!this.isOpen) {
|
|
142
|
+
throw new Error('Port is not open');
|
|
143
|
+
}
|
|
144
|
+
await this.writeOperation;
|
|
145
|
+
await (0, load_bindings_1.asyncDrain)(this.fd);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.DarwinPortBinding = DarwinPortBinding;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BindingsErrorInterface } from '@serialport/bindings-interface';
|
|
2
|
+
export declare class BindingsError extends Error implements BindingsErrorInterface {
|
|
3
|
+
canceled: boolean;
|
|
4
|
+
constructor(message: string, { canceled }?: {
|
|
5
|
+
canceled?: boolean | undefined;
|
|
6
|
+
});
|
|
7
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BindingsError = void 0;
|
|
4
|
+
class BindingsError extends Error {
|
|
5
|
+
constructor(message, { canceled = false } = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.canceled = canceled;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.BindingsError = BindingsError;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DarwinBindingInterface } from './darwin';
|
|
2
|
+
import { LinuxBindingInterface } from './linux';
|
|
3
|
+
import { WindowsBindingInterface } from './win32';
|
|
4
|
+
export * from '@serialport/bindings-interface';
|
|
5
|
+
export * from './darwin';
|
|
6
|
+
export * from './linux';
|
|
7
|
+
export * from './win32';
|
|
8
|
+
export * from './errors';
|
|
9
|
+
export type AutoDetectTypes = DarwinBindingInterface | WindowsBindingInterface | LinuxBindingInterface;
|
|
10
|
+
/**
|
|
11
|
+
* This is an auto detected binding for your current platform
|
|
12
|
+
*/
|
|
13
|
+
export declare function autoDetect(): AutoDetectTypes;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.autoDetect = autoDetect;
|
|
21
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
22
|
+
const debug_1 = __importDefault(require("debug"));
|
|
23
|
+
const darwin_1 = require("./darwin");
|
|
24
|
+
const linux_1 = require("./linux");
|
|
25
|
+
const win32_1 = require("./win32");
|
|
26
|
+
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
|
27
|
+
__exportStar(require("@serialport/bindings-interface"), exports);
|
|
28
|
+
__exportStar(require("./darwin"), exports);
|
|
29
|
+
__exportStar(require("./linux"), exports);
|
|
30
|
+
__exportStar(require("./win32"), exports);
|
|
31
|
+
__exportStar(require("./errors"), exports);
|
|
32
|
+
/**
|
|
33
|
+
* This is an auto detected binding for your current platform
|
|
34
|
+
*/
|
|
35
|
+
function autoDetect() {
|
|
36
|
+
switch (process.platform) {
|
|
37
|
+
case 'win32':
|
|
38
|
+
debug('loading WindowsBinding');
|
|
39
|
+
return win32_1.WindowsBinding;
|
|
40
|
+
case 'darwin':
|
|
41
|
+
debug('loading DarwinBinding');
|
|
42
|
+
return darwin_1.DarwinBinding;
|
|
43
|
+
default:
|
|
44
|
+
debug('loading LinuxBinding');
|
|
45
|
+
return linux_1.LinuxBinding;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.linuxList = linuxList;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const parser_readline_1 = require("@serialport/parser-readline");
|
|
6
|
+
// get only serial port names
|
|
7
|
+
function checkPathOfDevice(path) {
|
|
8
|
+
return /(tty(S|WCH|ACM|USB|AMA|MFD|O|XRUSB)|rfcomm)/.test(path) && path;
|
|
9
|
+
}
|
|
10
|
+
function propName(name) {
|
|
11
|
+
return {
|
|
12
|
+
DEVNAME: 'path',
|
|
13
|
+
ID_VENDOR_ENC: 'manufacturer',
|
|
14
|
+
ID_SERIAL_SHORT: 'serialNumber',
|
|
15
|
+
ID_VENDOR_ID: 'vendorId',
|
|
16
|
+
ID_MODEL_ID: 'productId',
|
|
17
|
+
DEVLINKS: 'pnpId',
|
|
18
|
+
/**
|
|
19
|
+
* Workaround for systemd defect
|
|
20
|
+
* see https://github.com/serialport/bindings-cpp/issues/115
|
|
21
|
+
*/
|
|
22
|
+
ID_USB_VENDOR_ENC: 'manufacturer',
|
|
23
|
+
ID_USB_SERIAL_SHORT: 'serialNumber',
|
|
24
|
+
ID_USB_VENDOR_ID: 'vendorId',
|
|
25
|
+
ID_USB_MODEL_ID: 'productId',
|
|
26
|
+
// End of workaround
|
|
27
|
+
}[name.toUpperCase()];
|
|
28
|
+
}
|
|
29
|
+
function decodeHexEscape(str) {
|
|
30
|
+
return str.replace(/\\x([a-fA-F0-9]{2})/g, (a, b) => {
|
|
31
|
+
return String.fromCharCode(parseInt(b, 16));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function propVal(name, val) {
|
|
35
|
+
if (name === 'pnpId') {
|
|
36
|
+
const match = val.match(/\/by-id\/([^\s]+)/);
|
|
37
|
+
return (match === null || match === void 0 ? void 0 : match[1]) || undefined;
|
|
38
|
+
}
|
|
39
|
+
if (name === 'manufacturer') {
|
|
40
|
+
return decodeHexEscape(val);
|
|
41
|
+
}
|
|
42
|
+
if (/^0x/.test(val)) {
|
|
43
|
+
return val.substr(2);
|
|
44
|
+
}
|
|
45
|
+
return val;
|
|
46
|
+
}
|
|
47
|
+
function linuxList(spawnCmd = child_process_1.spawn) {
|
|
48
|
+
const ports = [];
|
|
49
|
+
const udevadm = spawnCmd('udevadm', ['info', '-e']);
|
|
50
|
+
const lines = udevadm.stdout.pipe(new parser_readline_1.ReadlineParser());
|
|
51
|
+
let skipPort = false;
|
|
52
|
+
let port = {
|
|
53
|
+
path: '',
|
|
54
|
+
manufacturer: undefined,
|
|
55
|
+
serialNumber: undefined,
|
|
56
|
+
pnpId: undefined,
|
|
57
|
+
locationId: undefined,
|
|
58
|
+
vendorId: undefined,
|
|
59
|
+
productId: undefined,
|
|
60
|
+
};
|
|
61
|
+
lines.on('data', (line) => {
|
|
62
|
+
const lineType = line.slice(0, 1);
|
|
63
|
+
const data = line.slice(3);
|
|
64
|
+
// new port entry
|
|
65
|
+
if (lineType === 'P') {
|
|
66
|
+
port = {
|
|
67
|
+
path: '',
|
|
68
|
+
manufacturer: undefined,
|
|
69
|
+
serialNumber: undefined,
|
|
70
|
+
pnpId: undefined,
|
|
71
|
+
locationId: undefined,
|
|
72
|
+
vendorId: undefined,
|
|
73
|
+
productId: undefined,
|
|
74
|
+
};
|
|
75
|
+
skipPort = false;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (skipPort) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Check dev name and save port if it matches flag to skip the rest of the data if not
|
|
82
|
+
if (lineType === 'N') {
|
|
83
|
+
if (checkPathOfDevice(data)) {
|
|
84
|
+
ports.push(port);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
skipPort = true;
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// parse data about each port
|
|
92
|
+
if (lineType === 'E') {
|
|
93
|
+
const keyValue = data.match(/^(.+)=(.*)/);
|
|
94
|
+
if (!keyValue) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const key = propName(keyValue[1]);
|
|
98
|
+
if (!key) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
port[key] = propVal(key, keyValue[2]);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
udevadm.on('close', (code) => {
|
|
106
|
+
if (code) {
|
|
107
|
+
reject(new Error(`Error listing ports udevadm exited with error code: ${code}`));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
udevadm.on('error', reject);
|
|
111
|
+
lines.on('error', reject);
|
|
112
|
+
lines.on('finish', () => resolve(ports));
|
|
113
|
+
});
|
|
114
|
+
}
|
package/dist/linux.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Poller } from './poller';
|
|
2
|
+
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
|
3
|
+
import { BindingPortInterface } from '.';
|
|
4
|
+
export interface LinuxOpenOptions extends OpenOptions {
|
|
5
|
+
/** Defaults to none */
|
|
6
|
+
parity?: 'none' | 'even' | 'odd';
|
|
7
|
+
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 1 */
|
|
8
|
+
vmin?: number;
|
|
9
|
+
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 0 */
|
|
10
|
+
vtime?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface LinuxPortStatus extends PortStatus {
|
|
13
|
+
lowLatency: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface LinuxSetOptions extends SetOptions {
|
|
16
|
+
/** Low latency mode */
|
|
17
|
+
lowLatency?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type LinuxBindingInterface = BindingInterface<LinuxPortBinding, LinuxOpenOptions>;
|
|
20
|
+
export declare const LinuxBinding: LinuxBindingInterface;
|
|
21
|
+
/**
|
|
22
|
+
* The linux binding layer
|
|
23
|
+
*/
|
|
24
|
+
export declare class LinuxPortBinding implements BindingPortInterface {
|
|
25
|
+
readonly openOptions: Required<LinuxOpenOptions>;
|
|
26
|
+
readonly poller: Poller;
|
|
27
|
+
private writeOperation;
|
|
28
|
+
fd: number | null;
|
|
29
|
+
constructor(fd: number, openOptions: Required<LinuxOpenOptions>);
|
|
30
|
+
get isOpen(): boolean;
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
read(buffer: Buffer, offset: number, length: number): Promise<{
|
|
33
|
+
buffer: Buffer;
|
|
34
|
+
bytesRead: number;
|
|
35
|
+
}>;
|
|
36
|
+
write(buffer: Buffer): Promise<void>;
|
|
37
|
+
update(options: UpdateOptions): Promise<void>;
|
|
38
|
+
set(options: LinuxSetOptions): Promise<void>;
|
|
39
|
+
get(): Promise<LinuxPortStatus>;
|
|
40
|
+
getBaudRate(): Promise<{
|
|
41
|
+
baudRate: number;
|
|
42
|
+
}>;
|
|
43
|
+
flush(): Promise<void>;
|
|
44
|
+
drain(): Promise<void>;
|
|
45
|
+
}
|
package/dist/linux.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LinuxPortBinding = exports.LinuxBinding = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const linux_list_1 = require("./linux-list");
|
|
9
|
+
const poller_1 = require("./poller");
|
|
10
|
+
const unix_read_1 = require("./unix-read");
|
|
11
|
+
const unix_write_1 = require("./unix-write");
|
|
12
|
+
const load_bindings_1 = require("./load-bindings");
|
|
13
|
+
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
|
14
|
+
exports.LinuxBinding = {
|
|
15
|
+
list() {
|
|
16
|
+
debug('list');
|
|
17
|
+
return (0, linux_list_1.linuxList)();
|
|
18
|
+
},
|
|
19
|
+
async open(options) {
|
|
20
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
21
|
+
throw new TypeError('"options" is not an object');
|
|
22
|
+
}
|
|
23
|
+
if (!options.path) {
|
|
24
|
+
throw new TypeError('"path" is not a valid port');
|
|
25
|
+
}
|
|
26
|
+
if (!options.baudRate) {
|
|
27
|
+
throw new TypeError('"baudRate" is not a valid baudRate');
|
|
28
|
+
}
|
|
29
|
+
debug('open');
|
|
30
|
+
const openOptions = Object.assign({ vmin: 1, vtime: 0, dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
|
31
|
+
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
|
32
|
+
this.fd = fd;
|
|
33
|
+
return new LinuxPortBinding(fd, openOptions);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The linux binding layer
|
|
38
|
+
*/
|
|
39
|
+
class LinuxPortBinding {
|
|
40
|
+
constructor(fd, openOptions) {
|
|
41
|
+
this.fd = fd;
|
|
42
|
+
this.openOptions = openOptions;
|
|
43
|
+
this.poller = new poller_1.Poller(fd);
|
|
44
|
+
this.writeOperation = null;
|
|
45
|
+
}
|
|
46
|
+
get isOpen() {
|
|
47
|
+
return this.fd !== null;
|
|
48
|
+
}
|
|
49
|
+
async close() {
|
|
50
|
+
debug('close');
|
|
51
|
+
if (!this.isOpen) {
|
|
52
|
+
throw new Error('Port is not open');
|
|
53
|
+
}
|
|
54
|
+
const fd = this.fd;
|
|
55
|
+
this.poller.stop();
|
|
56
|
+
this.poller.destroy();
|
|
57
|
+
this.fd = null;
|
|
58
|
+
await (0, load_bindings_1.asyncClose)(fd);
|
|
59
|
+
}
|
|
60
|
+
async read(buffer, offset, length) {
|
|
61
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
62
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
63
|
+
}
|
|
64
|
+
if (typeof offset !== 'number' || isNaN(offset)) {
|
|
65
|
+
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
|
66
|
+
}
|
|
67
|
+
if (typeof length !== 'number' || isNaN(length)) {
|
|
68
|
+
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
|
69
|
+
}
|
|
70
|
+
debug('read');
|
|
71
|
+
if (buffer.length < offset + length) {
|
|
72
|
+
throw new Error('buffer is too small');
|
|
73
|
+
}
|
|
74
|
+
if (!this.isOpen) {
|
|
75
|
+
throw new Error('Port is not open');
|
|
76
|
+
}
|
|
77
|
+
return (0, unix_read_1.unixRead)({ binding: this, buffer, offset, length });
|
|
78
|
+
}
|
|
79
|
+
async write(buffer) {
|
|
80
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
81
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
82
|
+
}
|
|
83
|
+
debug('write', buffer.length, 'bytes');
|
|
84
|
+
if (!this.isOpen) {
|
|
85
|
+
debug('write', 'error port is not open');
|
|
86
|
+
throw new Error('Port is not open');
|
|
87
|
+
}
|
|
88
|
+
this.writeOperation = (async () => {
|
|
89
|
+
if (buffer.length === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
await (0, unix_write_1.unixWrite)({ binding: this, buffer });
|
|
93
|
+
this.writeOperation = null;
|
|
94
|
+
})();
|
|
95
|
+
return this.writeOperation;
|
|
96
|
+
}
|
|
97
|
+
async update(options) {
|
|
98
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
99
|
+
throw TypeError('"options" is not an object');
|
|
100
|
+
}
|
|
101
|
+
if (typeof options.baudRate !== 'number') {
|
|
102
|
+
throw new TypeError('"options.baudRate" is not a number');
|
|
103
|
+
}
|
|
104
|
+
debug('update');
|
|
105
|
+
if (!this.isOpen) {
|
|
106
|
+
throw new Error('Port is not open');
|
|
107
|
+
}
|
|
108
|
+
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
|
109
|
+
}
|
|
110
|
+
async set(options) {
|
|
111
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
112
|
+
throw new TypeError('"options" is not an object');
|
|
113
|
+
}
|
|
114
|
+
debug('set');
|
|
115
|
+
if (!this.isOpen) {
|
|
116
|
+
throw new Error('Port is not open');
|
|
117
|
+
}
|
|
118
|
+
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
|
119
|
+
}
|
|
120
|
+
async get() {
|
|
121
|
+
debug('get');
|
|
122
|
+
if (!this.isOpen) {
|
|
123
|
+
throw new Error('Port is not open');
|
|
124
|
+
}
|
|
125
|
+
return (0, load_bindings_1.asyncGet)(this.fd);
|
|
126
|
+
}
|
|
127
|
+
async getBaudRate() {
|
|
128
|
+
debug('getBaudRate');
|
|
129
|
+
if (!this.isOpen) {
|
|
130
|
+
throw new Error('Port is not open');
|
|
131
|
+
}
|
|
132
|
+
return (0, load_bindings_1.asyncGetBaudRate)(this.fd);
|
|
133
|
+
}
|
|
134
|
+
async flush() {
|
|
135
|
+
debug('flush');
|
|
136
|
+
if (!this.isOpen) {
|
|
137
|
+
throw new Error('Port is not open');
|
|
138
|
+
}
|
|
139
|
+
await (0, load_bindings_1.asyncFlush)(this.fd);
|
|
140
|
+
}
|
|
141
|
+
async drain() {
|
|
142
|
+
debug('drain');
|
|
143
|
+
if (!this.isOpen) {
|
|
144
|
+
throw new Error('Port is not open');
|
|
145
|
+
}
|
|
146
|
+
await this.writeOperation;
|
|
147
|
+
await (0, load_bindings_1.asyncDrain)(this.fd);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.LinuxPortBinding = LinuxPortBinding;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const asyncClose: Function;
|
|
2
|
+
export declare const asyncDrain: Function;
|
|
3
|
+
export declare const asyncFlush: Function;
|
|
4
|
+
export declare const asyncGet: Function;
|
|
5
|
+
export declare const asyncGetBaudRate: Function;
|
|
6
|
+
export declare const asyncList: Function;
|
|
7
|
+
export declare const asyncOpen: Function;
|
|
8
|
+
export declare const asyncSet: Function;
|
|
9
|
+
export declare const asyncUpdate: Function;
|
|
10
|
+
export declare const asyncRead: Function;
|
|
11
|
+
export declare const asyncWrite: Function;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asyncWrite = exports.asyncRead = exports.asyncUpdate = exports.asyncSet = exports.asyncOpen = exports.asyncList = exports.asyncGetBaudRate = exports.asyncGet = exports.asyncFlush = exports.asyncDrain = exports.asyncClose = void 0;
|
|
4
|
+
const util_1 = require("util");
|
|
5
|
+
const serialport_bindings_1 = require("./serialport-bindings");
|
|
6
|
+
exports.asyncClose = serialport_bindings_1.binding.close ? (0, util_1.promisify)(serialport_bindings_1.binding.close) : async () => { throw new Error('"binding.close" Method not implemented'); };
|
|
7
|
+
exports.asyncDrain = serialport_bindings_1.binding.drain ? (0, util_1.promisify)(serialport_bindings_1.binding.drain) : async () => { throw new Error('"binding.drain" Method not implemented'); };
|
|
8
|
+
exports.asyncFlush = serialport_bindings_1.binding.flush ? (0, util_1.promisify)(serialport_bindings_1.binding.flush) : async () => { throw new Error('"binding.flush" Method not implemented'); };
|
|
9
|
+
exports.asyncGet = serialport_bindings_1.binding.get ? (0, util_1.promisify)(serialport_bindings_1.binding.get) : async () => { throw new Error('"binding.get" Method not implemented'); };
|
|
10
|
+
exports.asyncGetBaudRate = serialport_bindings_1.binding.getBaudRate ? (0, util_1.promisify)(serialport_bindings_1.binding.getBaudRate) : async () => { throw new Error('"binding.getBaudRate" Method not implemented'); };
|
|
11
|
+
exports.asyncList = serialport_bindings_1.binding.list ? (0, util_1.promisify)(serialport_bindings_1.binding.list) : async () => { throw new Error('"binding.list" Method not implemented'); };
|
|
12
|
+
exports.asyncOpen = serialport_bindings_1.binding.open ? (0, util_1.promisify)(serialport_bindings_1.binding.open) : async () => { throw new Error('"binding.open" Method not implemented'); };
|
|
13
|
+
exports.asyncSet = serialport_bindings_1.binding.set ? (0, util_1.promisify)(serialport_bindings_1.binding.set) : async () => { throw new Error('"binding.set" Method not implemented'); };
|
|
14
|
+
exports.asyncUpdate = serialport_bindings_1.binding.update ? (0, util_1.promisify)(serialport_bindings_1.binding.update) : async () => { throw new Error('"binding.update" Method not implemented'); };
|
|
15
|
+
exports.asyncRead = serialport_bindings_1.binding.read ? (0, util_1.promisify)(serialport_bindings_1.binding.read) : async () => { throw new Error('"binding.read" Method not implemented'); };
|
|
16
|
+
exports.asyncWrite = serialport_bindings_1.binding.write ? (0, util_1.promisify)(serialport_bindings_1.binding.write) : async () => { throw new Error('"binding.write" Method not implemented'); };
|
package/dist/poller.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
interface PollerClass {
|
|
3
|
+
new (fd: number, cb: (err: Error, flag: number) => void): PollerInstance;
|
|
4
|
+
}
|
|
5
|
+
interface PollerInstance {
|
|
6
|
+
poll(flag: number): void;
|
|
7
|
+
stop(): void;
|
|
8
|
+
destroy(): void;
|
|
9
|
+
}
|
|
10
|
+
export declare const EVENTS: {
|
|
11
|
+
UV_READABLE: number;
|
|
12
|
+
UV_WRITABLE: number;
|
|
13
|
+
UV_DISCONNECT: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Polls unix systems for readable or writable states of a file or serialport
|
|
17
|
+
*/
|
|
18
|
+
export declare class Poller extends EventEmitter {
|
|
19
|
+
poller: PollerInstance;
|
|
20
|
+
constructor(fd: number, FDPoller?: PollerClass);
|
|
21
|
+
/**
|
|
22
|
+
* Wait for the next event to occur
|
|
23
|
+
* @param {string} event ('readable'|'writable'|'disconnect')
|
|
24
|
+
* @returns {Poller} returns itself
|
|
25
|
+
*/
|
|
26
|
+
once(event: 'readable' | 'writable' | 'disconnect', callback: (err: null | Error) => void): this;
|
|
27
|
+
/**
|
|
28
|
+
* Ask the bindings to listen for an event, it is recommend to use `.once()` for easy use
|
|
29
|
+
* @param {EVENTS} eventFlag polls for an event or group of events based upon a flag.
|
|
30
|
+
*/
|
|
31
|
+
poll(eventFlag?: number): void;
|
|
32
|
+
/**
|
|
33
|
+
* Stop listening for events and cancel all outstanding listening with an error
|
|
34
|
+
*/
|
|
35
|
+
stop(): void;
|
|
36
|
+
destroy(): void;
|
|
37
|
+
emitCanceled(): void;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
package/dist/poller.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Poller = exports.EVENTS = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const events_1 = require("events");
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
const serialport_bindings_1 = require("./serialport-bindings");
|
|
11
|
+
const { Poller: PollerBindings } = serialport_bindings_1.binding;
|
|
12
|
+
const logger = (0, debug_1.default)('serialport/bindings-cpp/poller');
|
|
13
|
+
exports.EVENTS = {
|
|
14
|
+
UV_READABLE: 0b0001,
|
|
15
|
+
UV_WRITABLE: 0b0010,
|
|
16
|
+
UV_DISCONNECT: 0b0100,
|
|
17
|
+
};
|
|
18
|
+
function handleEvent(error, eventFlag) {
|
|
19
|
+
if (error) {
|
|
20
|
+
logger('error', error);
|
|
21
|
+
this.emit('readable', error);
|
|
22
|
+
this.emit('writable', error);
|
|
23
|
+
this.emit('disconnect', error);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (eventFlag & exports.EVENTS.UV_READABLE) {
|
|
27
|
+
logger('received "readable"');
|
|
28
|
+
this.emit('readable', null);
|
|
29
|
+
}
|
|
30
|
+
if (eventFlag & exports.EVENTS.UV_WRITABLE) {
|
|
31
|
+
logger('received "writable"');
|
|
32
|
+
this.emit('writable', null);
|
|
33
|
+
}
|
|
34
|
+
if (eventFlag & exports.EVENTS.UV_DISCONNECT) {
|
|
35
|
+
logger('received "disconnect"');
|
|
36
|
+
this.emit('disconnect', null);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Polls unix systems for readable or writable states of a file or serialport
|
|
41
|
+
*/
|
|
42
|
+
class Poller extends events_1.EventEmitter {
|
|
43
|
+
constructor(fd, FDPoller = PollerBindings) {
|
|
44
|
+
logger('Creating poller');
|
|
45
|
+
super();
|
|
46
|
+
this.poller = new FDPoller(fd, handleEvent.bind(this));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Wait for the next event to occur
|
|
50
|
+
* @param {string} event ('readable'|'writable'|'disconnect')
|
|
51
|
+
* @returns {Poller} returns itself
|
|
52
|
+
*/
|
|
53
|
+
once(event, callback) {
|
|
54
|
+
switch (event) {
|
|
55
|
+
case 'readable':
|
|
56
|
+
this.poll(exports.EVENTS.UV_READABLE);
|
|
57
|
+
break;
|
|
58
|
+
case 'writable':
|
|
59
|
+
this.poll(exports.EVENTS.UV_WRITABLE);
|
|
60
|
+
break;
|
|
61
|
+
case 'disconnect':
|
|
62
|
+
this.poll(exports.EVENTS.UV_DISCONNECT);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
return super.once(event, callback);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Ask the bindings to listen for an event, it is recommend to use `.once()` for easy use
|
|
69
|
+
* @param {EVENTS} eventFlag polls for an event or group of events based upon a flag.
|
|
70
|
+
*/
|
|
71
|
+
poll(eventFlag = 0) {
|
|
72
|
+
if (eventFlag & exports.EVENTS.UV_READABLE) {
|
|
73
|
+
logger('Polling for "readable"');
|
|
74
|
+
}
|
|
75
|
+
if (eventFlag & exports.EVENTS.UV_WRITABLE) {
|
|
76
|
+
logger('Polling for "writable"');
|
|
77
|
+
}
|
|
78
|
+
if (eventFlag & exports.EVENTS.UV_DISCONNECT) {
|
|
79
|
+
logger('Polling for "disconnect"');
|
|
80
|
+
}
|
|
81
|
+
this.poller.poll(eventFlag);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Stop listening for events and cancel all outstanding listening with an error
|
|
85
|
+
*/
|
|
86
|
+
stop() {
|
|
87
|
+
logger('Stopping poller');
|
|
88
|
+
this.poller.stop();
|
|
89
|
+
this.emitCanceled();
|
|
90
|
+
}
|
|
91
|
+
destroy() {
|
|
92
|
+
logger('Destroying poller');
|
|
93
|
+
this.poller.destroy();
|
|
94
|
+
this.emitCanceled();
|
|
95
|
+
}
|
|
96
|
+
emitCanceled() {
|
|
97
|
+
const err = new errors_1.BindingsError('Canceled', { canceled: true });
|
|
98
|
+
this.emit('readable', err);
|
|
99
|
+
this.emit('writable', err);
|
|
100
|
+
this.emit('disconnect', err);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.Poller = Poller;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const binding: any;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.binding = void 0;
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const node_gyp_build_1 = __importDefault(require("node-gyp-build"));
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
exports.binding = (0, node_gyp_build_1.default)((0, path_1.join)(__dirname, '../'));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { read as fsRead } from 'fs';
|
|
2
|
+
import { LinuxPortBinding } from './linux';
|
|
3
|
+
import { DarwinPortBinding } from './darwin';
|
|
4
|
+
declare const readAsync: typeof fsRead.__promisify__;
|
|
5
|
+
interface UnixReadOptions {
|
|
6
|
+
binding: LinuxPortBinding | DarwinPortBinding;
|
|
7
|
+
buffer: Buffer;
|
|
8
|
+
offset: number;
|
|
9
|
+
length: number;
|
|
10
|
+
fsReadAsync?: typeof readAsync;
|
|
11
|
+
}
|
|
12
|
+
export declare const unixRead: ({ binding, buffer, offset, length, fsReadAsync, }: UnixReadOptions) => Promise<{
|
|
13
|
+
buffer: Buffer;
|
|
14
|
+
bytesRead: number;
|
|
15
|
+
}>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.unixRead = void 0;
|
|
7
|
+
const util_1 = require("util");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
const debug_1 = __importDefault(require("debug"));
|
|
11
|
+
const logger = (0, debug_1.default)('serialport/bindings-cpp/unixRead');
|
|
12
|
+
const readAsync = (0, util_1.promisify)(fs_1.read);
|
|
13
|
+
const readable = (binding) => {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
if (!binding.poller) {
|
|
16
|
+
throw new Error('No poller on bindings');
|
|
17
|
+
}
|
|
18
|
+
binding.poller.once('readable', err => (err ? reject(err) : resolve()));
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
const unixRead = async ({ binding, buffer, offset, length, fsReadAsync = readAsync, }) => {
|
|
22
|
+
logger('Starting read');
|
|
23
|
+
if (!binding.isOpen || !binding.fd) {
|
|
24
|
+
throw new errors_1.BindingsError('Port is not open', { canceled: true });
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const { bytesRead } = await fsReadAsync(binding.fd, buffer, offset, length, null);
|
|
28
|
+
if (bytesRead === 0) {
|
|
29
|
+
return (0, exports.unixRead)({ binding, buffer, offset, length, fsReadAsync });
|
|
30
|
+
}
|
|
31
|
+
logger('Finished read', bytesRead, 'bytes');
|
|
32
|
+
return { bytesRead, buffer };
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
logger('read error', err);
|
|
36
|
+
if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') {
|
|
37
|
+
if (!binding.isOpen) {
|
|
38
|
+
throw new errors_1.BindingsError('Port is not open', { canceled: true });
|
|
39
|
+
}
|
|
40
|
+
logger('waiting for readable because of code:', err.code);
|
|
41
|
+
await readable(binding);
|
|
42
|
+
return (0, exports.unixRead)({ binding, buffer, offset, length, fsReadAsync });
|
|
43
|
+
}
|
|
44
|
+
const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed
|
|
45
|
+
err.code === 'ENXIO' || // No such device or address probably usb disconnect
|
|
46
|
+
err.code === 'UNKNOWN' ||
|
|
47
|
+
err.errno === -1; // generic error
|
|
48
|
+
if (disconnectError) {
|
|
49
|
+
err.disconnect = true;
|
|
50
|
+
logger('disconnecting', err);
|
|
51
|
+
}
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.unixRead = unixRead;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { write } from 'fs';
|
|
2
|
+
import { LinuxPortBinding } from './linux';
|
|
3
|
+
import { DarwinPortBinding } from './darwin';
|
|
4
|
+
declare const writeAsync: typeof write.__promisify__;
|
|
5
|
+
interface UnixWriteOptions {
|
|
6
|
+
binding: LinuxPortBinding | DarwinPortBinding;
|
|
7
|
+
buffer: Buffer;
|
|
8
|
+
offset?: number;
|
|
9
|
+
fsWriteAsync?: typeof writeAsync;
|
|
10
|
+
}
|
|
11
|
+
export declare const unixWrite: ({ binding, buffer, offset, fsWriteAsync }: UnixWriteOptions) => Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.unixWrite = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const debug_1 = __importDefault(require("debug"));
|
|
9
|
+
const util_1 = require("util");
|
|
10
|
+
const logger = (0, debug_1.default)('serialport/bindings-cpp/unixWrite');
|
|
11
|
+
const writeAsync = (0, util_1.promisify)(fs_1.write);
|
|
12
|
+
const writable = (binding) => {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
binding.poller.once('writable', err => (err ? reject(err) : resolve()));
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
const unixWrite = async ({ binding, buffer, offset = 0, fsWriteAsync = writeAsync }) => {
|
|
18
|
+
const bytesToWrite = buffer.length - offset;
|
|
19
|
+
logger('Starting write', buffer.length, 'bytes offset', offset, 'bytesToWrite', bytesToWrite);
|
|
20
|
+
if (!binding.isOpen || !binding.fd) {
|
|
21
|
+
throw new Error('Port is not open');
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const { bytesWritten } = await fsWriteAsync(binding.fd, buffer, offset, bytesToWrite);
|
|
25
|
+
logger('write returned: wrote', bytesWritten, 'bytes');
|
|
26
|
+
if (bytesWritten + offset < buffer.length) {
|
|
27
|
+
if (!binding.isOpen) {
|
|
28
|
+
throw new Error('Port is not open');
|
|
29
|
+
}
|
|
30
|
+
return (0, exports.unixWrite)({ binding, buffer, offset: bytesWritten + offset, fsWriteAsync });
|
|
31
|
+
}
|
|
32
|
+
logger('Finished writing', bytesWritten + offset, 'bytes');
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
logger('write errored', err);
|
|
36
|
+
if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') {
|
|
37
|
+
if (!binding.isOpen) {
|
|
38
|
+
throw new Error('Port is not open');
|
|
39
|
+
}
|
|
40
|
+
logger('waiting for writable because of code:', err.code);
|
|
41
|
+
await writable(binding);
|
|
42
|
+
return (0, exports.unixWrite)({ binding, buffer, offset, fsWriteAsync });
|
|
43
|
+
}
|
|
44
|
+
const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed
|
|
45
|
+
err.code === 'ENXIO' || // No such device or address probably usb disconnect
|
|
46
|
+
err.code === 'UNKNOWN' ||
|
|
47
|
+
err.errno === -1; // generic error
|
|
48
|
+
if (disconnectError) {
|
|
49
|
+
err.disconnect = true;
|
|
50
|
+
logger('disconnecting', err);
|
|
51
|
+
}
|
|
52
|
+
logger('error', err);
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
exports.unixWrite = unixWrite;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const serialNumParser: (pnpId?: string) => string | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serialNumParser = void 0;
|
|
4
|
+
const PARSERS = [/USB\\(?:.+)\\(.+)/, /FTDIBUS\\(?:.+)\+(.+?)A?\\.+/];
|
|
5
|
+
const serialNumParser = (pnpId) => {
|
|
6
|
+
if (!pnpId) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
for (const parser of PARSERS) {
|
|
10
|
+
const sn = pnpId.match(parser);
|
|
11
|
+
if (sn) {
|
|
12
|
+
return sn[1];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
exports.serialNumParser = serialNumParser;
|
package/dist/win32.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BindingPortInterface } from '.';
|
|
2
|
+
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
|
3
|
+
export interface WindowsOpenOptions extends OpenOptions {
|
|
4
|
+
/** Device parity defaults to none */
|
|
5
|
+
parity?: 'none' | 'even' | 'odd' | 'mark' | 'space';
|
|
6
|
+
/** RTS mode defaults to handshake */
|
|
7
|
+
rtsMode?: 'handshake' | 'enable' | 'toggle';
|
|
8
|
+
}
|
|
9
|
+
export type WindowsBindingInterface = BindingInterface<WindowsPortBinding, WindowsOpenOptions>;
|
|
10
|
+
export declare const WindowsBinding: WindowsBindingInterface;
|
|
11
|
+
/**
|
|
12
|
+
* The Windows binding layer
|
|
13
|
+
*/
|
|
14
|
+
export declare class WindowsPortBinding implements BindingPortInterface {
|
|
15
|
+
fd: null | number;
|
|
16
|
+
writeOperation: Promise<void> | null;
|
|
17
|
+
openOptions: Required<OpenOptions>;
|
|
18
|
+
constructor(fd: number, options: Required<OpenOptions>);
|
|
19
|
+
get isOpen(): boolean;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
read(buffer: Buffer, offset: number, length: number): Promise<{
|
|
22
|
+
buffer: Buffer;
|
|
23
|
+
bytesRead: number;
|
|
24
|
+
}>;
|
|
25
|
+
write(buffer: Buffer): Promise<void>;
|
|
26
|
+
update(options: UpdateOptions): Promise<void>;
|
|
27
|
+
set(options: SetOptions): Promise<void>;
|
|
28
|
+
get(): Promise<PortStatus>;
|
|
29
|
+
getBaudRate(): Promise<{
|
|
30
|
+
baudRate: number;
|
|
31
|
+
}>;
|
|
32
|
+
flush(): Promise<void>;
|
|
33
|
+
drain(): Promise<void>;
|
|
34
|
+
}
|
package/dist/win32.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WindowsPortBinding = exports.WindowsBinding = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const _1 = require(".");
|
|
9
|
+
const load_bindings_1 = require("./load-bindings");
|
|
10
|
+
const win32_sn_parser_1 = require("./win32-sn-parser");
|
|
11
|
+
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
|
12
|
+
exports.WindowsBinding = {
|
|
13
|
+
async list() {
|
|
14
|
+
const ports = await (0, load_bindings_1.asyncList)();
|
|
15
|
+
// Grab the serial number from the pnp id
|
|
16
|
+
return ports.map(port => {
|
|
17
|
+
if (port.pnpId && !port.serialNumber) {
|
|
18
|
+
const serialNumber = (0, win32_sn_parser_1.serialNumParser)(port.pnpId);
|
|
19
|
+
if (serialNumber) {
|
|
20
|
+
return Object.assign(Object.assign({}, port), { serialNumber });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return port;
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
async open(options) {
|
|
27
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
28
|
+
throw new TypeError('"options" is not an object');
|
|
29
|
+
}
|
|
30
|
+
if (!options.path) {
|
|
31
|
+
throw new TypeError('"path" is not a valid port');
|
|
32
|
+
}
|
|
33
|
+
if (!options.baudRate) {
|
|
34
|
+
throw new TypeError('"baudRate" is not a valid baudRate');
|
|
35
|
+
}
|
|
36
|
+
debug('open');
|
|
37
|
+
const openOptions = Object.assign({ dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, rtsMode: 'handshake', xon: false, xoff: false, xany: false, hupcl: true }, options);
|
|
38
|
+
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
|
39
|
+
return new WindowsPortBinding(fd, openOptions);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The Windows binding layer
|
|
44
|
+
*/
|
|
45
|
+
class WindowsPortBinding {
|
|
46
|
+
constructor(fd, options) {
|
|
47
|
+
this.fd = fd;
|
|
48
|
+
this.openOptions = options;
|
|
49
|
+
this.writeOperation = null;
|
|
50
|
+
}
|
|
51
|
+
get isOpen() {
|
|
52
|
+
return this.fd !== null;
|
|
53
|
+
}
|
|
54
|
+
async close() {
|
|
55
|
+
debug('close');
|
|
56
|
+
if (!this.isOpen) {
|
|
57
|
+
throw new Error('Port is not open');
|
|
58
|
+
}
|
|
59
|
+
const fd = this.fd;
|
|
60
|
+
this.fd = null;
|
|
61
|
+
await (0, load_bindings_1.asyncClose)(fd);
|
|
62
|
+
}
|
|
63
|
+
async read(buffer, offset, length) {
|
|
64
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
65
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
66
|
+
}
|
|
67
|
+
if (typeof offset !== 'number' || isNaN(offset)) {
|
|
68
|
+
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
|
69
|
+
}
|
|
70
|
+
if (typeof length !== 'number' || isNaN(length)) {
|
|
71
|
+
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
|
72
|
+
}
|
|
73
|
+
debug('read');
|
|
74
|
+
if (buffer.length < offset + length) {
|
|
75
|
+
throw new Error('buffer is too small');
|
|
76
|
+
}
|
|
77
|
+
if (!this.isOpen) {
|
|
78
|
+
throw new Error('Port is not open');
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const bytesRead = await (0, load_bindings_1.asyncRead)(this.fd, buffer, offset, length);
|
|
82
|
+
return { bytesRead, buffer };
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (!this.isOpen) {
|
|
86
|
+
throw new _1.BindingsError(err.message, { canceled: true });
|
|
87
|
+
}
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async write(buffer) {
|
|
92
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
93
|
+
throw new TypeError('"buffer" is not a Buffer');
|
|
94
|
+
}
|
|
95
|
+
debug('write', buffer.length, 'bytes');
|
|
96
|
+
if (!this.isOpen) {
|
|
97
|
+
debug('write', 'error port is not open');
|
|
98
|
+
throw new Error('Port is not open');
|
|
99
|
+
}
|
|
100
|
+
this.writeOperation = (async () => {
|
|
101
|
+
if (buffer.length === 0) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
await (0, load_bindings_1.asyncWrite)(this.fd, buffer);
|
|
105
|
+
this.writeOperation = null;
|
|
106
|
+
})();
|
|
107
|
+
return this.writeOperation;
|
|
108
|
+
}
|
|
109
|
+
async update(options) {
|
|
110
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
111
|
+
throw TypeError('"options" is not an object');
|
|
112
|
+
}
|
|
113
|
+
if (typeof options.baudRate !== 'number') {
|
|
114
|
+
throw new TypeError('"options.baudRate" is not a number');
|
|
115
|
+
}
|
|
116
|
+
debug('update');
|
|
117
|
+
if (!this.isOpen) {
|
|
118
|
+
throw new Error('Port is not open');
|
|
119
|
+
}
|
|
120
|
+
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
|
121
|
+
}
|
|
122
|
+
async set(options) {
|
|
123
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
124
|
+
throw new TypeError('"options" is not an object');
|
|
125
|
+
}
|
|
126
|
+
debug('set', options);
|
|
127
|
+
if (!this.isOpen) {
|
|
128
|
+
throw new Error('Port is not open');
|
|
129
|
+
}
|
|
130
|
+
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
|
131
|
+
}
|
|
132
|
+
async get() {
|
|
133
|
+
debug('get');
|
|
134
|
+
if (!this.isOpen) {
|
|
135
|
+
throw new Error('Port is not open');
|
|
136
|
+
}
|
|
137
|
+
return (0, load_bindings_1.asyncGet)(this.fd);
|
|
138
|
+
}
|
|
139
|
+
async getBaudRate() {
|
|
140
|
+
debug('getBaudRate');
|
|
141
|
+
if (!this.isOpen) {
|
|
142
|
+
throw new Error('Port is not open');
|
|
143
|
+
}
|
|
144
|
+
return (0, load_bindings_1.asyncGetBaudRate)(this.fd);
|
|
145
|
+
}
|
|
146
|
+
async flush() {
|
|
147
|
+
debug('flush');
|
|
148
|
+
if (!this.isOpen) {
|
|
149
|
+
throw new Error('Port is not open');
|
|
150
|
+
}
|
|
151
|
+
await (0, load_bindings_1.asyncFlush)(this.fd);
|
|
152
|
+
}
|
|
153
|
+
async drain() {
|
|
154
|
+
debug('drain');
|
|
155
|
+
if (!this.isOpen) {
|
|
156
|
+
throw new Error('Port is not open');
|
|
157
|
+
}
|
|
158
|
+
await this.writeOperation;
|
|
159
|
+
await (0, load_bindings_1.asyncDrain)(this.fd);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
exports.WindowsPortBinding = WindowsPortBinding;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jason2866/serialport-bindings-cpp",
|
|
3
3
|
"description": "SerialPort Hardware bindings for node serialport written in c++",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "13.0.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"keywords": [
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
},
|
|
92
92
|
"repository": {
|
|
93
93
|
"type": "git",
|
|
94
|
-
"url": "
|
|
94
|
+
"url": "https://github.com/Jason2866/bindings-cpp"
|
|
95
95
|
},
|
|
96
96
|
"funding": "https://opencollective.com/serialport/donate",
|
|
97
97
|
"changelog": {
|
|
Binary file
|
|
Binary file
|
package/src/serialport_win.cpp
CHANGED
|
@@ -918,9 +918,15 @@ void ListBaton::Execute() {
|
|
|
918
918
|
}
|
|
919
919
|
if (isCom) {
|
|
920
920
|
ListResultItem* resultItem = new ListResultItem();
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
921
|
+
if (name) {
|
|
922
|
+
resultItem->path = name;
|
|
923
|
+
}
|
|
924
|
+
if (manufacturer) {
|
|
925
|
+
resultItem->manufacturer = manufacturer;
|
|
926
|
+
}
|
|
927
|
+
if (pnpId) {
|
|
928
|
+
resultItem->pnpId = pnpId;
|
|
929
|
+
}
|
|
924
930
|
if (vendorId) {
|
|
925
931
|
resultItem->vendorId = vendorId;
|
|
926
932
|
}
|
|
@@ -943,7 +949,9 @@ void ListBaton::Execute() {
|
|
|
943
949
|
free(manufacturer);
|
|
944
950
|
free(name);
|
|
945
951
|
|
|
946
|
-
|
|
952
|
+
if (hkey != INVALID_HANDLE_VALUE) {
|
|
953
|
+
RegCloseKey(hkey);
|
|
954
|
+
}
|
|
947
955
|
memberIndex++;
|
|
948
956
|
}
|
|
949
957
|
if (hDevInfo) {
|