@technoculture/data-bridge 0.1.1 → 0.1.2
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/CMakeLists.txt +10 -2
- package/deps/include/data_bridge/config.hpp +69 -0
- package/deps/include/data_bridge/protocol/crc16.hpp +8 -0
- package/deps/include/data_bridge/protocol/crc32.hpp +19 -0
- package/deps/include/data_bridge/protocol/packet.hpp +175 -0
- package/deps/include/data_bridge/protocol/reassembler.hpp +80 -0
- package/deps/include/data_bridge/transport/factory.hpp +0 -0
- package/deps/include/data_bridge/transport/iserial_port.hpp +15 -0
- package/deps/include/data_bridge/transport/serial_port.hpp +28 -0
- package/deps/src/CMakeLists.txt +18 -0
- package/deps/src/protocol/crc16.cpp +19 -0
- package/deps/src/protocol/packet.cpp +1 -0
- package/deps/src/transport/platform/linux/linux_serial.cpp +53 -0
- package/deps/src/transport/platform/windows/windows_serial.cpp +51 -0
- package/dist/index.d.mts +41 -72
- package/dist/index.d.ts +41 -72
- package/dist/index.js +196 -102
- package/dist/index.mjs +194 -103
- package/lib/index.ts +12 -160
- package/lib/native.ts +71 -0
- package/lib/reliable.ts +234 -0
- package/lib/resilient.ts +30 -6
- package/package.json +6 -4
- package/prebuilds/darwin-arm64/Release/data_bridge_node.node +0 -0
- package/src/addon.cpp +248 -137
- package/prebuilds/darwin-arm64/.ninja_deps +0 -0
- package/prebuilds/darwin-arm64/.ninja_log +0 -6
- package/prebuilds/darwin-arm64/CMakeCache.txt +0 -398
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeCCompiler.cmake +0 -84
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeCXXCompiler.cmake +0 -104
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeDetermineCompilerABI_C.bin +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeSystem.cmake +0 -15
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/CMakeCCompilerId.c +0 -905
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/a.out +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/apple-sdk.c +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -920
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/a.out +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/apple-sdk.cpp +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/CMakeConfigureLog.yaml +0 -531
- package/prebuilds/darwin-arm64/CMakeFiles/InstallScripts.json +0 -7
- package/prebuilds/darwin-arm64/CMakeFiles/TargetDirectories.txt +0 -3
- package/prebuilds/darwin-arm64/CMakeFiles/cmake.check_cache +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/protocol/crc16.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/transport/platform/linux/linux_serial.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/src/addon.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/src/serial_wrapper.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/rules.ninja +0 -64
- package/prebuilds/darwin-arm64/build.ninja +0 -192
- package/prebuilds/darwin-arm64/cmake_install.cmake +0 -61
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
|
|
3
|
+
interface DataBridgeOptions {
|
|
4
|
+
baudRate?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
ackTimeoutMs?: number;
|
|
7
|
+
fragmentSize?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* ReliableDataBridge
|
|
11
|
+
*
|
|
12
|
+
* Implements Stop-and-Wait ARQ with fragmentation/reassembly.
|
|
13
|
+
* Mirrors the Python bindings.wrapper.DataBridge logic.
|
|
14
|
+
*/
|
|
15
|
+
declare class ReliableDataBridge extends EventEmitter {
|
|
16
|
+
private serial;
|
|
17
|
+
private reassembler;
|
|
18
|
+
private isOpen_;
|
|
19
|
+
private options;
|
|
20
|
+
private seqId;
|
|
21
|
+
private rxBuffer;
|
|
22
|
+
private pendingAcks;
|
|
23
|
+
constructor(options?: DataBridgeOptions);
|
|
24
|
+
static open(port: string, baudOrOptions?: number | DataBridgeOptions, cb?: (data: Buffer) => void): Promise<ReliableDataBridge>;
|
|
25
|
+
open(port: string, baud?: number): Promise<boolean>;
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
get isOpen(): boolean;
|
|
28
|
+
send(data: string | Buffer): Promise<void>;
|
|
29
|
+
private sendWithRetry;
|
|
30
|
+
private onData;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface SerialPort {
|
|
34
|
+
open(port: string, baud: number, callback: (data: Buffer) => void): boolean;
|
|
35
|
+
write(data: Buffer): number;
|
|
36
|
+
close(): boolean;
|
|
37
|
+
isOpen(): boolean;
|
|
38
|
+
}
|
|
39
|
+
declare const SerialPort: {
|
|
40
|
+
new (): SerialPort;
|
|
41
|
+
};
|
|
42
|
+
|
|
3
43
|
/**
|
|
4
44
|
* ResilientDataBridge - Connection-resilient wrapper
|
|
5
45
|
*
|
|
@@ -74,75 +114,4 @@ declare class ResilientDataBridge extends EventEmitter {
|
|
|
74
114
|
emit<K extends keyof ResilientEvents>(event: K, ...args: Parameters<ResilientEvents[K]>): boolean;
|
|
75
115
|
}
|
|
76
116
|
|
|
77
|
-
|
|
78
|
-
* Data Bridge - Guaranteed Reliable Serial Communication
|
|
79
|
-
*
|
|
80
|
-
* TypeScript wrapper for the native Node-API addon.
|
|
81
|
-
* Provides a clean, async-friendly API for Electron applications.
|
|
82
|
-
*/
|
|
83
|
-
|
|
84
|
-
interface DataBridgeOptions {
|
|
85
|
-
baudRate?: number;
|
|
86
|
-
}
|
|
87
|
-
interface DataBridgeEvents {
|
|
88
|
-
data: (data: Buffer) => void;
|
|
89
|
-
error: (error: Error) => void;
|
|
90
|
-
close: () => void;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* DataBridge provides guaranteed reliable serial communication.
|
|
94
|
-
*
|
|
95
|
-
* Features:
|
|
96
|
-
* - Automatic retransmission on packet loss
|
|
97
|
-
* - CRC32 integrity checking
|
|
98
|
-
* - COBS framing for robust delimitation
|
|
99
|
-
* - Fragmentation for large messages
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```typescript
|
|
103
|
-
* const bridge = await DataBridge.open('/dev/ttyUSB0');
|
|
104
|
-
*
|
|
105
|
-
* bridge.on('data', (data) => {
|
|
106
|
-
* console.log('Received:', data.toString());
|
|
107
|
-
* });
|
|
108
|
-
*
|
|
109
|
-
* await bridge.send('Hello, World!');
|
|
110
|
-
* await bridge.close();
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
declare class DataBridge extends EventEmitter {
|
|
114
|
-
private native;
|
|
115
|
-
private _isOpen;
|
|
116
|
-
private constructor();
|
|
117
|
-
/**
|
|
118
|
-
* Open a serial port with guaranteed reliable communication.
|
|
119
|
-
*
|
|
120
|
-
* @param port - Serial port path (e.g., '/dev/ttyUSB0' or 'COM3')
|
|
121
|
-
* @param options - Configuration options
|
|
122
|
-
* @returns Promise resolving to a DataBridge instance
|
|
123
|
-
*/
|
|
124
|
-
static open(port: string, options?: DataBridgeOptions): Promise<DataBridge>;
|
|
125
|
-
/**
|
|
126
|
-
* Send data with guaranteed delivery.
|
|
127
|
-
*
|
|
128
|
-
* The data will be fragmented if necessary, checksummed, and
|
|
129
|
-
* retransmitted until acknowledged by the receiver.
|
|
130
|
-
*
|
|
131
|
-
* @param data - Data to send (Buffer or string)
|
|
132
|
-
* @returns Promise resolving when data is acknowledged
|
|
133
|
-
*/
|
|
134
|
-
send(data: Buffer | string): Promise<void>;
|
|
135
|
-
/**
|
|
136
|
-
* Close the serial port.
|
|
137
|
-
*/
|
|
138
|
-
close(): Promise<void>;
|
|
139
|
-
/**
|
|
140
|
-
* Check if the port is currently open.
|
|
141
|
-
*/
|
|
142
|
-
get isOpen(): boolean;
|
|
143
|
-
on<K extends keyof DataBridgeEvents>(event: K, listener: DataBridgeEvents[K]): this;
|
|
144
|
-
once<K extends keyof DataBridgeEvents>(event: K, listener: DataBridgeEvents[K]): this;
|
|
145
|
-
emit<K extends keyof DataBridgeEvents>(event: K, ...args: Parameters<DataBridgeEvents[K]>): boolean;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export { DataBridge, type DataBridgeEvents, type DataBridgeOptions, ResilientDataBridge, type ResilientEvents, type ResilientOptions, DataBridge as default };
|
|
117
|
+
export { ReliableDataBridge as DataBridge, type DataBridgeOptions, SerialPort as RawSerialPort, ResilientDataBridge, type ResilientEvents, type ResilientOptions };
|
package/dist/index.js
CHANGED
|
@@ -30,17 +30,194 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// lib/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
DataBridge: () =>
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
DataBridge: () => ReliableDataBridge,
|
|
34
|
+
RawSerialPort: () => SerialPort,
|
|
35
|
+
ResilientDataBridge: () => ResilientDataBridge
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
// lib/reliable.ts
|
|
40
|
+
var import_events = require("events");
|
|
41
|
+
|
|
42
|
+
// lib/native.ts
|
|
39
43
|
var import_path = __toESM(require("path"));
|
|
44
|
+
function loadAddon() {
|
|
45
|
+
const possiblePaths = [
|
|
46
|
+
`../prebuilds/${process.platform}-${process.arch}/data_bridge_node.node`,
|
|
47
|
+
"../build/Release/data_bridge_node.node"
|
|
48
|
+
];
|
|
49
|
+
for (const p of possiblePaths) {
|
|
50
|
+
try {
|
|
51
|
+
return require(import_path.default.join(__dirname, p));
|
|
52
|
+
} catch {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new Error("Failed to load native addon. Run `npm run build` first.");
|
|
57
|
+
}
|
|
58
|
+
var addon = loadAddon();
|
|
59
|
+
var SerialPort = addon.SerialPort;
|
|
60
|
+
var Packet = addon.Packet;
|
|
61
|
+
var Reassembler = addon.Reassembler;
|
|
62
|
+
|
|
63
|
+
// lib/reliable.ts
|
|
64
|
+
var ReliableDataBridge = class _ReliableDataBridge extends import_events.EventEmitter {
|
|
65
|
+
serial;
|
|
66
|
+
reassembler;
|
|
67
|
+
isOpen_ = false;
|
|
68
|
+
// Config
|
|
69
|
+
options;
|
|
70
|
+
// State
|
|
71
|
+
seqId = 0;
|
|
72
|
+
rxBuffer = Buffer.alloc(0);
|
|
73
|
+
// ARQ State
|
|
74
|
+
// We only process one send at a time (Stop-and-Wait)
|
|
75
|
+
// Map of seqId -> { resolve, reject } (though we only have one really)
|
|
76
|
+
pendingAcks = /* @__PURE__ */ new Map();
|
|
77
|
+
constructor(options = {}) {
|
|
78
|
+
super();
|
|
79
|
+
this.serial = new SerialPort();
|
|
80
|
+
this.reassembler = new Reassembler();
|
|
81
|
+
this.options = {
|
|
82
|
+
baudRate: options.baudRate ?? 115200,
|
|
83
|
+
maxRetries: options.maxRetries ?? 10,
|
|
84
|
+
ackTimeoutMs: options.ackTimeoutMs ?? 500,
|
|
85
|
+
fragmentSize: options.fragmentSize ?? 200
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
static async open(port, baudOrOptions, cb) {
|
|
89
|
+
let opts = {};
|
|
90
|
+
if (typeof baudOrOptions === "number") {
|
|
91
|
+
opts.baudRate = baudOrOptions;
|
|
92
|
+
} else if (baudOrOptions) {
|
|
93
|
+
opts = baudOrOptions;
|
|
94
|
+
}
|
|
95
|
+
const bridge = new _ReliableDataBridge(opts);
|
|
96
|
+
if (cb) bridge.on("data", cb);
|
|
97
|
+
await bridge.open(port);
|
|
98
|
+
return bridge;
|
|
99
|
+
}
|
|
100
|
+
async open(port, baud) {
|
|
101
|
+
if (this.isOpen_) return true;
|
|
102
|
+
const baudRate = baud ?? this.options.baudRate;
|
|
103
|
+
const success = this.serial.open(port, baudRate, (data) => {
|
|
104
|
+
this.onData(data);
|
|
105
|
+
});
|
|
106
|
+
if (success) {
|
|
107
|
+
this.isOpen_ = true;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Failed to open ${port}`);
|
|
111
|
+
}
|
|
112
|
+
async close() {
|
|
113
|
+
if (this.isOpen_) {
|
|
114
|
+
this.serial.close();
|
|
115
|
+
this.isOpen_ = false;
|
|
116
|
+
this.emit("close");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
get isOpen() {
|
|
120
|
+
return this.isOpen_;
|
|
121
|
+
}
|
|
122
|
+
async send(data) {
|
|
123
|
+
if (!this.isOpen_) throw new Error("Port not open");
|
|
124
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
125
|
+
const fragments = [];
|
|
126
|
+
for (let i = 0; i < buf.length; i += this.options.fragmentSize) {
|
|
127
|
+
fragments.push(buf.subarray(i, i + this.options.fragmentSize));
|
|
128
|
+
}
|
|
129
|
+
const totalFrags = fragments.length;
|
|
130
|
+
const seq = this.seqId;
|
|
131
|
+
this.seqId = (this.seqId + 1) % 256;
|
|
132
|
+
for (let fragId = 0; fragId < totalFrags; fragId++) {
|
|
133
|
+
const payload = fragments[fragId];
|
|
134
|
+
const packet = Packet.serialize(
|
|
135
|
+
Packet.TYPE_DATA,
|
|
136
|
+
seq,
|
|
137
|
+
payload,
|
|
138
|
+
fragId,
|
|
139
|
+
totalFrags
|
|
140
|
+
);
|
|
141
|
+
await this.sendWithRetry(packet, seq, fragId);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async sendWithRetry(packet, seq, fragId) {
|
|
145
|
+
let retries = 0;
|
|
146
|
+
while (retries <= this.options.maxRetries) {
|
|
147
|
+
const ackPromise = new Promise((resolve, reject) => {
|
|
148
|
+
const handler = (ackedFragId) => {
|
|
149
|
+
if (ackedFragId === fragId) resolve();
|
|
150
|
+
};
|
|
151
|
+
this.pendingAcks.set(seq, handler);
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
if (this.pendingAcks.has(seq)) {
|
|
154
|
+
this.pendingAcks.delete(seq);
|
|
155
|
+
reject(new Error("Timeout"));
|
|
156
|
+
}
|
|
157
|
+
}, this.options.ackTimeoutMs);
|
|
158
|
+
});
|
|
159
|
+
this.serial.write(packet);
|
|
160
|
+
try {
|
|
161
|
+
await ackPromise;
|
|
162
|
+
return;
|
|
163
|
+
} catch (e) {
|
|
164
|
+
retries++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`Send failed after ${this.options.maxRetries} retries`);
|
|
168
|
+
}
|
|
169
|
+
onData(chunk) {
|
|
170
|
+
this.rxBuffer = Buffer.concat([this.rxBuffer, chunk]);
|
|
171
|
+
while (true) {
|
|
172
|
+
const { frame, remaining } = Packet.deserialize(this.rxBuffer);
|
|
173
|
+
if (!frame.valid) {
|
|
174
|
+
if (remaining.length === this.rxBuffer.length) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
this.rxBuffer = Buffer.from(remaining);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
this.rxBuffer = Buffer.from(remaining);
|
|
181
|
+
if (frame.header.type === Packet.TYPE_ACK) {
|
|
182
|
+
const seq = frame.header.seq_id;
|
|
183
|
+
const frag = frame.header.fragment_id;
|
|
184
|
+
if (this.pendingAcks.has(seq)) {
|
|
185
|
+
this.pendingAcks.get(seq)(frag);
|
|
186
|
+
}
|
|
187
|
+
} else if (frame.header.type === Packet.TYPE_DATA) {
|
|
188
|
+
let shouldAck = false;
|
|
189
|
+
if (this.reassembler.processFragment(frame)) {
|
|
190
|
+
shouldAck = true;
|
|
191
|
+
if (this.reassembler.isComplete(frame)) {
|
|
192
|
+
try {
|
|
193
|
+
const data = this.reassembler.getData();
|
|
194
|
+
this.emit("data", data);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.error("Error in data emission:", e);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} else if (this.reassembler.isDuplicate(frame)) {
|
|
200
|
+
shouldAck = true;
|
|
201
|
+
}
|
|
202
|
+
if (shouldAck) {
|
|
203
|
+
const ackParams = Packet.serialize(
|
|
204
|
+
Packet.TYPE_ACK,
|
|
205
|
+
frame.header.seq_id,
|
|
206
|
+
Buffer.alloc(0),
|
|
207
|
+
frame.header.fragment_id,
|
|
208
|
+
frame.header.total_frags
|
|
209
|
+
);
|
|
210
|
+
this.serial.write(ackParams);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
40
216
|
|
|
41
217
|
// lib/resilient.ts
|
|
42
|
-
var
|
|
43
|
-
var ResilientDataBridge = class _ResilientDataBridge extends
|
|
218
|
+
var import_events2 = require("events");
|
|
219
|
+
var ResilientDataBridge = class _ResilientDataBridge extends import_events2.EventEmitter {
|
|
220
|
+
// Use DataBridge type from index (which is reliable now)
|
|
44
221
|
bridge = null;
|
|
45
222
|
port;
|
|
46
223
|
options;
|
|
@@ -55,6 +232,9 @@ var ResilientDataBridge = class _ResilientDataBridge extends import_events.Event
|
|
|
55
232
|
this.port = port;
|
|
56
233
|
this.options = {
|
|
57
234
|
baudRate: options.baudRate ?? 115200,
|
|
235
|
+
maxRetries: options.maxRetries ?? 10,
|
|
236
|
+
ackTimeoutMs: options.ackTimeoutMs ?? 500,
|
|
237
|
+
fragmentSize: options.fragmentSize ?? 200,
|
|
58
238
|
reconnect: options.reconnect ?? true,
|
|
59
239
|
reconnectDelay: options.reconnectDelay ?? 1e3,
|
|
60
240
|
maxReconnectDelay: options.maxReconnectDelay ?? 3e4,
|
|
@@ -74,9 +254,8 @@ var ResilientDataBridge = class _ResilientDataBridge extends import_events.Event
|
|
|
74
254
|
}
|
|
75
255
|
async connect() {
|
|
76
256
|
try {
|
|
77
|
-
this.bridge =
|
|
78
|
-
|
|
79
|
-
});
|
|
257
|
+
this.bridge = new ReliableDataBridge(this.options);
|
|
258
|
+
await this.bridge.open(this.port);
|
|
80
259
|
this.isConnected = true;
|
|
81
260
|
this.reconnectAttempt = 0;
|
|
82
261
|
this.bridge.on("data", (data) => {
|
|
@@ -84,6 +263,11 @@ var ResilientDataBridge = class _ResilientDataBridge extends import_events.Event
|
|
|
84
263
|
});
|
|
85
264
|
this.bridge.on("error", (err) => {
|
|
86
265
|
this.emit("error", err);
|
|
266
|
+
if (!this.bridge?.isOpen) {
|
|
267
|
+
this.handleDisconnect();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
this.bridge.on("close", () => {
|
|
87
271
|
this.handleDisconnect();
|
|
88
272
|
});
|
|
89
273
|
if (this.isReconnecting) {
|
|
@@ -139,10 +323,11 @@ var ResilientDataBridge = class _ResilientDataBridge extends import_events.Event
|
|
|
139
323
|
*/
|
|
140
324
|
async send(data) {
|
|
141
325
|
const buffer = typeof data === "string" ? Buffer.from(data) : data;
|
|
142
|
-
if (this.isConnected && this.bridge) {
|
|
326
|
+
if (this.isConnected && this.bridge && this.bridge.isOpen) {
|
|
143
327
|
try {
|
|
144
328
|
await this.bridge.send(buffer);
|
|
145
329
|
} catch (err) {
|
|
330
|
+
this.handleDisconnect();
|
|
146
331
|
return this.queueMessage(buffer);
|
|
147
332
|
}
|
|
148
333
|
} else {
|
|
@@ -215,100 +400,9 @@ var ResilientDataBridge = class _ResilientDataBridge extends import_events.Event
|
|
|
215
400
|
return super.emit(event, ...args);
|
|
216
401
|
}
|
|
217
402
|
};
|
|
218
|
-
|
|
219
|
-
// lib/index.ts
|
|
220
|
-
var addon;
|
|
221
|
-
function loadAddon() {
|
|
222
|
-
const possiblePaths = [
|
|
223
|
-
// Prebuilt binaries
|
|
224
|
-
`../prebuilds/${process.platform}-${process.arch}/data_bridge_node.node`,
|
|
225
|
-
// Local build
|
|
226
|
-
"../build/Release/data_bridge_node.node"
|
|
227
|
-
];
|
|
228
|
-
for (const p of possiblePaths) {
|
|
229
|
-
try {
|
|
230
|
-
return require(import_path.default.join(__dirname, p));
|
|
231
|
-
} catch {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
throw new Error("Failed to load native addon. Run `npm run build` first.");
|
|
236
|
-
}
|
|
237
|
-
addon = loadAddon();
|
|
238
|
-
var DataBridge = class _DataBridge extends import_events2.EventEmitter {
|
|
239
|
-
native;
|
|
240
|
-
_isOpen = false;
|
|
241
|
-
constructor() {
|
|
242
|
-
super();
|
|
243
|
-
this.native = new addon.DataBridge();
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Open a serial port with guaranteed reliable communication.
|
|
247
|
-
*
|
|
248
|
-
* @param port - Serial port path (e.g., '/dev/ttyUSB0' or 'COM3')
|
|
249
|
-
* @param options - Configuration options
|
|
250
|
-
* @returns Promise resolving to a DataBridge instance
|
|
251
|
-
*/
|
|
252
|
-
static async open(port, options = {}) {
|
|
253
|
-
const instance = new _DataBridge();
|
|
254
|
-
const baud = options.baudRate ?? 115200;
|
|
255
|
-
const onData = (data) => {
|
|
256
|
-
instance.emit("data", data);
|
|
257
|
-
};
|
|
258
|
-
try {
|
|
259
|
-
await instance.native.open(port, baud, onData);
|
|
260
|
-
instance._isOpen = true;
|
|
261
|
-
return instance;
|
|
262
|
-
} catch (err) {
|
|
263
|
-
throw new Error(`Failed to open ${port}: ${err instanceof Error ? err.message : err}`);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Send data with guaranteed delivery.
|
|
268
|
-
*
|
|
269
|
-
* The data will be fragmented if necessary, checksummed, and
|
|
270
|
-
* retransmitted until acknowledged by the receiver.
|
|
271
|
-
*
|
|
272
|
-
* @param data - Data to send (Buffer or string)
|
|
273
|
-
* @returns Promise resolving when data is acknowledged
|
|
274
|
-
*/
|
|
275
|
-
async send(data) {
|
|
276
|
-
if (!this._isOpen) {
|
|
277
|
-
throw new Error("Port not open");
|
|
278
|
-
}
|
|
279
|
-
const buffer = typeof data === "string" ? Buffer.from(data) : data;
|
|
280
|
-
await this.native.send(buffer);
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Close the serial port.
|
|
284
|
-
*/
|
|
285
|
-
async close() {
|
|
286
|
-
if (this._isOpen) {
|
|
287
|
-
this.native.close();
|
|
288
|
-
this._isOpen = false;
|
|
289
|
-
this.emit("close");
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Check if the port is currently open.
|
|
294
|
-
*/
|
|
295
|
-
get isOpen() {
|
|
296
|
-
return this._isOpen && this.native.isOpen();
|
|
297
|
-
}
|
|
298
|
-
// Type-safe event emitter methods
|
|
299
|
-
on(event, listener) {
|
|
300
|
-
return super.on(event, listener);
|
|
301
|
-
}
|
|
302
|
-
once(event, listener) {
|
|
303
|
-
return super.once(event, listener);
|
|
304
|
-
}
|
|
305
|
-
emit(event, ...args) {
|
|
306
|
-
return super.emit(event, ...args);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
var index_default = DataBridge;
|
|
310
403
|
// Annotate the CommonJS export names for ESM import in node:
|
|
311
404
|
0 && (module.exports = {
|
|
312
405
|
DataBridge,
|
|
406
|
+
RawSerialPort,
|
|
313
407
|
ResilientDataBridge
|
|
314
408
|
});
|