tauri-plugin-serialplugin-api 2.18.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.
@@ -0,0 +1,1112 @@
1
+ import { invoke } from '@tauri-apps/api/core';
2
+ import { listen } from '@tauri-apps/api/event';
3
+
4
+ /**
5
+ * Auto-reconnect manager for serial ports
6
+ * Handles automatic reconnection logic with configurable settings
7
+ */
8
+ class AutoReconnectManager {
9
+ constructor() {
10
+ this.enabled = false;
11
+ this.interval = 5000; // 5 seconds default
12
+ this.maxAttempts = 10; // 10 attempts default, null for infinite
13
+ this.currentAttempts = 0;
14
+ this.timer = null;
15
+ }
16
+ /**
17
+ * @description Enables auto-reconnect functionality
18
+ * @param {Object} options Auto-reconnect configuration options
19
+ * @param {number} [options.interval=5000] Reconnection interval in milliseconds
20
+ * @param {number | null} [options.maxAttempts=10] Maximum number of reconnection attempts (null for infinite)
21
+ * @param {Function} [options.onReconnect] Callback function called on each reconnection attempt
22
+ * @param {Function} options.reconnectFunction Function that performs the actual reconnection
23
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect is enabled
24
+ */
25
+ async enable(options) {
26
+ if (this.enabled) {
27
+ console.warn('Auto-reconnect is already enabled');
28
+ return;
29
+ }
30
+ this.enabled = true;
31
+ this.interval = options.interval || 5000;
32
+ this.maxAttempts = options.maxAttempts === undefined ? 10 : options.maxAttempts;
33
+ this.currentAttempts = 0;
34
+ this.callback = options.onReconnect;
35
+ this.reconnectFunction = options.reconnectFunction;
36
+ console.log(`Auto-reconnect enabled: interval=${this.interval}ms, maxAttempts=${this.maxAttempts === null ? 'infinite' : this.maxAttempts}`);
37
+ }
38
+ /**
39
+ * @description Disables auto-reconnect functionality
40
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect is disabled
41
+ */
42
+ async disable() {
43
+ if (!this.enabled) {
44
+ console.warn('Auto-reconnect is not enabled');
45
+ return;
46
+ }
47
+ this.enabled = false;
48
+ this.currentAttempts = 0;
49
+ this.callback = undefined;
50
+ this.reconnectFunction = undefined;
51
+ // Clear any pending reconnect timer
52
+ if (this.timer) {
53
+ clearTimeout(this.timer);
54
+ this.timer = null;
55
+ }
56
+ console.log('Auto-reconnect disabled');
57
+ }
58
+ /**
59
+ * @description Gets auto-reconnect status and configuration
60
+ * @returns {Object} Auto-reconnect information
61
+ */
62
+ getInfo() {
63
+ return {
64
+ enabled: this.enabled,
65
+ interval: this.interval,
66
+ maxAttempts: this.maxAttempts,
67
+ currentAttempts: this.currentAttempts,
68
+ hasCallback: !!this.callback
69
+ };
70
+ }
71
+ /**
72
+ * @description Starts the auto-reconnect process
73
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect process starts
74
+ */
75
+ async start() {
76
+ if (!this.enabled || !this.reconnectFunction) {
77
+ return;
78
+ }
79
+ this.currentAttempts = 0;
80
+ await this.performAttempt();
81
+ }
82
+ /**
83
+ * @description Stops the auto-reconnect process (clears timer but keeps enabled)
84
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect process stops
85
+ */
86
+ async stop() {
87
+ if (this.timer) {
88
+ clearTimeout(this.timer);
89
+ this.timer = null;
90
+ }
91
+ }
92
+ /**
93
+ * @description Resets the attempt counter
94
+ * @returns {Promise<void>} A promise that resolves when counter is reset
95
+ */
96
+ async reset() {
97
+ this.currentAttempts = 0;
98
+ }
99
+ /**
100
+ * @description Internal method to perform a single reconnection attempt
101
+ * @returns {Promise<void>} A promise that resolves when the attempt is complete
102
+ */
103
+ async performAttempt() {
104
+ if (!this.enabled || !this.reconnectFunction) {
105
+ return;
106
+ }
107
+ // Проверяем лимит ДО увеличения счётчика
108
+ if (this.maxAttempts !== null && this.currentAttempts >= this.maxAttempts) {
109
+ console.error(`Auto-reconnect failed after ${this.maxAttempts} attempts`);
110
+ if (this.callback) {
111
+ this.callback(false, this.currentAttempts);
112
+ }
113
+ return;
114
+ }
115
+ this.currentAttempts++;
116
+ console.log(`Auto-reconnect attempt ${this.currentAttempts}${this.maxAttempts !== null ? `/${this.maxAttempts}` : ''}`);
117
+ try {
118
+ const success = await this.reconnectFunction();
119
+ if (success) {
120
+ console.log('Auto-reconnect successful');
121
+ this.currentAttempts = 0; // Reset counter on success
122
+ if (this.callback) {
123
+ this.callback(true, this.currentAttempts);
124
+ }
125
+ }
126
+ else {
127
+ throw new Error('Reconnect function returned false');
128
+ }
129
+ }
130
+ catch (error) {
131
+ console.error(`Auto-reconnect attempt ${this.currentAttempts} failed:`, error);
132
+ if (this.callback) {
133
+ this.callback(false, this.currentAttempts);
134
+ }
135
+ // Schedule next attempt
136
+ if (this.enabled) {
137
+ this.timer = setTimeout(() => {
138
+ this.performAttempt();
139
+ }, this.interval);
140
+ }
141
+ }
142
+ }
143
+ isEnabled() {
144
+ return this.enabled;
145
+ }
146
+ getInterval() {
147
+ return this.interval;
148
+ }
149
+ getMaxAttempts() {
150
+ return this.maxAttempts;
151
+ }
152
+ getCurrentAttempts() {
153
+ return this.currentAttempts;
154
+ }
155
+ hasCallback() {
156
+ return !!this.callback;
157
+ }
158
+ }
159
+
160
+ class ListenerManager {
161
+ constructor() {
162
+ this.listeners = new Map();
163
+ this.listenerIdCounter = 0;
164
+ }
165
+ add(type, unlisten) {
166
+ const id = `${type}_${++this.listenerIdCounter}`;
167
+ this.listeners.set(id, { unlisten, type });
168
+ return () => {
169
+ try {
170
+ this.delete(id);
171
+ if (typeof unlisten === 'function') {
172
+ unlisten();
173
+ }
174
+ }
175
+ catch (error) {
176
+ console.warn(`Error in unlisten function for ${id}:`, error);
177
+ }
178
+ };
179
+ }
180
+ set(id, listener) {
181
+ this.listeners.set(id, listener);
182
+ return () => {
183
+ try {
184
+ this.delete(id);
185
+ if (typeof listener.unlisten === 'function') {
186
+ listener.unlisten();
187
+ }
188
+ }
189
+ catch (error) {
190
+ console.warn(`Error in unlisten function for ${id}:`, error);
191
+ }
192
+ };
193
+ }
194
+ delete(id) {
195
+ this.listeners.delete(id);
196
+ }
197
+ entries() {
198
+ return this.listeners.entries();
199
+ }
200
+ filterByType(type) {
201
+ return Array.from(this.listeners.entries()).filter(([_, l]) => l.type === type);
202
+ }
203
+ all() {
204
+ return Array.from(this.listeners.entries());
205
+ }
206
+ clear() {
207
+ this.listeners.clear();
208
+ }
209
+ getInfo() {
210
+ const all = this.all();
211
+ const data = all.filter(([_, l]) => l.type === 'data');
212
+ const disconnect = all.filter(([_, l]) => l.type === 'disconnect');
213
+ return {
214
+ total: all.length,
215
+ data: data.length,
216
+ disconnect: disconnect.length,
217
+ ids: all.map(([id]) => id)
218
+ };
219
+ }
220
+ get(id) {
221
+ return this.listeners.get(id);
222
+ }
223
+ }
224
+
225
+ var DataBits;
226
+ (function (DataBits) {
227
+ DataBits["Five"] = "Five";
228
+ DataBits["Six"] = "Six";
229
+ DataBits["Seven"] = "Seven";
230
+ DataBits["Eight"] = "Eight";
231
+ })(DataBits || (DataBits = {}));
232
+ var FlowControl;
233
+ (function (FlowControl) {
234
+ FlowControl["None"] = "None";
235
+ FlowControl["Software"] = "Software";
236
+ FlowControl["Hardware"] = "Hardware";
237
+ })(FlowControl || (FlowControl = {}));
238
+ var Parity;
239
+ (function (Parity) {
240
+ Parity["None"] = "None";
241
+ Parity["Odd"] = "Odd";
242
+ Parity["Even"] = "Even";
243
+ })(Parity || (Parity = {}));
244
+ var StopBits;
245
+ (function (StopBits) {
246
+ StopBits["One"] = "One";
247
+ StopBits["Two"] = "Two";
248
+ })(StopBits || (StopBits = {}));
249
+ var ClearBuffer;
250
+ (function (ClearBuffer) {
251
+ ClearBuffer["Input"] = "Input";
252
+ ClearBuffer["Output"] = "Output";
253
+ ClearBuffer["All"] = "All";
254
+ })(ClearBuffer || (ClearBuffer = {}));
255
+ class SerialPort {
256
+ constructor(options) {
257
+ this.listeners = new ListenerManager();
258
+ this.autoReconnectManager = new AutoReconnectManager();
259
+ this.isOpen = false;
260
+ this.encoding = options.encoding || 'utf-8';
261
+ this.options = {
262
+ path: options.path,
263
+ baudRate: options.baudRate,
264
+ dataBits: options.dataBits || DataBits.Eight,
265
+ flowControl: options.flowControl || FlowControl.None,
266
+ parity: options.parity || Parity.None,
267
+ stopBits: options.stopBits || StopBits.One,
268
+ size: options.size || 1024,
269
+ timeout: options.timeout || 200,
270
+ };
271
+ this.size = options.size || 1024;
272
+ }
273
+ /**
274
+ * @description Lists all available serial ports
275
+ * @returns {Promise<{ [key: string]: PortInfo }>} A promise that resolves to a map of port names to port information
276
+ */
277
+ static async available_ports() {
278
+ try {
279
+ const result = await invoke('plugin:serialplugin|available_ports');
280
+ return Promise.resolve(result);
281
+ }
282
+ catch (error) {
283
+ return Promise.reject(error);
284
+ }
285
+ }
286
+ /**
287
+ * @description Lists all available serial ports using platform-specific commands
288
+ * @returns {Promise<{ [key: string]: PortInfo }>} A promise that resolves to a map of port names to port information
289
+ */
290
+ static async available_ports_direct() {
291
+ try {
292
+ const result = await invoke('plugin:serialplugin|available_ports_direct');
293
+ return Promise.resolve(result);
294
+ }
295
+ catch (error) {
296
+ return Promise.reject(error);
297
+ }
298
+ }
299
+ /**
300
+ * @description Lists all managed serial ports (ports that are currently open and managed by the application).
301
+ * @returns {Promise<string[]>} A promise that resolves to an array of port paths (names).
302
+ */
303
+ static async managed_ports() {
304
+ try {
305
+ const result = await invoke('plugin:serialplugin|managed_ports');
306
+ return Promise.resolve(result);
307
+ }
308
+ catch (error) {
309
+ return Promise.reject(error);
310
+ }
311
+ }
312
+ /**
313
+ * @description Forcefully closes a specific serial port
314
+ * @param {string} path The path of the serial port to close
315
+ * @returns {Promise<void>} A promise that resolves when the port is closed
316
+ */
317
+ static async forceClose(path) {
318
+ return await invoke('plugin:serialplugin|force_close', { path });
319
+ }
320
+ /**
321
+ * @description Closes all open serial ports
322
+ * @returns {Promise<void>} A promise that resolves when all ports are closed
323
+ */
324
+ static async closeAll() {
325
+ return await invoke('plugin:serialplugin|close_all');
326
+ }
327
+ /**
328
+ * @description Gets the full serial number for a specific port
329
+ * On Windows, this can fix truncated serial numbers (e.g., "B4" → "B4:3D:4D:B1:5A:C8" for ESP32 devices)
330
+ * @param {string} path The port path (e.g., "COM3", "/dev/ttyUSB0")
331
+ * @returns {Promise<string>} A promise that resolves to the full serial number, or "Unknown" if not found
332
+ */
333
+ static async get_full_serial_number(path) {
334
+ try {
335
+ const result = await invoke('plugin:serialplugin|get_full_serial_number', { path });
336
+ return Promise.resolve(result);
337
+ }
338
+ catch (error) {
339
+ return Promise.reject(error);
340
+ }
341
+ }
342
+ /**
343
+ * @description Cancels listening for serial port data (does not affect disconnect listeners)
344
+ * @returns {Promise<void>} A promise that resolves when listening is cancelled
345
+ */
346
+ async cancelListen() {
347
+ try {
348
+ // Cancel only data listeners - disconnect listeners remain active
349
+ const dataListeners = this.listeners.filterByType('data');
350
+ for (const [id, listener] of dataListeners) {
351
+ try {
352
+ if (typeof listener.unlisten === 'function') {
353
+ listener.unlisten();
354
+ }
355
+ }
356
+ catch (error) {
357
+ console.warn(`Error unlistening data listener ${id}:`, error);
358
+ }
359
+ // Remove from map regardless of success/failure
360
+ this.listeners.delete(id);
361
+ }
362
+ return;
363
+ }
364
+ catch (error) {
365
+ return Promise.reject('Failed to cancel serial monitoring: ' + error);
366
+ }
367
+ }
368
+ /**
369
+ * @description Cancels all listeners (both data and disconnect listeners)
370
+ * @returns {Promise<void>} A promise that resolves when all listeners are cancelled
371
+ */
372
+ async cancelAllListeners() {
373
+ try {
374
+ const allListeners = this.listeners.all();
375
+ for (const [id, listener] of allListeners) {
376
+ try {
377
+ if (typeof listener.unlisten === 'function') {
378
+ listener.unlisten();
379
+ }
380
+ }
381
+ catch (error) {
382
+ console.warn(`Error unlistening listener ${id}:`, error);
383
+ }
384
+ // Remove from map regardless of success/failure
385
+ this.listeners.delete(id);
386
+ }
387
+ return;
388
+ }
389
+ catch (error) {
390
+ return Promise.reject('Failed to cancel all listeners: ' + error);
391
+ }
392
+ }
393
+ /**
394
+ * @description Gets information about active listeners (for debugging)
395
+ * @returns {Object} Information about active listeners
396
+ */
397
+ getListenersInfo() {
398
+ return this.listeners.getInfo();
399
+ }
400
+ /**
401
+ * @description Cancels reading data from the serial port
402
+ * @returns {Promise<void>} A promise that resolves when reading is cancelled
403
+ */
404
+ async cancelRead() {
405
+ try {
406
+ await invoke('plugin:serialplugin|cancel_read', {
407
+ path: this.options.path,
408
+ });
409
+ }
410
+ catch (error) {
411
+ return Promise.reject(error instanceof Error ? error : new Error(String(error)));
412
+ }
413
+ }
414
+ /**
415
+ * @description Changes the serial port configuration
416
+ * @param {object} options Configuration options
417
+ * @param {string} [options.path] New port path
418
+ * @param {number} [options.baudRate] New baud rate
419
+ * @returns {Promise<void>} A promise that resolves when configuration is changed
420
+ */
421
+ async change(options) {
422
+ try {
423
+ let isOpened = false;
424
+ if (this.isOpen) {
425
+ isOpened = true;
426
+ await this.close();
427
+ }
428
+ if (options.path) {
429
+ this.options.path = options.path;
430
+ }
431
+ if (options.baudRate) {
432
+ this.options.baudRate = options.baudRate;
433
+ }
434
+ if (isOpened) {
435
+ await this.open();
436
+ }
437
+ return Promise.resolve();
438
+ }
439
+ catch (error) {
440
+ return Promise.reject(error);
441
+ }
442
+ }
443
+ /**
444
+ * @description Closes the currently open serial port
445
+ * @returns {Promise<void>} A promise that resolves when the port is closed
446
+ */
447
+ async close() {
448
+ try {
449
+ if (!this.isOpen) {
450
+ return;
451
+ }
452
+ // Stop auto-reconnect temporarily to prevent conflicts
453
+ const wasAutoReconnectEnabled = this.autoReconnectManager.isEnabled();
454
+ if (wasAutoReconnectEnabled) {
455
+ await this.autoReconnectManager.stop();
456
+ }
457
+ // First we cancel the reading
458
+ try {
459
+ await this.cancelRead();
460
+ }
461
+ catch (cancelReadError) {
462
+ console.warn('Error during cancelRead:', cancelReadError);
463
+ }
464
+ // Closing the port
465
+ let res = undefined;
466
+ try {
467
+ res = await invoke('plugin:serialplugin|close', {
468
+ path: this.options.path,
469
+ });
470
+ }
471
+ catch (closeError) {
472
+ console.warn('Error during port close:', closeError);
473
+ }
474
+ // Cancel all listeners
475
+ try {
476
+ await this.cancelAllListeners();
477
+ }
478
+ catch (cancelListenError) {
479
+ console.warn('Error during cancelAllListeners:', cancelListenError);
480
+ // Try to clear listeners manually as fallback
481
+ try {
482
+ this.listeners.clear();
483
+ }
484
+ catch (clearError) {
485
+ console.warn('Error during manual listener clear:', clearError);
486
+ }
487
+ }
488
+ this.isOpen = false;
489
+ return res;
490
+ }
491
+ catch (error) {
492
+ return Promise.reject(error);
493
+ }
494
+ }
495
+ /**
496
+ * @description Sets up a listener for port disconnection events
497
+ * @param {Function} fn Callback function to handle disconnection
498
+ * @returns {Promise<void>} A promise that resolves when the listener is set up
499
+ */
500
+ async disconnected(fn) {
501
+ let sub_path = this.options.path?.toString().replaceAll(".", "-").replaceAll("/", "-");
502
+ let checkEvent = `plugin-serialplugin-disconnected-${sub_path}`;
503
+ console.log('listen event: ' + checkEvent);
504
+ const unListenResult = await listen(checkEvent, () => {
505
+ try {
506
+ fn();
507
+ }
508
+ catch (error) {
509
+ console.error(error);
510
+ }
511
+ });
512
+ if (typeof unListenResult === 'function') {
513
+ this.listeners.add('disconnect', unListenResult);
514
+ }
515
+ else {
516
+ console.warn('disconnected() did not return a valid unlisten function');
517
+ }
518
+ }
519
+ /**
520
+ * @description Enables auto-reconnect functionality
521
+ * @param {Object} options Auto-reconnect configuration options
522
+ * @param {number} [options.interval=5000] Reconnection interval in milliseconds
523
+ * @param {number | null} [options.maxAttempts=10] Maximum number of reconnection attempts (null for infinite)
524
+ * @param {Function} [options.onReconnect] Callback function called on each reconnection attempt
525
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect is enabled
526
+ */
527
+ async enableAutoReconnect(options = {}) {
528
+ try {
529
+ await this.autoReconnectManager.enable({
530
+ ...options,
531
+ reconnectFunction: async () => {
532
+ if (this.isOpen) {
533
+ return true;
534
+ }
535
+ try {
536
+ await this.open();
537
+ return true;
538
+ }
539
+ catch (error) {
540
+ return false;
541
+ }
542
+ }
543
+ });
544
+ // Set up disconnect listener that triggers auto-reconnect
545
+ await this.disconnected(async () => {
546
+ this.isOpen = false;
547
+ if (this.autoReconnectManager.isEnabled()) {
548
+ await this.autoReconnectManager.start();
549
+ }
550
+ });
551
+ }
552
+ catch (error) {
553
+ return Promise.reject(error);
554
+ }
555
+ }
556
+ /**
557
+ * @description Disables auto-reconnect functionality
558
+ * @returns {Promise<void>} A promise that resolves when auto-reconnect is disabled
559
+ */
560
+ async disableAutoReconnect() {
561
+ try {
562
+ await this.autoReconnectManager.disable();
563
+ }
564
+ catch (error) {
565
+ return Promise.reject(error);
566
+ }
567
+ }
568
+ /**
569
+ * @description Gets auto-reconnect status and configuration
570
+ * @returns {Object} Auto-reconnect information
571
+ */
572
+ getAutoReconnectInfo() {
573
+ return {
574
+ enabled: this.autoReconnectManager.isEnabled(),
575
+ interval: this.autoReconnectManager.getInterval(),
576
+ maxAttempts: this.autoReconnectManager.getMaxAttempts(),
577
+ currentAttempts: this.autoReconnectManager.getCurrentAttempts(),
578
+ hasCallback: this.autoReconnectManager.hasCallback(),
579
+ };
580
+ }
581
+ /**
582
+ * @description Manually triggers a reconnection attempt
583
+ * @returns {Promise<boolean>} A promise that resolves to true if reconnection was successful
584
+ */
585
+ async manualReconnect() {
586
+ try {
587
+ if (this.isOpen) {
588
+ console.log('Port is already open, no need to reconnect');
589
+ return true;
590
+ }
591
+ console.log('Manual reconnection attempt...');
592
+ await this.open();
593
+ console.log('Manual reconnection successful');
594
+ return true;
595
+ }
596
+ catch (error) {
597
+ console.error('Manual reconnection failed:', error);
598
+ return false;
599
+ }
600
+ }
601
+ /**
602
+ * @description Monitors serial port data
603
+ * @param {Function} fn Callback function to handle received data
604
+ * @param {boolean} [isDecode=true] Whether to decode the received data
605
+ * @returns {Promise<UnlistenFn>} A promise that resolves to an unlisten function
606
+ */
607
+ async listen(fn, isDecode = true) {
608
+ try {
609
+ if (!this.isOpen) {
610
+ return Promise.reject('Port is not open');
611
+ }
612
+ let sub_path = this.options.path?.toString().replaceAll(".", "-").replaceAll("/", "-");
613
+ let readEvent = `plugin-serialplugin-read-${sub_path}`;
614
+ console.log('listen event: ' + readEvent);
615
+ try {
616
+ const unListenResult = await listen(readEvent, ({ payload }) => {
617
+ try {
618
+ if (isDecode) {
619
+ const uint8Array = new Uint8Array(payload.data);
620
+ try {
621
+ const decoder = new TextDecoder(this.encoding);
622
+ const textData = decoder.decode(uint8Array);
623
+ fn(textData);
624
+ }
625
+ catch (error) {
626
+ console.error('Error converting to text with configured encoding:', error);
627
+ try {
628
+ const fallbackDecoder = new TextDecoder('utf-8');
629
+ const textData = fallbackDecoder.decode(uint8Array);
630
+ fn(textData);
631
+ }
632
+ catch (fallbackError) {
633
+ console.error('Fallback decoding also failed:', fallbackError);
634
+ fn(String.fromCharCode(...uint8Array));
635
+ }
636
+ }
637
+ }
638
+ else {
639
+ fn(new Uint8Array(payload.data));
640
+ }
641
+ }
642
+ catch (error) {
643
+ console.error(error);
644
+ }
645
+ });
646
+ if (typeof unListenResult === 'function') {
647
+ return this.listeners.add('data', unListenResult);
648
+ }
649
+ else {
650
+ console.warn('listen() did not return a valid unlisten function');
651
+ return Promise.reject('Failed to get unlisten function');
652
+ }
653
+ }
654
+ catch (listenError) {
655
+ console.error('Error setting up listener:', listenError);
656
+ throw listenError;
657
+ }
658
+ }
659
+ catch (error) {
660
+ return Promise.reject('Failed to monitor serial port data: ' + error);
661
+ }
662
+ }
663
+ /**
664
+ * @description Opens the serial port with current settings
665
+ * @returns {Promise<void>} A promise that resolves when the port is opened
666
+ */
667
+ async open() {
668
+ try {
669
+ if (!this.options.path) {
670
+ return Promise.reject(`path Can not be empty!`);
671
+ }
672
+ if (!this.options.baudRate) {
673
+ return Promise.reject(`baudRate Can not be empty!`);
674
+ }
675
+ if (this.isOpen) {
676
+ return;
677
+ }
678
+ const res = await invoke('plugin:serialplugin|open', {
679
+ path: this.options.path,
680
+ baudRate: this.options.baudRate,
681
+ dataBits: this.options.dataBits,
682
+ flowControl: this.options.flowControl,
683
+ parity: this.options.parity,
684
+ stopBits: this.options.stopBits,
685
+ timeout: this.options.timeout,
686
+ });
687
+ this.isOpen = true;
688
+ this.disconnected(() => {
689
+ this.isOpen = false;
690
+ }).catch(err => console.error(err));
691
+ return Promise.resolve(res);
692
+ }
693
+ catch (error) {
694
+ return Promise.reject(error);
695
+ }
696
+ }
697
+ /**
698
+ * Starts listening for data on the serial port
699
+ * The port will continuously monitor for incoming data and emit events
700
+ * @returns {Promise<void>} A promise that resolves when listening starts
701
+ * @throws {Error} If starting listener fails or port is not open
702
+ * @example
703
+ * const port = new SerialPort({ path: '/dev/ttyUSB0' });
704
+ * await port.startListening();
705
+ * // Listen for data events
706
+ * port.listen((data) => {
707
+ * console.log('listen', data)
708
+ * receivedData += data;
709
+ * });
710
+ */
711
+ async startListening() {
712
+ try {
713
+ await invoke('plugin:serialplugin|start_listening', {
714
+ path: this.options.path,
715
+ size: this.options.size,
716
+ timeout: this.options.timeout,
717
+ });
718
+ }
719
+ catch (error) {
720
+ return Promise.reject(error);
721
+ }
722
+ }
723
+ /**
724
+ * Stops listening for data on the serial port
725
+ * Cleans up event listeners and monitoring threads
726
+ * @returns {Promise<void>} A promise that resolves when listening stops
727
+ * @throws {Error} If stopping listener fails or port is not open
728
+ * @example
729
+ * await port.stopListening();
730
+ */
731
+ async stopListening() {
732
+ try {
733
+ await invoke('plugin:serialplugin|stop_listening', {
734
+ path: this.options.path,
735
+ });
736
+ }
737
+ catch (error) {
738
+ return Promise.reject(error);
739
+ }
740
+ }
741
+ /**
742
+ * @description Reads data from the serial port
743
+ * @param {ReadOptions} [options] Read options
744
+ * @returns {Promise<void>} A promise that resolves when data is read
745
+ */
746
+ async read(options) {
747
+ try {
748
+ if (!this.isOpen) {
749
+ return Promise.reject('Port is not open');
750
+ }
751
+ return await invoke('plugin:serialplugin|read', {
752
+ path: this.options.path,
753
+ timeout: options?.timeout || this.options.timeout,
754
+ size: options?.size || this.size,
755
+ });
756
+ }
757
+ catch (error) {
758
+ return Promise.reject(error);
759
+ }
760
+ }
761
+ /**
762
+ * @description Reads binary data from the serial port
763
+ * @param {ReadOptions} [options] Read options
764
+ * @returns {Promise<Uint8Array>} A promise that resolves with binary data
765
+ */
766
+ async readBinary(options) {
767
+ try {
768
+ const result = await invoke('plugin:serialplugin|read_binary', {
769
+ path: this.options.path,
770
+ timeout: options?.timeout || this.options.timeout,
771
+ size: options?.size || this.size,
772
+ });
773
+ return new Uint8Array(result);
774
+ }
775
+ catch (error) {
776
+ return Promise.reject(error);
777
+ }
778
+ }
779
+ /**
780
+ * @description Sets the baud rate of the serial port
781
+ * @param {number} value The new baud rate
782
+ * @returns {Promise<void>} A promise that resolves when baud rate is set
783
+ */
784
+ async setBaudRate(value) {
785
+ try {
786
+ return await invoke('plugin:serialplugin|set_baud_rate', {
787
+ path: this.options.path,
788
+ baudRate: value
789
+ });
790
+ }
791
+ catch (error) {
792
+ return Promise.reject(error);
793
+ }
794
+ }
795
+ /**
796
+ * @description Sets the data bits configuration
797
+ * @param {DataBits} value The new data bits setting
798
+ * @returns {Promise<void>} A promise that resolves when data bits are set
799
+ */
800
+ async setDataBits(value) {
801
+ try {
802
+ return await invoke('plugin:serialplugin|set_data_bits', {
803
+ path: this.options.path,
804
+ dataBits: value
805
+ });
806
+ }
807
+ catch (error) {
808
+ return Promise.reject(error);
809
+ }
810
+ }
811
+ /**
812
+ * @description Sets the flow control mode
813
+ * @param {FlowControl} value The new flow control setting
814
+ * @returns {Promise<void>} A promise that resolves when flow control is set
815
+ */
816
+ async setFlowControl(value) {
817
+ try {
818
+ return await invoke('plugin:serialplugin|set_flow_control', {
819
+ path: this.options.path,
820
+ flowControl: value
821
+ });
822
+ }
823
+ catch (error) {
824
+ return Promise.reject(error);
825
+ }
826
+ }
827
+ /**
828
+ * @description Sets the parity checking mode
829
+ * @param {Parity} value The new parity setting
830
+ * @returns {Promise<void>} A promise that resolves when parity is set
831
+ */
832
+ async setParity(value) {
833
+ try {
834
+ return await invoke('plugin:serialplugin|set_parity', {
835
+ path: this.options.path,
836
+ parity: value
837
+ });
838
+ }
839
+ catch (error) {
840
+ return Promise.reject(error);
841
+ }
842
+ }
843
+ /**
844
+ * @description Sets the number of stop bits
845
+ * @param {StopBits} value The new stop bits setting
846
+ * @returns {Promise<void>} A promise that resolves when stop bits are set
847
+ */
848
+ async setStopBits(value) {
849
+ try {
850
+ return await invoke('plugin:serialplugin|set_stop_bits', {
851
+ path: this.options.path,
852
+ stopBits: value
853
+ });
854
+ }
855
+ catch (error) {
856
+ return Promise.reject(error);
857
+ }
858
+ }
859
+ /**
860
+ * @description Sets the timeout duration
861
+ * @param {number} value The new timeout in milliseconds
862
+ * @returns {Promise<void>} A promise that resolves when timeout is set
863
+ */
864
+ async setTimeout(value) {
865
+ try {
866
+ return await invoke('plugin:serialplugin|set_timeout', {
867
+ path: this.options.path,
868
+ timeout: value
869
+ });
870
+ }
871
+ catch (error) {
872
+ return Promise.reject(error);
873
+ }
874
+ }
875
+ /**
876
+ * @description Sets the RTS (Request To Send) control signal
877
+ * @param {boolean} value The signal level to set
878
+ * @returns {Promise<void>} A promise that resolves when RTS is set
879
+ */
880
+ async setRequestToSend(value) {
881
+ try {
882
+ return await invoke('plugin:serialplugin|write_request_to_send', {
883
+ path: this.options.path,
884
+ level: value
885
+ });
886
+ }
887
+ catch (error) {
888
+ return Promise.reject(error);
889
+ }
890
+ }
891
+ /**
892
+ * @description Sets the DTR (Data Terminal Ready) control signal
893
+ * @param {boolean} value The signal level to set
894
+ * @returns {Promise<void>} A promise that resolves when DTR is set
895
+ */
896
+ async setDataTerminalReady(value) {
897
+ try {
898
+ return await invoke('plugin:serialplugin|write_data_terminal_ready', {
899
+ path: this.options.path,
900
+ level: value
901
+ });
902
+ }
903
+ catch (error) {
904
+ return Promise.reject(error);
905
+ }
906
+ }
907
+ /**
908
+ * @description Writes the RTS (Request To Send) control signal
909
+ * @param {boolean} level The signal level to set
910
+ * @returns {Promise<void>} A promise that resolves when RTS is set
911
+ */
912
+ async writeRequestToSend(level) {
913
+ try {
914
+ return await invoke('plugin:serialplugin|write_request_to_send', {
915
+ path: this.options.path,
916
+ level: level
917
+ });
918
+ }
919
+ catch (error) {
920
+ return Promise.reject(error);
921
+ }
922
+ }
923
+ /**
924
+ * @description Writes the DTR (Data Terminal Ready) control signal
925
+ * @param {boolean} level The signal level to set
926
+ * @returns {Promise<void>} A promise that resolves when DTR is set
927
+ */
928
+ async writeDataTerminalReady(level) {
929
+ try {
930
+ return await invoke('plugin:serialplugin|write_data_terminal_ready', {
931
+ path: this.options.path,
932
+ level: level
933
+ });
934
+ }
935
+ catch (error) {
936
+ return Promise.reject(error);
937
+ }
938
+ }
939
+ /**
940
+ * @description Reads the CTS (Clear To Send) control signal state
941
+ * @returns {Promise<boolean>} A promise that resolves to the CTS state
942
+ */
943
+ async readClearToSend() {
944
+ try {
945
+ return await invoke('plugin:serialplugin|read_clear_to_send', {
946
+ path: this.options.path
947
+ });
948
+ }
949
+ catch (error) {
950
+ return Promise.reject(error);
951
+ }
952
+ }
953
+ /**
954
+ * @description Reads the DSR (Data Set Ready) control signal state
955
+ * @returns {Promise<boolean>} A promise that resolves to the DSR state
956
+ */
957
+ async readDataSetReady() {
958
+ try {
959
+ return await invoke('plugin:serialplugin|read_data_set_ready', {
960
+ path: this.options.path
961
+ });
962
+ }
963
+ catch (error) {
964
+ return Promise.reject(error);
965
+ }
966
+ }
967
+ /**
968
+ * @description Reads the RI (Ring Indicator) control signal state
969
+ * @returns {Promise<boolean>} A promise that resolves to the RI state
970
+ */
971
+ async readRingIndicator() {
972
+ try {
973
+ return await invoke('plugin:serialplugin|read_ring_indicator', {
974
+ path: this.options.path
975
+ });
976
+ }
977
+ catch (error) {
978
+ return Promise.reject(error);
979
+ }
980
+ }
981
+ /**
982
+ * @description Reads the CD (Carrier Detect) control signal state
983
+ * @returns {Promise<boolean>} A promise that resolves to the CD state
984
+ */
985
+ async readCarrierDetect() {
986
+ try {
987
+ return await invoke('plugin:serialplugin|read_carrier_detect', {
988
+ path: this.options.path
989
+ });
990
+ }
991
+ catch (error) {
992
+ return Promise.reject(error);
993
+ }
994
+ }
995
+ /**
996
+ * @description Gets the number of bytes available to read
997
+ * @returns {Promise<number>} A promise that resolves to the number of bytes
998
+ */
999
+ async bytesToRead() {
1000
+ try {
1001
+ return await invoke('plugin:serialplugin|bytes_to_read', {
1002
+ path: this.options.path
1003
+ });
1004
+ }
1005
+ catch (error) {
1006
+ return Promise.reject(error);
1007
+ }
1008
+ }
1009
+ /**
1010
+ * @description Gets the number of bytes waiting to be written
1011
+ * @returns {Promise<number>} A promise that resolves to the number of bytes
1012
+ */
1013
+ async bytesToWrite() {
1014
+ try {
1015
+ return await invoke('plugin:serialplugin|bytes_to_write', {
1016
+ path: this.options.path
1017
+ });
1018
+ }
1019
+ catch (error) {
1020
+ return Promise.reject(error);
1021
+ }
1022
+ }
1023
+ /**
1024
+ * @description Clears the specified buffer
1025
+ * @param {ClearBuffer} buffer The buffer to clear
1026
+ * @returns {Promise<void>} A promise that resolves when the buffer is cleared
1027
+ */
1028
+ async clearBuffer(buffer) {
1029
+ try {
1030
+ return await invoke('plugin:serialplugin|clear_buffer', {
1031
+ path: this.options.path,
1032
+ bufferType: buffer
1033
+ });
1034
+ }
1035
+ catch (error) {
1036
+ return Promise.reject(error);
1037
+ }
1038
+ }
1039
+ /**
1040
+ * @description Starts transmitting a break signal
1041
+ * @returns {Promise<void>} A promise that resolves when break signal starts
1042
+ */
1043
+ async setBreak() {
1044
+ try {
1045
+ return await invoke('plugin:serialplugin|set_break', {
1046
+ path: this.options.path
1047
+ });
1048
+ }
1049
+ catch (error) {
1050
+ return Promise.reject(error);
1051
+ }
1052
+ }
1053
+ /**
1054
+ * @description Stops transmitting a break signal
1055
+ * @returns {Promise<void>} A promise that resolves when break signal stops
1056
+ */
1057
+ async clearBreak() {
1058
+ try {
1059
+ return await invoke('plugin:serialplugin|clear_break', {
1060
+ path: this.options.path
1061
+ });
1062
+ }
1063
+ catch (error) {
1064
+ return Promise.reject(error);
1065
+ }
1066
+ }
1067
+ /**
1068
+ * @description Writes string data to the serial port
1069
+ * @param {string} value The data to write
1070
+ * @returns {Promise<number>} A promise that resolves to the number of bytes written
1071
+ */
1072
+ async write(value) {
1073
+ try {
1074
+ if (!this.isOpen) {
1075
+ return Promise.reject(`serial port ${this.options.path} not opened!`);
1076
+ }
1077
+ return await invoke('plugin:serialplugin|write', {
1078
+ value,
1079
+ path: this.options.path,
1080
+ });
1081
+ }
1082
+ catch (error) {
1083
+ return Promise.reject(error);
1084
+ }
1085
+ }
1086
+ /**
1087
+ * @description Writes binary data to the serial port
1088
+ * @param {Uint8Array | number[]} value The binary data to write
1089
+ * @returns {Promise<number>} A promise that resolves to the number of bytes written
1090
+ */
1091
+ async writeBinary(value) {
1092
+ try {
1093
+ if (!this.isOpen) {
1094
+ return Promise.reject(`serial port ${this.options.path} not opened!`);
1095
+ }
1096
+ if (value instanceof Uint8Array || value instanceof Array) {
1097
+ return await invoke('plugin:serialplugin|write_binary', {
1098
+ value: Array.from(value),
1099
+ path: this.options.path,
1100
+ });
1101
+ }
1102
+ else {
1103
+ return Promise.reject('value Argument type error! Expected type: string, Uint8Array, number[]');
1104
+ }
1105
+ }
1106
+ catch (error) {
1107
+ return Promise.reject(error);
1108
+ }
1109
+ }
1110
+ }
1111
+
1112
+ export { ClearBuffer, DataBits, FlowControl, Parity, SerialPort, StopBits };