node-ch347 0.0.1

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/uart.js ADDED
@@ -0,0 +1,343 @@
1
+ "use strict";
2
+ /**
3
+ * CH347 UART Interface
4
+ *
5
+ * The CH347 UART interface appears as a virtual COM port (CDC ACM).
6
+ * On Linux/macOS, it typically shows up as /dev/ttyACM0 or /dev/tty.usbmodem*
7
+ *
8
+ * This module provides a cross-platform wrapper around the serial port.
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.CH347UART = void 0;
45
+ const events_1 = require("events");
46
+ const constants_1 = require("./constants");
47
+ // We'll use the native serialport package for UART
48
+ // Since it requires native bindings, we'll make it optional
49
+ let SerialPort = null;
50
+ try {
51
+ // Dynamic import to avoid hard dependency
52
+ SerialPort = require('serialport').SerialPort;
53
+ }
54
+ catch {
55
+ // SerialPort not available
56
+ }
57
+ const DEFAULT_UART_CONFIG = {
58
+ baudRate: constants_1.CH347_UART_DEFAULT_BAUD,
59
+ dataBits: 8,
60
+ stopBits: 1,
61
+ parity: 'none',
62
+ flowControl: 'none',
63
+ };
64
+ class CH347UART extends events_1.EventEmitter {
65
+ config;
66
+ port = null;
67
+ portPath = null;
68
+ isOpen = false;
69
+ constructor(config) {
70
+ super();
71
+ this.config = { ...DEFAULT_UART_CONFIG, ...config };
72
+ }
73
+ /**
74
+ * List available serial ports that might be CH347 UART
75
+ * Returns array of tty paths (e.g., '/dev/ttyACM0')
76
+ */
77
+ static async listPorts() {
78
+ if (!SerialPort) {
79
+ throw new Error('serialport package not installed. Install with: npm install serialport');
80
+ }
81
+ const { SerialPort: SP } = await Promise.resolve().then(() => __importStar(require('serialport')));
82
+ const ports = await SP.list();
83
+ // Filter for potential CH347 devices
84
+ // CH347 uses VID 1a86, PID 55db/55dd
85
+ return ports
86
+ .filter((port) => {
87
+ // Include all ports but prioritize CH347 devices
88
+ const vid = port.vendorId?.toLowerCase();
89
+ return vid === '1a86' || port.path.includes('ttyACM') || port.path.includes('usbmodem');
90
+ })
91
+ .map((port) => port.path);
92
+ }
93
+ /**
94
+ * Open UART port
95
+ */
96
+ async open(portPath, config) {
97
+ if (!SerialPort) {
98
+ throw new Error('serialport package not installed. Install with: npm install serialport');
99
+ }
100
+ if (this.isOpen) {
101
+ await this.close();
102
+ }
103
+ if (config) {
104
+ this.config = { ...this.config, ...config };
105
+ }
106
+ this.portPath = portPath;
107
+ return new Promise((resolve, reject) => {
108
+ this.port = new SerialPort({
109
+ path: portPath,
110
+ baudRate: this.config.baudRate,
111
+ dataBits: this.config.dataBits,
112
+ stopBits: this.config.stopBits,
113
+ parity: this.config.parity,
114
+ rtscts: this.config.flowControl === 'hardware',
115
+ autoOpen: false,
116
+ });
117
+ this.port.on('data', (data) => {
118
+ this.emit('data', data);
119
+ });
120
+ this.port.on('error', (err) => {
121
+ this.emit('error', err);
122
+ });
123
+ this.port.on('close', () => {
124
+ this.isOpen = false;
125
+ this.emit('close');
126
+ });
127
+ this.port.open((err) => {
128
+ if (err) {
129
+ reject(new Error(`Failed to open port: ${err.message}`));
130
+ }
131
+ else {
132
+ this.isOpen = true;
133
+ this.emit('open');
134
+ resolve();
135
+ }
136
+ });
137
+ });
138
+ }
139
+ /**
140
+ * Close UART port
141
+ */
142
+ async close() {
143
+ if (!this.port || !this.isOpen) {
144
+ return;
145
+ }
146
+ return new Promise((resolve, reject) => {
147
+ this.port.close((err) => {
148
+ if (err) {
149
+ reject(new Error(`Failed to close port: ${err.message}`));
150
+ }
151
+ else {
152
+ this.isOpen = false;
153
+ this.port = null;
154
+ resolve();
155
+ }
156
+ });
157
+ });
158
+ }
159
+ /**
160
+ * Write data to UART
161
+ */
162
+ async write(data) {
163
+ if (!this.port || !this.isOpen) {
164
+ throw new Error('Port not open');
165
+ }
166
+ const buffer = typeof data === 'string' ? Buffer.from(data) : data;
167
+ return new Promise((resolve, reject) => {
168
+ this.port.write(buffer, (err) => {
169
+ if (err) {
170
+ reject(new Error(`Failed to write: ${err.message}`));
171
+ }
172
+ else {
173
+ this.port.drain((drainErr) => {
174
+ if (drainErr) {
175
+ reject(new Error(`Failed to drain: ${drainErr.message}`));
176
+ }
177
+ else {
178
+ resolve();
179
+ }
180
+ });
181
+ }
182
+ });
183
+ });
184
+ }
185
+ /**
186
+ * Read data from UART (with timeout)
187
+ */
188
+ async read(length, timeoutMs = 1000) {
189
+ if (!this.port || !this.isOpen) {
190
+ throw new Error('Port not open');
191
+ }
192
+ const chunks = [];
193
+ let totalRead = 0;
194
+ return new Promise((resolve, reject) => {
195
+ const timeoutId = setTimeout(() => {
196
+ cleanup();
197
+ resolve(Buffer.concat(chunks));
198
+ }, timeoutMs);
199
+ const onData = (data) => {
200
+ chunks.push(data);
201
+ totalRead += data.length;
202
+ if (totalRead >= length) {
203
+ cleanup();
204
+ resolve(Buffer.concat(chunks).subarray(0, length));
205
+ }
206
+ };
207
+ const cleanup = () => {
208
+ clearTimeout(timeoutId);
209
+ this.port.off('data', onData);
210
+ };
211
+ this.port.on('data', onData);
212
+ });
213
+ }
214
+ /**
215
+ * Read line (until newline)
216
+ */
217
+ async readLine(timeoutMs = 1000) {
218
+ if (!this.port || !this.isOpen) {
219
+ throw new Error('Port not open');
220
+ }
221
+ const chunks = [];
222
+ return new Promise((resolve) => {
223
+ const timeoutId = setTimeout(() => {
224
+ cleanup();
225
+ resolve(Buffer.concat(chunks).toString('utf8'));
226
+ }, timeoutMs);
227
+ const onData = (data) => {
228
+ chunks.push(data);
229
+ const str = Buffer.concat(chunks).toString('utf8');
230
+ const newlineIndex = str.indexOf('\n');
231
+ if (newlineIndex !== -1) {
232
+ cleanup();
233
+ resolve(str.substring(0, newlineIndex + 1));
234
+ }
235
+ };
236
+ const cleanup = () => {
237
+ clearTimeout(timeoutId);
238
+ this.port.off('data', onData);
239
+ };
240
+ this.port.on('data', onData);
241
+ });
242
+ }
243
+ /**
244
+ * Write and wait for response
245
+ */
246
+ async writeRead(data, responseLength, timeoutMs = 1000) {
247
+ await this.write(data);
248
+ return this.read(responseLength, timeoutMs);
249
+ }
250
+ /**
251
+ * Set baud rate
252
+ */
253
+ async setBaudRate(baudRate) {
254
+ if (!this.port || !this.isOpen) {
255
+ throw new Error('Port not open');
256
+ }
257
+ return new Promise((resolve, reject) => {
258
+ this.port.update({ baudRate }, (err) => {
259
+ if (err) {
260
+ reject(new Error(`Failed to set baud rate: ${err.message}`));
261
+ }
262
+ else {
263
+ this.config.baudRate = baudRate;
264
+ resolve();
265
+ }
266
+ });
267
+ });
268
+ }
269
+ /**
270
+ * Flush input/output buffers
271
+ */
272
+ async flush() {
273
+ if (!this.port || !this.isOpen) {
274
+ throw new Error('Port not open');
275
+ }
276
+ return new Promise((resolve, reject) => {
277
+ this.port.flush((err) => {
278
+ if (err) {
279
+ reject(new Error(`Failed to flush: ${err.message}`));
280
+ }
281
+ else {
282
+ resolve();
283
+ }
284
+ });
285
+ });
286
+ }
287
+ /**
288
+ * Set DTR signal
289
+ */
290
+ async setDTR(value) {
291
+ if (!this.port || !this.isOpen) {
292
+ throw new Error('Port not open');
293
+ }
294
+ return new Promise((resolve, reject) => {
295
+ this.port.set({ dtr: value }, (err) => {
296
+ if (err) {
297
+ reject(new Error(`Failed to set DTR: ${err.message}`));
298
+ }
299
+ else {
300
+ resolve();
301
+ }
302
+ });
303
+ });
304
+ }
305
+ /**
306
+ * Set RTS signal
307
+ */
308
+ async setRTS(value) {
309
+ if (!this.port || !this.isOpen) {
310
+ throw new Error('Port not open');
311
+ }
312
+ return new Promise((resolve, reject) => {
313
+ this.port.set({ rts: value }, (err) => {
314
+ if (err) {
315
+ reject(new Error(`Failed to set RTS: ${err.message}`));
316
+ }
317
+ else {
318
+ resolve();
319
+ }
320
+ });
321
+ });
322
+ }
323
+ /**
324
+ * Check if port is open
325
+ */
326
+ isConnected() {
327
+ return this.isOpen;
328
+ }
329
+ /**
330
+ * Get current port path
331
+ */
332
+ getPortPath() {
333
+ return this.portPath;
334
+ }
335
+ /**
336
+ * Get current configuration
337
+ */
338
+ getConfig() {
339
+ return { ...this.config };
340
+ }
341
+ }
342
+ exports.CH347UART = CH347UART;
343
+ //# sourceMappingURL=uart.js.map
package/dist/usb.d.ts ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * CH347 USB Communication Layer
3
+ */
4
+ import * as usb from 'usb';
5
+ import { CH347DeviceInfo } from './types';
6
+ export declare class CH347USB {
7
+ private device;
8
+ private interface;
9
+ private epIn;
10
+ private epOut;
11
+ private isOpen;
12
+ /**
13
+ * Get the underlying USB device (for advanced operations)
14
+ */
15
+ getDevice(): usb.Device | null;
16
+ /**
17
+ * List all connected CH347 devices
18
+ */
19
+ static listDevices(): CH347DeviceInfo[];
20
+ /**
21
+ * Open connection to CH347 device
22
+ */
23
+ open(deviceIndex?: number): Promise<void>;
24
+ /**
25
+ * Close connection
26
+ */
27
+ close(): void;
28
+ /**
29
+ * Check if device is open
30
+ */
31
+ isConnected(): boolean;
32
+ /**
33
+ * Send data to device
34
+ */
35
+ write(data: Buffer): Promise<number>;
36
+ /**
37
+ * Read data from device
38
+ */
39
+ read(length?: number, timeout?: number): Promise<Buffer>;
40
+ /**
41
+ * Write and then read response
42
+ */
43
+ transfer(outData: Buffer, readLength?: number): Promise<Buffer>;
44
+ /**
45
+ * Bulk write for large data transfers
46
+ */
47
+ bulkWrite(data: Buffer, chunkSize?: number): Promise<void>;
48
+ /**
49
+ * Bulk read for large data transfers
50
+ */
51
+ bulkRead(totalLength: number, chunkSize?: number): Promise<Buffer>;
52
+ /**
53
+ * USB control transfer (for vendor-specific commands)
54
+ */
55
+ controlTransfer(bmRequestType: number, bRequest: number, wValue: number, wIndex: number, dataOrLength: Buffer | number): Promise<Buffer | number>;
56
+ /**
57
+ * Get USB string descriptor
58
+ */
59
+ getStringDescriptor(index: number): Promise<string>;
60
+ /**
61
+ * Get device descriptor info including serial number index
62
+ */
63
+ getDeviceDescriptor(): usb.DeviceDescriptor | null;
64
+ /**
65
+ * Get the UART tty path for this CH347 device
66
+ * On Linux: scans /sys/class/tty for matching USB device
67
+ * On macOS: scans /dev for matching usbmodem device
68
+ */
69
+ getUARTPath(): string | null;
70
+ /**
71
+ * Find TTY device on Linux by scanning sysfs
72
+ */
73
+ private findLinuxTTY;
74
+ /**
75
+ * Find TTY device on macOS
76
+ * macOS names CDC ACM devices as /dev/tty.usbmodem* with location ID
77
+ */
78
+ private findMacOSTTY;
79
+ }
80
+ //# sourceMappingURL=usb.d.ts.map