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.
package/README.md ADDED
@@ -0,0 +1,1678 @@
1
+ [![npm version](https://img.shields.io/npm/v/tauri-plugin-serialplugin/latest?style=for-the-badge)](https://www.npmjs.com/package/tauri-plugin-serialplugin)
2
+ [![Crates.io](https://img.shields.io/crates/v/tauri-plugin-serialplugin?style=for-the-badge)](https://crates.io/crates/tauri-plugin-serialplugin)
3
+ [![Documentation](https://img.shields.io/badge/docs-docs.rs-blue?style=for-the-badge)](https://docs.rs/tauri-plugin-serialplugin/latest/tauri_plugin_serialplugin/all.html)
4
+ [![GitHub issues](https://img.shields.io/github/issues/s00d/tauri-plugin-serialplugin?style=for-the-badge)](https://github.com/s00d/tauri-plugin-serialplugin/issues)
5
+ [![GitHub stars](https://img.shields.io/github/stars/s00d/tauri-plugin-serialplugin?style=for-the-badge)](https://github.com/s00d/tauri-plugin-serialplugin/stargazers)
6
+ [![Donate](https://img.shields.io/badge/Donate-Donationalerts-ff4081?style=for-the-badge)](https://www.donationalerts.com/r/s00d88)
7
+
8
+ # Tauri Plugin — SerialPort
9
+
10
+ A comprehensive plugin for Tauri applications to communicate with serial ports. This plugin provides a complete API for reading from and writing to serial devices, with support for various configuration options and control signals.
11
+
12
+ > **⚠️ Important Notice:** The JavaScript dependency has been renamed from `tauri-plugin-serialplugin` to `tauri-plugin-serialplugin-api`. Please update your `package.json` before updating to the latest version, following the same pattern used by other Tauri plugins.
13
+
14
+ ---
15
+
16
+ ## Table of Contents
17
+
18
+ 1. [Installation](#installation)
19
+ 2. [Basic Usage](#basic-usage)
20
+ 3. [TypeScript Support](#typescript-support)
21
+ 4. [Rust Usage](#rust-usage)
22
+ 5. [Permissions](#permissions)
23
+ 6. [API Reference](#api-reference)
24
+ 6.1. [Port Discovery](#port-discovery)
25
+ 6.2. [Connection Management](#connection-management)
26
+ 6.3. [Data Transfer](#data-transfer)
27
+ 6.4. [Port Configuration](#port-configuration)
28
+ 6.5. [Control Signals](#control-signals)
29
+ 6.6. [Buffer Management](#buffer-management)
30
+ 7. [Common Use Cases](#common-use-cases)
31
+ 8. [Android Setup](#android-setup)
32
+ 9. [Contributing](#contributing)
33
+ 10. [Development Setup](#development-setup)
34
+ 11. [Testing](#testing)
35
+ 12. [Partners](#partners)
36
+ 13. [License](#license)
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ ### Prerequisites
43
+
44
+ - **Rust** version 1.70 or higher
45
+ - **Tauri** 2.0 or higher
46
+ - **Node.js** and an npm-compatible package manager (npm, yarn, pnpm)
47
+
48
+
49
+
50
+
51
+ ## Installation
52
+
53
+ ### Automatic Installation (Recommended)
54
+
55
+ Use the Tauri CLI to automatically install both the Rust and JavaScript parts of the plugin:
56
+
57
+ ```bash
58
+ # npm
59
+ npm run tauri add serialplugin
60
+
61
+ # yarn
62
+ yarn run tauri add serialplugin
63
+
64
+ # pnpm
65
+ pnpm tauri add serialplugin
66
+
67
+ # deno
68
+ deno task tauri add serialplugin
69
+
70
+ # bun
71
+ bun tauri add serialplugin
72
+
73
+ # cargo
74
+ cargo tauri add serialplugin
75
+ ```
76
+
77
+ ### Manual Installation
78
+
79
+ #### Backend (Rust)
80
+
81
+ Add the plugin using cargo:
82
+
83
+ ```bash
84
+ cd ./src-tauri
85
+ cargo add tauri-plugin-serialplugin
86
+ ```
87
+
88
+ #### Frontend (JavaScript/TypeScript)
89
+
90
+ Install the JavaScript API:
91
+
92
+ ```bash
93
+ npm install tauri-plugin-serialplugin-api
94
+ # or
95
+ pnpm add tauri-plugin-serialplugin-api
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Basic Usage
101
+
102
+ 1. **Register the Plugin**
103
+ ```rust
104
+ // src-tauri/src/main.rs
105
+ fn main() {
106
+ tauri::Builder::default()
107
+ .plugin(tauri_plugin_serialplugin::init())
108
+ .run(tauri::generate_context!())
109
+ .expect("error while running tauri application");
110
+ }
111
+ ```
112
+
113
+ 2. **Configure Permissions**
114
+ ```jsonc
115
+ // src-tauri/capabilities/default.json
116
+ {
117
+ "$schema": "../gen/schemas/desktop-schema.json",
118
+ "identifier": "default",
119
+ "description": "Capability for the main window",
120
+ "windows": ["main"],
121
+ "permissions": [
122
+ "core:default",
123
+ "serialplugin:default"
124
+ ]
125
+ }
126
+ ```
127
+
128
+ 3. **Basic Example**
129
+ ```typescript
130
+ import { SerialPort } from "tauri-plugin-serialplugin-api";
131
+
132
+ // List available ports
133
+ const ports = await SerialPort.available_ports();
134
+ console.log("Available ports:", ports);
135
+
136
+ // Open a port
137
+ const port = new SerialPort({
138
+ path: "COM1",
139
+ baudRate: 9600
140
+ });
141
+ await port.open();
142
+
143
+ // Write data
144
+ await port.write("Hello, Serial Port!");
145
+
146
+ // Start port listening
147
+ const unsubscribe = await port.listen((data) => {
148
+ console.log("Received:", data);
149
+ });
150
+
151
+ // Stop listening when done
152
+ await port.cancelListen();
153
+
154
+ // Close port
155
+ await port.close();
156
+ ```
157
+
158
+ 4. **Error Handling Example**
159
+ ```typescript
160
+ import { SerialPort } from "tauri-plugin-serialplugin-api";
161
+
162
+ async function handleSerialPort() {
163
+ let port: SerialPort | null = null;
164
+
165
+ try {
166
+ // List available ports
167
+ const ports = await SerialPort.available_ports();
168
+ if (Object.keys(ports).length === 0) {
169
+ throw new Error("No serial ports found");
170
+ }
171
+
172
+ // Open port
173
+ port = new SerialPort({
174
+ path: "COM1",
175
+ baudRate: 9600
176
+ });
177
+
178
+ try {
179
+ await port.open();
180
+ } catch (error) {
181
+ throw new Error(`Failed to open port: ${error}`);
182
+ }
183
+
184
+ try {
185
+ // Write data
186
+ await port.write("Test data");
187
+ } catch (error) {
188
+ throw new Error(`Failed to write data: ${error}`);
189
+ }
190
+
191
+ try {
192
+ // Read data
193
+ const data = await port.read({ timeout: 1000 });
194
+ console.log("Received:", data);
195
+ } catch (error) {
196
+ throw new Error(`Failed to read data: ${error}`);
197
+ }
198
+
199
+ try {
200
+ // Start listening
201
+ await port.startListening();
202
+ await port.listen((data) => {
203
+ console.log("Received:", data);
204
+ });
205
+ } catch (error) {
206
+ throw new Error(`Failed to start listening: ${error}`);
207
+ }
208
+
209
+ try {
210
+ // Configure port settings
211
+ await port.setBaudRate(115200);
212
+ await port.setDataBits(DataBits.Eight);
213
+ await port.setFlowControl(FlowControl.None);
214
+ await port.setParity(Parity.None);
215
+ await port.setStopBits(StopBits.One);
216
+ await port.setTimeout(1000);
217
+ } catch (error) {
218
+ throw new Error(`Failed to configure port: ${error}`);
219
+ }
220
+
221
+ } catch (error) {
222
+ // Handle all errors in one place
223
+ console.error("Serial port error:", error);
224
+ } finally {
225
+ // Clean up
226
+ if (port) {
227
+ try {
228
+ await port.cancelListen();
229
+ await port.close();
230
+ } catch (error) {
231
+ console.error("Error during cleanup:", error);
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ // Usage
238
+ handleSerialPort();
239
+ ```
240
+
241
+ ---
242
+
243
+ ## TypeScript Support
244
+
245
+ This plugin provides full TypeScript support with comprehensive type definitions. All methods, interfaces, and enums are properly typed for better development experience.
246
+
247
+ ### Available Types
248
+
249
+ ```typescript
250
+ import {
251
+ SerialPort,
252
+ DataBits,
253
+ FlowControl,
254
+ Parity,
255
+ StopBits,
256
+ ClearBuffer,
257
+ PortInfo,
258
+ SerialportOptions,
259
+ ReadOptions
260
+ } from "tauri-plugin-serialplugin-api";
261
+ ```
262
+
263
+ ### Type Definitions
264
+
265
+ - **`SerialPort`** - Main class for serial port operations
266
+ - **`DataBits`** - Enum: `Five`, `Six`, `Seven`, `Eight`
267
+ - **`FlowControl`** - Enum: `None`, `Software`, `Hardware`
268
+ - **`Parity`** - Enum: `None`, `Odd`, `Even`
269
+ - **`StopBits`** - Enum: `One`, `Two`
270
+ - **`ClearBuffer`** - Enum: `Input`, `Output`, `All`
271
+ - **`PortInfo`** - Interface for port information
272
+ - **`SerialportOptions`** - Interface for port configuration
273
+ - **`ReadOptions`** - Interface for read operation options
274
+
275
+ ### Configuration Example with Types
276
+
277
+ ```typescript
278
+ import { SerialPort, DataBits, FlowControl, Parity, StopBits } from "tauri-plugin-serialplugin-api";
279
+
280
+ const port = new SerialPort({
281
+ path: "/dev/ttyUSB0",
282
+ baudRate: 9600,
283
+ dataBits: DataBits.Eight, // Type-safe enum
284
+ flowControl: FlowControl.None, // Type-safe enum
285
+ parity: Parity.None, // Type-safe enum
286
+ stopBits: StopBits.One, // Type-safe enum
287
+ timeout: 1000,
288
+ size: 1024
289
+ });
290
+
291
+ // All configuration methods are fully typed
292
+ await port.setBaudRate(115200);
293
+ await port.setDataBits(DataBits.Eight);
294
+ await port.setFlowControl(FlowControl.None);
295
+ await port.setParity(Parity.None);
296
+ await port.setStopBits(StopBits.One);
297
+ await port.setTimeout(500);
298
+ ```
299
+
300
+ ### Control Signals with Types
301
+
302
+ ```typescript
303
+ // Set control signals
304
+ await port.setRequestToSend(true);
305
+ await port.setDataTerminalReady(true);
306
+
307
+ // Alternative methods (writeRequestToSend and writeDataTerminalReady)
308
+ await port.writeRequestToSend(true);
309
+ await port.writeDataTerminalReady(true);
310
+
311
+ // Read control signals
312
+ const cts = await port.readClearToSend();
313
+ const dsr = await port.readDataSetReady();
314
+ const ri = await port.readRingIndicator();
315
+ const cd = await port.readCarrierDetect();
316
+ ```
317
+
318
+ ### Buffer Management with Types
319
+
320
+ ```typescript
321
+ import { ClearBuffer } from "tauri-plugin-serialplugin-api";
322
+
323
+ // Check buffer status
324
+ const bytesToRead = await port.bytesToRead();
325
+ const bytesToWrite = await port.bytesToWrite();
326
+
327
+ // Clear buffers with type-safe enum
328
+ await port.clearBuffer(ClearBuffer.Input);
329
+ await port.clearBuffer(ClearBuffer.Output);
330
+ await port.clearBuffer(ClearBuffer.All);
331
+
332
+ // Break signal control
333
+ await port.setBreak();
334
+ await port.clearBreak();
335
+ ```
336
+
337
+ ---
338
+
339
+ ## Rust Usage
340
+
341
+ This plugin can also be used directly from Rust code in your Tauri backend. For complete API documentation, see [docs.rs](https://docs.rs/tauri-plugin-serialplugin/).
342
+
343
+ Here's how to use it:
344
+
345
+ ### Using Commands Directly
346
+
347
+ You can import and use the command functions directly from the plugin:
348
+
349
+ ```rust
350
+ use tauri_plugin_serialplugin::commands::{
351
+ available_ports, open, write, read, close, set_baud_rate,
352
+ set_data_bits, set_flow_control, set_parity, set_stop_bits, set_timeout,
353
+ write_request_to_send, write_data_terminal_ready,
354
+ read_clear_to_send, read_data_set_ready,
355
+ bytes_to_read, bytes_to_write, clear_buffer,
356
+ set_break, clear_break
357
+ };
358
+ use tauri_plugin_serialplugin::state::{DataBits, FlowControl, Parity, StopBits, ClearBuffer};
359
+ use tauri::{AppHandle, State, Runtime};
360
+ use std::collections::HashMap;
361
+
362
+ #[tauri::command]
363
+ async fn rust_serial_example(
364
+ app: AppHandle<tauri::Wry>,
365
+ serial: State<'_, tauri_plugin_serialplugin::desktop_api::SerialPort<tauri::Wry>>
366
+ ) -> Result<(), String> {
367
+ // Get available ports
368
+ let ports = available_ports(app.clone(), serial.clone())
369
+ .map_err(|e| format!("Failed to get ports: {}", e))?;
370
+ println!("Available ports: {:?}", ports);
371
+
372
+ // Open a serial port
373
+ let path = "COM1".to_string();
374
+ let baud_rate = 9600;
375
+
376
+ open(
377
+ app.clone(),
378
+ serial.clone(),
379
+ path.clone(),
380
+ baud_rate,
381
+ Some(DataBits::Eight),
382
+ Some(FlowControl::None),
383
+ Some(Parity::None),
384
+ Some(StopBits::One),
385
+ Some(1000u64) // timeout in milliseconds
386
+ ).map_err(|e| format!("Failed to open port: {}", e))?;
387
+
388
+ // Write data
389
+ let data = "Hello from Rust!".to_string();
390
+ let bytes_written = write(app.clone(), serial.clone(), path.clone(), data)
391
+ .map_err(|e| format!("Failed to write: {}", e))?;
392
+ println!("Wrote {} bytes", bytes_written);
393
+
394
+ // Read data
395
+ let received_data = read(
396
+ app.clone(),
397
+ serial.clone(),
398
+ path.clone(),
399
+ Some(1000u64), // timeout
400
+ Some(1024usize) // max bytes to read
401
+ ).map_err(|e| format!("Failed to read: {}", e))?;
402
+ println!("Received: {}", received_data);
403
+
404
+ // Configure port settings
405
+ set_baud_rate(app.clone(), serial.clone(), path.clone(), 115200)
406
+ .map_err(|e| format!("Failed to set baud rate: {}", e))?;
407
+
408
+ set_data_bits(app.clone(), serial.clone(), path.clone(), DataBits::Eight)
409
+ .map_err(|e| format!("Failed to set data bits: {}", e))?;
410
+
411
+ set_flow_control(app.clone(), serial.clone(), path.clone(), FlowControl::None)
412
+ .map_err(|e| format!("Failed to set flow control: {}", e))?;
413
+
414
+ set_parity(app.clone(), serial.clone(), path.clone(), Parity::None)
415
+ .map_err(|e| format!("Failed to set parity: {}", e))?;
416
+
417
+ set_stop_bits(app.clone(), serial.clone(), path.clone(), StopBits::One)
418
+ .map_err(|e| format!("Failed to set stop bits: {}", e))?;
419
+
420
+ // Set timeout
421
+ set_timeout(app.clone(), serial.clone(), path.clone(), 1000u64)
422
+ .map_err(|e| format!("Failed to set timeout: {}", e))?;
423
+
424
+ // Control signals
425
+ write_request_to_send(app.clone(), serial.clone(), path.clone(), true)
426
+ .map_err(|e| format!("Failed to set RTS: {}", e))?;
427
+
428
+ write_data_terminal_ready(app.clone(), serial.clone(), path.clone(), true)
429
+ .map_err(|e| format!("Failed to set DTR: {}", e))?;
430
+
431
+ // Read control signals
432
+ let cts = read_clear_to_send(app.clone(), serial.clone(), path.clone())
433
+ .map_err(|e| format!("Failed to read CTS: {}", e))?;
434
+ println!("CTS: {}", cts);
435
+
436
+ let dsr = read_data_set_ready(app.clone(), serial.clone(), path.clone())
437
+ .map_err(|e| format!("Failed to read DSR: {}", e))?;
438
+ println!("DSR: {}", dsr);
439
+
440
+ // Buffer management
441
+ let bytes_to_read = bytes_to_read(app.clone(), serial.clone(), path.clone())
442
+ .map_err(|e| format!("Failed to get bytes to read: {}", e))?;
443
+ println!("Bytes available to read: {}", bytes_to_read);
444
+
445
+ let bytes_to_write = bytes_to_write(app.clone(), serial.clone(), path.clone())
446
+ .map_err(|e| format!("Failed to get bytes to write: {}", e))?;
447
+ println!("Bytes waiting to write: {}", bytes_to_write);
448
+
449
+ // Clear buffers
450
+ clear_buffer(app.clone(), serial.clone(), path.clone(), ClearBuffer::All)
451
+ .map_err(|e| format!("Failed to clear buffer: {}", e))?;
452
+
453
+ // Break signal
454
+ set_break(app.clone(), serial.clone(), path.clone())
455
+ .map_err(|e| format!("Failed to set break: {}", e))?;
456
+
457
+ clear_break(app.clone(), serial.clone(), path.clone())
458
+ .map_err(|e| format!("Failed to clear break: {}", e))?;
459
+
460
+ // Close the port
461
+ close(app, serial, path)
462
+ .map_err(|e| format!("Failed to close port: {}", e))?;
463
+
464
+ Ok(())
465
+ }
466
+ ```
467
+
468
+ ### Advanced Rust Example with Error Handling
469
+
470
+ ```rust
471
+ use tauri_plugin_serialplugin::commands::{
472
+ available_ports, open, write, read, close, force_close, managed_ports, start_listening
473
+ };
474
+ use tauri_plugin_serialplugin::state::{DataBits, FlowControl, Parity, StopBits};
475
+ use tauri::{AppHandle, State};
476
+ use std::collections::HashMap;
477
+
478
+ #[tauri::command]
479
+ async fn advanced_serial_example(
480
+ app: AppHandle<tauri::Wry>,
481
+ serial: State<'_, tauri_plugin_serialplugin::desktop_api::SerialPort<tauri::Wry>>
482
+ ) -> Result<(), String> {
483
+ // Get available ports with error handling
484
+ let ports = match available_ports(app.clone(), serial.clone()) {
485
+ Ok(ports) => ports,
486
+ Err(e) => {
487
+ eprintln!("Failed to get available ports: {}", e);
488
+ return Err("No serial ports available".to_string());
489
+ }
490
+ };
491
+
492
+ if ports.is_empty() {
493
+ return Err("No serial ports found".to_string());
494
+ }
495
+
496
+ // Use the first available port
497
+ let port_path = ports.keys().next().unwrap().clone();
498
+ println!("Using port: {}", port_path);
499
+
500
+ // Open port with full configuration
501
+ let open_result = open(
502
+ app.clone(),
503
+ serial.clone(),
504
+ port_path.clone(),
505
+ 9600u32, // baud rate
506
+ Some(DataBits::Eight),
507
+ Some(FlowControl::None),
508
+ Some(Parity::None),
509
+ Some(StopBits::One),
510
+ Some(5000u64) // 5 second timeout
511
+ );
512
+
513
+ match open_result {
514
+ Ok(_) => println!("Port opened successfully"),
515
+ Err(e) => {
516
+ eprintln!("Failed to open port: {}", e);
517
+ return Err(format!("Failed to open port {}: {}", port_path, e));
518
+ }
519
+ }
520
+
521
+ // Start listening for data
522
+ match start_listening(
523
+ app.clone(),
524
+ serial.clone(),
525
+ port_path.clone(),
526
+ Some(1000u64), // timeout
527
+ Some(1024usize) // max bytes
528
+ ) {
529
+ Ok(_) => println!("Started listening"),
530
+ Err(e) => {
531
+ eprintln!("Failed to start listening: {}", e);
532
+ // Continue anyway, we can still read manually
533
+ }
534
+ }
535
+
536
+ // Send a command and read response
537
+ let command = "AT\r\n".to_string();
538
+ match write(app.clone(), serial.clone(), port_path.clone(), command) {
539
+ Ok(bytes) => println!("Sent {} bytes", bytes),
540
+ Err(e) => {
541
+ eprintln!("Failed to write command: {}", e);
542
+ return Err(format!("Write failed: {}", e));
543
+ }
544
+ }
545
+
546
+ // Read response with timeout
547
+ match read(
548
+ app.clone(),
549
+ serial.clone(),
550
+ port_path.clone(),
551
+ Some(2000u64), // 2 second timeout
552
+ Some(512usize) // max 512 bytes
553
+ ) {
554
+ Ok(response) => println!("Response: {}", response),
555
+ Err(e) => {
556
+ eprintln!("Failed to read response: {}", e);
557
+ return Err(format!("Read failed: {}", e));
558
+ }
559
+ }
560
+
561
+ // Get managed ports
562
+ let managed_ports = match managed_ports(app.clone(), serial.clone()) {
563
+ Ok(ports) => ports,
564
+ Err(e) => {
565
+ eprintln!("Failed to get managed ports: {}", e);
566
+ Vec::new()
567
+ }
568
+ };
569
+ println!("Managed ports: {:?}", managed_ports);
570
+
571
+ // Clean up
572
+ let cleanup_result = close(app.clone(), serial.clone(), port_path.clone());
573
+ match cleanup_result {
574
+ Ok(_) => println!("Port closed successfully"),
575
+ Err(e) => {
576
+ eprintln!("Failed to close port: {}", e);
577
+ // Try force close
578
+ if let Err(e2) = force_close(app, serial, port_path) {
579
+ eprintln!("Failed to force close port: {}", e2);
580
+ }
581
+ }
582
+ }
583
+
584
+ Ok(())
585
+ }
586
+ ```
587
+
588
+ ### Binary Data Handling in Rust
589
+
590
+ ```rust
591
+ use tauri_plugin_serialplugin::commands::{open, write_binary, read_binary, close};
592
+ use tauri_plugin_serialplugin::state::{DataBits, FlowControl, Parity, StopBits};
593
+ use tauri::{AppHandle, State};
594
+
595
+ #[tauri::command]
596
+ async fn binary_data_example(
597
+ app: AppHandle<tauri::Wry>,
598
+ serial: State<'_, tauri_plugin_serialplugin::desktop_api::SerialPort<tauri::Wry>>
599
+ ) -> Result<(), String> {
600
+ let port_path = "COM1".to_string();
601
+
602
+ // Open port
603
+ open(
604
+ app.clone(),
605
+ serial.clone(),
606
+ port_path.clone(),
607
+ 115200u32,
608
+ Some(DataBits::Eight),
609
+ Some(FlowControl::None),
610
+ Some(Parity::None),
611
+ Some(StopBits::One),
612
+ Some(1000u64)
613
+ ).map_err(|e| format!("Failed to open port: {}", e))?;
614
+
615
+ // Write binary data
616
+ let binary_data = vec![0x48, 0x65, 0x6C, 0x6C, 0x6F]; // "Hello" in ASCII
617
+ let bytes_written = write_binary(app.clone(), serial.clone(), port_path.clone(), binary_data)
618
+ .map_err(|e| format!("Failed to write binary data: {}", e))?;
619
+ println!("Wrote {} bytes of binary data", bytes_written);
620
+
621
+ // Read binary data
622
+ let received_data = read_binary(
623
+ app.clone(),
624
+ serial.clone(),
625
+ port_path.clone(),
626
+ Some(1000u64), // timeout
627
+ Some(256usize) // max bytes
628
+ ).map_err(|e| format!("Failed to read binary data: {}", e))?;
629
+
630
+ println!("Received {} bytes: {:?}", received_data.len(), received_data);
631
+
632
+ // Close port
633
+ close(app, serial, port_path)
634
+ .map_err(|e| format!("Failed to close port: {}", e))?;
635
+
636
+ Ok(())
637
+ }
638
+ ```
639
+
640
+ ### Using Commands vs Direct API
641
+
642
+ You have two ways to use the plugin in Rust:
643
+
644
+ #### Option 1: Using Commands (Recommended)
645
+
646
+ Import and use the command functions directly. These functions are documented in the [docs.rs documentation](https://docs.rs/tauri-plugin-serialplugin/):
647
+
648
+ ```rust
649
+ use tauri_plugin_serialplugin::commands::{available_ports, open, write, read, close};
650
+ use tauri::{AppHandle, State};
651
+
652
+ #[tauri::command]
653
+ async fn my_serial_function(
654
+ app: AppHandle<tauri::Wry>,
655
+ serial: State<'_, tauri_plugin_serialplugin::desktop_api::SerialPort<tauri::Wry>>
656
+ ) -> Result<(), String> {
657
+ // Use command functions
658
+ let ports = available_ports(app.clone(), serial.clone())?;
659
+ open(app.clone(), serial.clone(), "COM1".to_string(), 9600, None, None, None, None, None)?;
660
+ // ... rest of your code
661
+ }
662
+ ```
663
+
664
+ #### Option 2: Using Direct API
665
+
666
+ Use the SerialPort methods directly:
667
+
668
+ ```rust
669
+ use tauri::State;
670
+ use tauri_plugin_serialplugin::desktop_api::SerialPort;
671
+
672
+ #[tauri::command]
673
+ async fn my_serial_function(
674
+ serial: State<'_, SerialPort<tauri::Wry>>
675
+ ) -> Result<(), String> {
676
+ // Use serial methods directly
677
+ let ports = serial.available_ports()?;
678
+ // ... rest of your code
679
+ }
680
+ ```
681
+
682
+ ### Available Rust Types
683
+
684
+ The plugin provides the following Rust types for configuration:
685
+
686
+ ```rust
687
+ use tauri_plugin_serialplugin::state::{
688
+ DataBits, // Five, Six, Seven, Eight
689
+ FlowControl, // None, Software, Hardware
690
+ Parity, // None, Odd, Even
691
+ StopBits, // One, Two
692
+ ClearBuffer // Input, Output, All
693
+ };
694
+ ```
695
+
696
+ ### Complete Command Functions Reference
697
+
698
+ Here are all the available command functions you can import and use. For detailed documentation with examples, see the [docs.rs documentation](https://docs.rs/tauri-plugin-serialplugin/):
699
+
700
+ ```rust
701
+ use tauri_plugin_serialplugin::commands::{
702
+ // Port discovery
703
+ available_ports, // Get list of available ports
704
+ available_ports_direct, // Get ports using platform-specific commands
705
+ managed_ports, // Get list of currently managed ports
706
+
707
+ // Connection management
708
+ open, // Open a serial port
709
+ close, // Close a serial port
710
+ close_all, // Close all open ports
711
+ force_close, // Force close a port
712
+
713
+ // Data transfer
714
+ write, // Write string data
715
+ write_binary, // Write binary data
716
+ read, // Read string data
717
+ read_binary, // Read binary data
718
+
719
+ // Listening
720
+ start_listening, // Start listening for data
721
+ stop_listening, // Stop listening
722
+ cancel_read, // Cancel read operations
723
+
724
+ // Port configuration
725
+ set_baud_rate, // Set baud rate
726
+ set_data_bits, // Set data bits
727
+ set_flow_control, // Set flow control
728
+ set_parity, // Set parity
729
+ set_stop_bits, // Set stop bits
730
+ set_timeout, // Set timeout
731
+
732
+ // Control signals
733
+ write_request_to_send, // Set RTS signal
734
+ write_data_terminal_ready, // Set DTR signal
735
+ read_clear_to_send, // Read CTS signal
736
+ read_data_set_ready, // Read DSR signal
737
+ read_ring_indicator, // Read RI signal
738
+ read_carrier_detect, // Read CD signal
739
+
740
+ // Buffer management
741
+ bytes_to_read, // Get bytes available to read
742
+ bytes_to_write, // Get bytes waiting to write
743
+ clear_buffer, // Clear buffers
744
+
745
+ // Break signal
746
+ set_break, // Start break signal
747
+ clear_break, // Stop break signal
748
+ };
749
+ ```
750
+
751
+ ### Command Function Signatures
752
+
753
+ All command functions follow this pattern:
754
+
755
+ ```rust
756
+ pub fn function_name<R: Runtime>(
757
+ app: AppHandle<R>,
758
+ serial: State<'_, SerialPort<R>>,
759
+ // ... additional parameters specific to the function
760
+ ) -> Result<ReturnType, Error>
761
+ ```
762
+
763
+ For example:
764
+ ```rust
765
+ // Open port
766
+ pub fn open<R: Runtime>(
767
+ app: AppHandle<R>,
768
+ serial: State<'_, SerialPort<R>>,
769
+ path: String,
770
+ baud_rate: u32,
771
+ data_bits: Option<DataBits>,
772
+ flow_control: Option<FlowControl>,
773
+ parity: Option<Parity>,
774
+ stop_bits: Option<StopBits>,
775
+ timeout: Option<u64>,
776
+ ) -> Result<(), Error>
777
+
778
+ // Write data
779
+ pub fn write<R: Runtime>(
780
+ app: AppHandle<R>,
781
+ serial: State<'_, SerialPort<R>>,
782
+ path: String,
783
+ value: String,
784
+ ) -> Result<usize, Error>
785
+ ```
786
+
787
+ ### Error Messages
788
+
789
+ #### Port Discovery
790
+ - "Failed to lock serialports mutex" - Error acquiring mutex lock when listing ports
791
+ - "Invalid response format" - Invalid response format from plugin
792
+ - "Plugin error: {error}" - Plugin execution error
793
+
794
+ #### Port Management
795
+ - "Failed to acquire lock: {error}" - Error acquiring mutex lock
796
+ - "Port '{path}' not found" - Port does not exist
797
+ - "Serial port {path} is not open!" - Port is not open
798
+ - "Failed to open serial port: {error}" - Error opening port
799
+ - "Failed to clone serial port: {error}" - Error cloning port
800
+ - "Failed to set short timeout: {error}" - Error setting timeout
801
+ - "Failed to stop existing listener: {error}" - Error stopping existing listener
802
+ - "Failed to join thread: {error}" - Error waiting for thread completion
803
+ - "Failed to cancel serial port data reading: {error}" - Error canceling data reading
804
+
805
+ #### Data Operations
806
+ - "Failed to write data: {error}" - Error writing data
807
+ - "Failed to write binary data: {error}" - Error writing binary data
808
+ - "Failed to read data: {error}" - Error reading data
809
+ - "no data received within {timeout} ms" - Read timeout
810
+ - "Failed to set timeout: {error}" - Error setting timeout
811
+
812
+ #### Port Configuration
813
+ - "Failed to set baud rate: {error}" - Error setting baud rate
814
+ - "Failed to set data bits: {error}" - Error setting data bits
815
+ - "Failed to set flow control: {error}" - Error setting flow control
816
+ - "Failed to set parity: {error}" - Error setting parity
817
+ - "Failed to set stop bits: {error}" - Error setting stop bits
818
+
819
+ #### Control Signals
820
+ - "Failed to set RTS: {error}" - Error setting RTS signal
821
+ - "Failed to set DTR: {error}" - Error setting DTR signal
822
+ - "Failed to read CTS: {error}" - Error reading CTS signal
823
+ - "Failed to read DSR: {error}" - Error reading DSR signal
824
+ - "Failed to read RI: {error}" - Error reading RI signal
825
+ - "Failed to read CD: {error}" - Error reading CD signal
826
+ - "Failed to set break: {error}" - Error setting break signal
827
+ - "Failed to clear break: {error}" - Error clearing break signal
828
+
829
+ #### Buffer Management
830
+ - "Failed to clear buffer: {error}" - Error clearing buffer
831
+ - "Failed to get bytes to read: {error}" - Error getting bytes available to read
832
+ - "Failed to get bytes to write: {error}" - Error getting bytes waiting to write
833
+
834
+ ---
835
+
836
+ ## Permissions
837
+
838
+ Below is a list of all permissions the plugin supports. Granting or denying them allows fine-grained control over what your application can do with serial ports.
839
+
840
+ | Permission | Description |
841
+ |---------------------------------------------|-------------------------------------------------------------------------------|
842
+ | `serialplugin:allow-available-ports` | Allows listing of available serial ports |
843
+ | `serialplugin:deny-available-ports` | Denies listing of available serial ports |
844
+ | `serialplugin:allow-cancel-read` | Allows canceling of read operations |
845
+ | `serialplugin:deny-cancel-read` | Denies canceling of read operations |
846
+ | `serialplugin:allow-close` | Allows closing of serial ports |
847
+ | `serialplugin:deny-close` | Denies closing of serial ports |
848
+ | `serialplugin:allow-close-all` | Allows closing of all open serial ports |
849
+ | `serialplugin:deny-close-all` | Denies closing of all open serial ports |
850
+ | `serialplugin:allow-force-close` | Allows forcefully closing of serial ports |
851
+ | `serialplugin:deny-force-close` | Denies forcefully closing of serial ports |
852
+ | `serialplugin:allow-open` | Allows opening of serial ports |
853
+ | `serialplugin:deny-open` | Denies opening of serial ports |
854
+ | `serialplugin:allow-read` | Allows reading data from serial ports |
855
+ | `serialplugin:deny-read` | Denies reading data from serial ports |
856
+ | `serialplugin:allow-read-binary` | Allows reading binary data from serial ports |
857
+ | `serialplugin:deny-read-binary` | Denies reading binary data from serial ports |
858
+ | `serialplugin:allow-write` | Allows writing data to serial ports |
859
+ | `serialplugin:deny-write` | Denies writing data to serial ports |
860
+ | `serialplugin:allow-write-binary` | Allows writing binary data to serial ports |
861
+ | `serialplugin:deny-write-binary` | Denies writing binary data to serial ports |
862
+ | `serialplugin:allow-available-ports-direct` | Enables the `available_ports_direct` command without any pre-configured scope |
863
+ | `serialplugin:deny-available-ports-direct` | Denies the `available_ports_direct` command without any pre-configured scope |
864
+ | `serialplugin:allow-set-baud-rate` | Allows changing the baud rate of serial ports |
865
+ | `serialplugin:deny-set-baud-rate` | Denies changing the baud rate of serial ports |
866
+ | `serialplugin:allow-set-data-bits` | Allows changing the data bits configuration |
867
+ | `serialplugin:deny-set-data-bits` | Denies changing the data bits configuration |
868
+ | `serialplugin:allow-set-flow-control` | Allows changing the flow control mode |
869
+ | `serialplugin:deny-set-flow-control` | Denies changing the flow control mode |
870
+ | `serialplugin:allow-set-parity` | Allows changing the parity checking mode |
871
+ | `serialplugin:deny-set-parity` | Denies changing the parity checking mode |
872
+ | `serialplugin:allow-set-stop-bits` | Allows changing the stop bits configuration |
873
+ | `serialplugin:deny-set-stop-bits` | Denies changing the stop bits configuration |
874
+ | `serialplugin:allow-set-timeout` | Allows changing the timeout duration |
875
+ | `serialplugin:deny-set-timeout` | Denies changing the timeout duration |
876
+ | `serialplugin:allow-write-rts` | Allows setting the RTS (Request To Send) control signal |
877
+ | `serialplugin:deny-write-rts` | Denies setting the RTS control signal |
878
+ | `serialplugin:allow-write-dtr` | Allows setting the DTR (Data Terminal Ready) control signal |
879
+ | `serialplugin:deny-write-dtr` | Denies setting the DTR control signal |
880
+ | `serialplugin:allow-read-cts` | Allows reading the CTS (Clear To Send) control signal state |
881
+ | `serialplugin:deny-read-cts` | Denies reading the CTS control signal state |
882
+ | `serialplugin:allow-read-dsr` | Allows reading the DSR (Data Set Ready) control signal state |
883
+ | `serialplugin:deny-read-dsr` | Denies reading the DSR control signal state |
884
+ | `serialplugin:allow-read-ri` | Allows reading the RI (Ring Indicator) control signal state |
885
+ | `serialplugin:deny-read-ri` | Denies reading the RI control signal state |
886
+ | `serialplugin:allow-read-cd` | Allows reading the CD (Carrier Detect) control signal state |
887
+ | `serialplugin:deny-read-cd` | Denies reading the CD control signal state |
888
+ | `serialplugin:allow-bytes-to-read` | Allows checking the number of bytes available to read |
889
+ | `serialplugin:deny-bytes-to-read` | Denies checking the number of bytes available to read |
890
+ | `serialplugin:allow-bytes-to-write` | Allows checking the number of bytes waiting to be written |
891
+ | `serialplugin:deny-bytes-to-write` | Denies checking the number of bytes waiting to be written |
892
+ | `serialplugin:allow-clear-buffer` | Allows clearing input/output buffers |
893
+ | `serialplugin:deny-clear-buffer` | Denies clearing input/output buffers |
894
+ | `serialplugin:allow-set-break` | Allows starting break signal transmission |
895
+ | `serialplugin:deny-set-break` | Denies starting break signal transmission |
896
+ | `serialplugin:allow-clear-break` | Allows stopping break signal transmission |
897
+ | `serialplugin:deny-clear-break` | Denies stopping break signal transmission |
898
+ | `serialplugin:allow-start-listening` | Allows starting automatic port monitoring and data listening |
899
+ | `serialplugin:deny-start-listening` | Denies starting automatic port monitoring and data listening |
900
+ | `serialplugin:allow-stop-listening` | Allows stopping automatic port monitoring and data listening |
901
+ | `serialplugin:deny-stop-listening` | Denies stopping automatic port monitoring and data listening |
902
+
903
+ ### Granting All Permissions (Example)
904
+
905
+ ```jsonc
906
+ "permissions": [
907
+ "core:default",
908
+ "serialplugin:default",
909
+ "serialplugin:allow-available-ports",
910
+ "serialplugin:allow-cancel-read",
911
+ "serialplugin:allow-close",
912
+ "serialplugin:allow-close-all",
913
+ "serialplugin:allow-force-close",
914
+ "serialplugin:allow-open",
915
+ "serialplugin:allow-read",
916
+ "serialplugin:allow-write",
917
+ "serialplugin:allow-write-binary",
918
+ "serialplugin:allow-available-ports-direct",
919
+ "serialplugin:allow-set-baud-rate",
920
+ "serialplugin:allow-set-data-bits",
921
+ "serialplugin:allow-set-flow-control",
922
+ "serialplugin:allow-set-parity",
923
+ "serialplugin:allow-set-stop-bits",
924
+ "serialplugin:allow-set-timeout",
925
+ "serialplugin:allow-write-rts",
926
+ "serialplugin:allow-write-dtr",
927
+ "serialplugin:allow-read-cts",
928
+ "serialplugin:allow-read-dsr",
929
+ "serialplugin:allow-read-ri",
930
+ "serialplugin:allow-read-cd",
931
+ "serialplugin:allow-bytes-to-read",
932
+ "serialplugin:allow-bytes-to-write",
933
+ "serialplugin:allow-clear-buffer",
934
+ "serialplugin:allow-set-break",
935
+ "serialplugin:allow-clear-break",
936
+ "serialplugin:allow-start-listening",
937
+ "serialplugin:allow-stop-listening"
938
+ ]
939
+ ```
940
+
941
+ ---
942
+
943
+ ## API Reference
944
+
945
+ ### Port Discovery
946
+
947
+ ```typescript
948
+ class SerialPort {
949
+ /**
950
+ * Lists all available serial ports on the system
951
+ * @returns {Promise<{[key: string]: PortInfo}>} Map of port names to port information
952
+ * @example
953
+ * const ports = await SerialPort.available_ports();
954
+ * console.log(ports);
955
+ */
956
+ static async available_ports(): Promise<{ [key: string]: PortInfo }>;
957
+
958
+ /**
959
+ * Lists ports using platform-specific commands for enhanced detection
960
+ * @returns {Promise<{[key: string]: PortInfo}>} Map of port names to port information
961
+ * @example
962
+ * const ports = await SerialPort.available_ports_direct();
963
+ */
964
+ static async available_ports_direct(): Promise<{ [key: string]: PortInfo }>;
965
+
966
+ /**
967
+ * @description Lists all managed serial ports (ports that are currently open and managed by the application).
968
+ * @returns {Promise<string[]>} A promise that resolves to an array of port paths (names).
969
+ */
970
+ static async managed_ports(): Promise<string[]>;
971
+ }
972
+ ```
973
+
974
+ ### Connection Management
975
+
976
+ ```typescript
977
+ class SerialPort {
978
+ /**
979
+ * Opens the serial port with specified configuration
980
+ * @returns {Promise<void>}
981
+ * @throws {Error} If port is already open or invalid configuration
982
+ * @example
983
+ * const port = new SerialPort({ path: "COM1", baudRate: 9600 });
984
+ * await port.open();
985
+ */
986
+ async open(): Promise<void>;
987
+
988
+ /**
989
+ * Closes the serial port connection
990
+ * @returns {Promise<void>}
991
+ * @throws {Error} If port is not open
992
+ * @example
993
+ * await port.close();
994
+ */
995
+ async close(): Promise<void>;
996
+
997
+ /**
998
+ * Starts listening for data on the serial port
999
+ * @returns {Promise<void>} A promise that resolves when listening starts
1000
+ * @throws {Error} If starting listener fails or port is not open
1001
+ * @example
1002
+ * await port.startListening();
1003
+ *
1004
+ * // Listen for data events
1005
+ * port.listen((data) => {
1006
+ * console.log("Data received:", data);
1007
+ * });
1008
+ */
1009
+ async startListening(): Promise<void>;
1010
+
1011
+ /**
1012
+ * Stops listening for data on the serial port
1013
+ * @returns {Promise<void>} A promise that resolves when listening stops
1014
+ * @throws {Error} If stopping listener fails or port is not open
1015
+ * @example
1016
+ * await port.stopListening();
1017
+ */
1018
+ async stopListening(): Promise<void>;
1019
+
1020
+ /**
1021
+ * Forces a serial port to close regardless of its state
1022
+ * @param {string} path Port path to force close
1023
+ * @returns {Promise<void>}
1024
+ * @example
1025
+ * await SerialPort.forceClose("COM1");
1026
+ */
1027
+ static async forceClose(path: string): Promise<void>;
1028
+
1029
+ /**
1030
+ * Closes all open serial port connections
1031
+ * @returns {Promise<void>}
1032
+ * @example
1033
+ * await SerialPort.closeAll();
1034
+ */
1035
+ static async closeAll(): Promise<void>;
1036
+ }
1037
+ ```
1038
+
1039
+ ### Data Transfer
1040
+
1041
+ ```typescript
1042
+ class SerialPort {
1043
+ /**
1044
+ * Writes string data to the serial port
1045
+ * @param {string} data Data to write
1046
+ * @returns {Promise<number>} Number of bytes written
1047
+ * @throws {Error} If write fails or port is not open
1048
+ * @example
1049
+ * const bytesWritten = await port.write("Hello");
1050
+ */
1051
+ async write(data: string): Promise<number>;
1052
+
1053
+ /**
1054
+ * Reads data from the serial port
1055
+ * @param {ReadOptions} [options] Read options
1056
+ * @returns {Promise<string>} A promise that resolves to a string
1057
+ */
1058
+ async read(options?: ReadOptions): Promise<string>;
1059
+
1060
+ /**
1061
+ * Reads binary data from the serial port
1062
+ * @param {ReadOptions} [options] Read options
1063
+ * @returns {Promise<Uint8Array>} A promise that resolves with binary data
1064
+ */
1065
+ async readBinary(options?: ReadOptions): Promise<Uint8Array>;
1066
+
1067
+ /**
1068
+ * Writes binary data to the serial port
1069
+ * @param {Uint8Array | number[]} data Binary data to write
1070
+ * @returns {Promise<number>} Number of bytes written
1071
+ * @throws {Error} If write fails or port is not open
1072
+ * @example
1073
+ * const data = new Uint8Array([0x01, 0x02, 0x03]);
1074
+ * const bytesWritten = await port.writeBinary(data);
1075
+ */
1076
+ async writeBinary(data: Uint8Array | number[]): Promise<number>;
1077
+
1078
+ /**
1079
+ * Sets up a listener for incoming data
1080
+ * @param {(data: string | Uint8Array) => void} callback Function to handle received data
1081
+ * @param {boolean} [decode=true] Whether to decode data as string (true) or return raw bytes (false)
1082
+ * @returns {Promise<UnlistenFn>} A promise that resolves to an unlisten function
1083
+ * @example
1084
+ * const unsubscribe = await port.listen((data) => {
1085
+ * console.log("Received:", data);
1086
+ * });
1087
+ *
1088
+ * // Later, to stop listening:
1089
+ * unsubscribe();
1090
+ */
1091
+ async listen(callback: (data: string | Uint8Array) => void, decode?: boolean): Promise<UnlistenFn>;
1092
+
1093
+ /**
1094
+ * Cancels listening for serial port data (does not affect disconnect listeners)
1095
+ * @returns {Promise<void>} A promise that resolves when listening is cancelled
1096
+ * @example
1097
+ * await port.cancelListen();
1098
+ */
1099
+ async cancelListen(): Promise<void>;
1100
+ }
1101
+ ```
1102
+
1103
+ ### Port Configuration
1104
+
1105
+ ```typescript
1106
+ class SerialPort {
1107
+ /**
1108
+ * Sets the baud rate
1109
+ * @param {number} baudRate Speed in bits per second
1110
+ * @returns {Promise<void>}
1111
+ * @example
1112
+ * await port.setBaudRate(115200);
1113
+ */
1114
+ async setBaudRate(baudRate: number): Promise<void>;
1115
+
1116
+ /**
1117
+ * Sets the number of data bits
1118
+ * @param {DataBits} dataBits Number of bits per character (5-8)
1119
+ * @returns {Promise<void>}
1120
+ * @example
1121
+ * await port.setDataBits(DataBits.Eight);
1122
+ */
1123
+ async setDataBits(dataBits: DataBits): Promise<void>;
1124
+
1125
+ /**
1126
+ * Sets the flow control mode
1127
+ * @param {FlowControl} flowControl Flow control setting
1128
+ * @returns {Promise<void>}
1129
+ * @example
1130
+ * await port.setFlowControl(FlowControl.Hardware);
1131
+ */
1132
+ async setFlowControl(flowControl: FlowControl): Promise<void>;
1133
+
1134
+ /**
1135
+ * Sets the parity checking mode
1136
+ * @param {Parity} parity Parity checking mode
1137
+ * @returns {Promise<void>}
1138
+ * @example
1139
+ * await port.setParity(Parity.None);
1140
+ */
1141
+ async setParity(parity: Parity): Promise<void>;
1142
+
1143
+ /**
1144
+ * Sets the number of stop bits
1145
+ * @param {StopBits} stopBits Number of stop bits
1146
+ * @returns {Promise<void>}
1147
+ * @example
1148
+ * await port.setStopBits(StopBits.One);
1149
+ */
1150
+ async setStopBits(stopBits: StopBits): Promise<void>;
1151
+
1152
+ /**
1153
+ * Sets the timeout for read operations
1154
+ * @param {number} timeout Timeout value in milliseconds
1155
+ * @returns {Promise<void>}
1156
+ * @example
1157
+ * await port.setTimeout(1000);
1158
+ */
1159
+ async setTimeout(timeout: number): Promise<void>;
1160
+ }
1161
+ ```
1162
+
1163
+ ### Control Signals
1164
+
1165
+ ```typescript
1166
+ class SerialPort {
1167
+ /**
1168
+ * Sets the RTS (Request to Send) signal
1169
+ * @param {boolean} level Signal level (true = high, false = low)
1170
+ * @returns {Promise<void>}
1171
+ * @example
1172
+ * await port.writeRequestToSend(true);
1173
+ */
1174
+ async writeRequestToSend(level: boolean): Promise<void>;
1175
+
1176
+ /**
1177
+ * Sets the DTR (Data Terminal Ready) signal
1178
+ * @param {boolean} level Signal level (true = high, false = low)
1179
+ * @returns {Promise<void>}
1180
+ * @example
1181
+ * await port.writeDataTerminalReady(true);
1182
+ */
1183
+ async writeDataTerminalReady(level: boolean): Promise<void>;
1184
+
1185
+ /**
1186
+ * Alternative method to set RTS signal
1187
+ * @param {boolean} value Signal level (true = high, false = low)
1188
+ * @returns {Promise<void>}
1189
+ * @example
1190
+ * await port.setRequestToSend(true);
1191
+ */
1192
+ async setRequestToSend(value: boolean): Promise<void>;
1193
+
1194
+ /**
1195
+ * Alternative method to set DTR signal
1196
+ * @param {boolean} value Signal level (true = high, false = low)
1197
+ * @returns {Promise<void>}
1198
+ * @example
1199
+ * await port.setDataTerminalReady(true);
1200
+ */
1201
+ async setDataTerminalReady(value: boolean): Promise<void>;
1202
+
1203
+ /**
1204
+ * Reads the CTS (Clear to Send) signal state
1205
+ * @returns {Promise<boolean>} Signal state
1206
+ * @example
1207
+ * const cts = await port.readClearToSend();
1208
+ */
1209
+ async readClearToSend(): Promise<boolean>;
1210
+
1211
+ /**
1212
+ * Reads the DSR (Data Set Ready) signal state
1213
+ * @returns {Promise<boolean>} Signal state
1214
+ * @example
1215
+ * const dsr = await port.readDataSetReady();
1216
+ */
1217
+ async readDataSetReady(): Promise<boolean>;
1218
+
1219
+ /**
1220
+ * Reads the RI (Ring Indicator) signal state
1221
+ * @returns {Promise<boolean>} Signal state
1222
+ * @example
1223
+ * const ri = await port.readRingIndicator();
1224
+ */
1225
+ async readRingIndicator(): Promise<boolean>;
1226
+
1227
+ /**
1228
+ * Reads the CD (Carrier Detect) signal state
1229
+ * @returns {Promise<boolean>} Signal state
1230
+ * @example
1231
+ * const cd = await port.readCarrierDetect();
1232
+ */
1233
+ async readCarrierDetect(): Promise<boolean>;
1234
+ }
1235
+ ```
1236
+
1237
+ ### Buffer Management
1238
+
1239
+ ```typescript
1240
+ class SerialPort {
1241
+ /**
1242
+ * Gets number of bytes available to read
1243
+ * @returns {Promise<number>} Number of bytes in read buffer
1244
+ * @example
1245
+ * const available = await port.bytesToRead();
1246
+ */
1247
+ async bytesToRead(): Promise<number>;
1248
+
1249
+ /**
1250
+ * Gets number of bytes waiting to be written
1251
+ * @returns {Promise<number>} Number of bytes in write buffer
1252
+ * @example
1253
+ * const pending = await port.bytesToWrite();
1254
+ */
1255
+ async bytesToWrite(): Promise<number>;
1256
+
1257
+ /**
1258
+ * Clears the specified buffer
1259
+ * @param {ClearBuffer} buffer Buffer to clear
1260
+ * @returns {Promise<void>}
1261
+ * @example
1262
+ * await port.clearBuffer(ClearBuffer.Input);
1263
+ */
1264
+ async clearBuffer(buffer: ClearBuffer): Promise<void>;
1265
+
1266
+ /**
1267
+ * Sets the break signal
1268
+ * @returns {Promise<void>}
1269
+ * @example
1270
+ * await port.setBreak();
1271
+ */
1272
+ async setBreak(): Promise<void>;
1273
+
1274
+ /**
1275
+ * Clears the break signal
1276
+ * @returns {Promise<void>}
1277
+ * @example
1278
+ * await port.clearBreak();
1279
+ */
1280
+ async clearBreak(): Promise<void>;
1281
+ }
1282
+ ```
1283
+
1284
+ ### Auto-Reconnect Management
1285
+
1286
+ ```typescript
1287
+ class SerialPort {
1288
+ /**
1289
+ * Enables auto-reconnect functionality
1290
+ * @param {Object} options Auto-reconnect configuration options
1291
+ * @param {number} [options.interval=5000] Reconnection interval in milliseconds
1292
+ * @param {number | null} [options.maxAttempts=10] Maximum number of reconnection attempts (null for infinite)
1293
+ * @param {Function} [options.onReconnect] Callback function called on each reconnection attempt
1294
+ * @returns {Promise<void>}
1295
+ * @example
1296
+ * await port.enableAutoReconnect({
1297
+ * interval: 3000,
1298
+ * maxAttempts: 5,
1299
+ * onReconnect: (success, attempt) => {
1300
+ * console.log(`Reconnect attempt ${attempt}: ${success ? 'success' : 'failed'}`);
1301
+ * }
1302
+ * });
1303
+ */
1304
+ async enableAutoReconnect(options?: {
1305
+ interval?: number;
1306
+ maxAttempts?: number | null;
1307
+ onReconnect?: (success: boolean, attempt: number) => void;
1308
+ }): Promise<void>;
1309
+
1310
+ /**
1311
+ * Disables auto-reconnect functionality
1312
+ * @returns {Promise<void>}
1313
+ * @example
1314
+ * await port.disableAutoReconnect();
1315
+ */
1316
+ async disableAutoReconnect(): Promise<void>;
1317
+
1318
+ /**
1319
+ * Gets auto-reconnect status and configuration
1320
+ * @returns {Object} Auto-reconnect information
1321
+ * @example
1322
+ * const info = port.getAutoReconnectInfo();
1323
+ * console.log('Auto-reconnect enabled:', info.enabled);
1324
+ * console.log('Current attempts:', info.currentAttempts);
1325
+ */
1326
+ getAutoReconnectInfo(): {
1327
+ enabled: boolean;
1328
+ interval: number;
1329
+ maxAttempts: number | null;
1330
+ currentAttempts: number;
1331
+ hasCallback: boolean;
1332
+ };
1333
+
1334
+ /**
1335
+ * Manually triggers a reconnection attempt
1336
+ * @returns {Promise<boolean>} A promise that resolves to true if reconnection was successful
1337
+ * @example
1338
+ * const success = await port.manualReconnect();
1339
+ * if (success) {
1340
+ * console.log('Manual reconnection successful');
1341
+ * }
1342
+ */
1343
+ async manualReconnect(): Promise<boolean>;
1344
+ }
1345
+ ```
1346
+
1347
+ ## Common Use Cases
1348
+
1349
+ ### Reading Sensor Data
1350
+
1351
+ ```typescript
1352
+ const port = new SerialPort({
1353
+ path: "COM1",
1354
+ baudRate: 9600
1355
+ });
1356
+
1357
+ await port.open();
1358
+ await port.listen((data) => {
1359
+ const sensorValue = parseFloat(data);
1360
+ console.log("Sensor reading:", sensorValue);
1361
+ });
1362
+ ```
1363
+
1364
+ ### Binary Protocol Communication
1365
+
1366
+ ```typescript
1367
+ const port = new SerialPort({
1368
+ path: "COM1",
1369
+ baudRate: 115200
1370
+ });
1371
+
1372
+ await port.open();
1373
+
1374
+ // Send command
1375
+ const command = new Uint8Array([0x02, 0x01, 0x03]);
1376
+ await port.writeBinary(command);
1377
+
1378
+ // Read response (raw bytes)
1379
+ await port.listen((data) => {
1380
+ const response = data instanceof Uint8Array ? data : new Uint8Array();
1381
+ console.log("Response:", response);
1382
+ }, false);
1383
+ ```
1384
+
1385
+ ### Modbus Communication
1386
+
1387
+ ```typescript
1388
+ const port = new SerialPort({
1389
+ path: "COM1",
1390
+ baudRate: 9600,
1391
+ dataBits: DataBits.Eight,
1392
+ stopBits: StopBits.One,
1393
+ parity: Parity.None
1394
+ });
1395
+
1396
+ await port.open();
1397
+
1398
+ function createModbusRequest(address: number, length: number): Uint8Array {
1399
+ return new Uint8Array([
1400
+ 0x01, // Device ID
1401
+ 0x03, // Function code: Read Holding Registers
1402
+ address >> 8, address & 0xFF,
1403
+ length >> 8, length & 0xFF
1404
+ ]);
1405
+ }
1406
+
1407
+ // Send Modbus request
1408
+ const request = createModbusRequest(0x1000, 10);
1409
+ await port.writeBinary(request);
1410
+ ```
1411
+
1412
+ ### Auto-Reconnect for Reliable Communication
1413
+
1414
+ ```typescript
1415
+ const port = new SerialPort({
1416
+ path: "COM1",
1417
+ baudRate: 9600
1418
+ });
1419
+
1420
+ await port.open();
1421
+
1422
+ // Enable auto-reconnect with custom settings
1423
+ await port.enableAutoReconnect({
1424
+ interval: 3000, // Try to reconnect every 3 seconds
1425
+ maxAttempts: 5, // Maximum 5 attempts
1426
+ onReconnect: (success, attempt) => {
1427
+ if (success) {
1428
+ console.log(`Reconnected successfully on attempt ${attempt}`);
1429
+ } else {
1430
+ console.log(`Reconnection attempt ${attempt} failed`);
1431
+ }
1432
+ }
1433
+ });
1434
+
1435
+ // Set up data listener
1436
+ const unsubscribe = await port.listen((data) => {
1437
+ console.log("Received data:", data);
1438
+ });
1439
+
1440
+ // The port will automatically reconnect if disconnected
1441
+ // You can also manually trigger reconnection
1442
+ const success = await port.manualReconnect();
1443
+ if (success) {
1444
+ console.log("Manual reconnection successful");
1445
+ }
1446
+
1447
+ // Check auto-reconnect status
1448
+ const info = port.getAutoReconnectInfo();
1449
+ console.log("Auto-reconnect enabled:", info.enabled);
1450
+ console.log("Current attempts:", info.currentAttempts);
1451
+
1452
+ // Disable auto-reconnect when no longer needed
1453
+ await port.disableAutoReconnect();
1454
+ ```
1455
+
1456
+ ---
1457
+
1458
+ ## Android Setup
1459
+
1460
+ To use this plugin on Android, you need to add the JitPack repository to your project's `build.gradle.kts` file located at `/src-tauri/gen/android/build.gradle.kts`. Below is an example of how to configure it:
1461
+
1462
+ ```kotlin
1463
+ buildscript {
1464
+ repositories {
1465
+ // ...
1466
+ maven { url = uri("https://jitpack.io") }
1467
+ }
1468
+ // ...
1469
+ }
1470
+
1471
+ allprojects {
1472
+ repositories {
1473
+ // ...
1474
+ maven { url = uri("https://jitpack.io") }
1475
+ }
1476
+ }
1477
+ ```
1478
+
1479
+ ---
1480
+
1481
+ ## Contributing
1482
+
1483
+ Pull requests are welcome! Please read our contributing guidelines before you start.
1484
+
1485
+ ---
1486
+
1487
+ ## Development Setup
1488
+
1489
+ ```bash
1490
+ git clone https://github.com/s00d/tauri-plugin-serialplugin.git
1491
+ cd tauri-plugin-serialplugin
1492
+
1493
+ pnpm i
1494
+ pnpm run build
1495
+ pnpm run playground
1496
+ ```
1497
+
1498
+ ## Testing
1499
+
1500
+ For testing applications without physical hardware, you can use a mock implementation of the serial port. The mock port emulates all functions of a real port and allows testing the application without physical devices.
1501
+
1502
+ ### Using Mock Port
1503
+
1504
+ ```rust
1505
+ use tauri_plugin_serialplugin::tests::mock::MockSerialPort;
1506
+
1507
+ // Create a mock port
1508
+ let mock_port = MockSerialPort::new();
1509
+
1510
+ // Configure port settings
1511
+ mock_port.set_baud_rate(9600).unwrap();
1512
+ mock_port.set_data_bits(serialport::DataBits::Eight).unwrap();
1513
+ mock_port.set_flow_control(serialport::FlowControl::None).unwrap();
1514
+ mock_port.set_parity(serialport::Parity::None).unwrap();
1515
+ mock_port.set_stop_bits(serialport::StopBits::One).unwrap();
1516
+
1517
+ // Write data
1518
+ mock_port.write("Test data".as_bytes()).unwrap();
1519
+
1520
+ // Read data
1521
+ let mut buffer = [0u8; 1024];
1522
+ let bytes_read = mock_port.read(&mut buffer).unwrap();
1523
+ let data = String::from_utf8_lossy(&buffer[..bytes_read]);
1524
+ assert_eq!(data, "Test data");
1525
+ ```
1526
+
1527
+ ### Mock Port Features
1528
+
1529
+ - Complete emulation of all real port functions
1530
+ - Built-in buffer for data storage
1531
+ - Control signal emulation (RTS, DTR, CTS, DSR)
1532
+ - Support for parallel operation testing
1533
+ - No additional software required
1534
+ - Works on all platforms
1535
+
1536
+ ### Application Testing Example
1537
+
1538
+ ```rust
1539
+ #[test]
1540
+ fn test_serial_communication() {
1541
+ let app = create_test_app();
1542
+ let serial_port = SerialPort::new(app.handle().clone());
1543
+ app.manage(serial_port);
1544
+
1545
+ // Open mock port
1546
+ app.state::<SerialPort<MockRuntime>>().open(
1547
+ "COM1".to_string(),
1548
+ 9600,
1549
+ Some(DataBits::Eight),
1550
+ Some(FlowControl::None),
1551
+ Some(Parity::None),
1552
+ Some(StopBits::One),
1553
+ Some(1000),
1554
+ ).unwrap();
1555
+
1556
+ // Test write and read operations
1557
+ app.state::<SerialPort<MockRuntime>>().write(
1558
+ "COM1".to_string(),
1559
+ "Test data".to_string(),
1560
+ ).unwrap();
1561
+
1562
+ let data = app.state::<SerialPort<MockRuntime>>().read(
1563
+ "COM1".to_string(),
1564
+ Some(1000),
1565
+ Some(1024),
1566
+ ).unwrap();
1567
+ assert_eq!(data, "Test data");
1568
+
1569
+ // Test port settings
1570
+ app.state::<SerialPort<MockRuntime>>().set_baud_rate(
1571
+ "COM1".to_string(),
1572
+ 115200,
1573
+ ).unwrap();
1574
+
1575
+ // Close port
1576
+ app.state::<SerialPort<MockRuntime>>().close("COM1".to_string()).unwrap();
1577
+ }
1578
+ ```
1579
+
1580
+ ### Implementing Your Own Mock Port
1581
+
1582
+ You can implement your own mock port by implementing the `SerialPort` trait. Here's a basic example of how to create a custom mock port:
1583
+
1584
+ ```rust
1585
+ use std::io::{self, Read, Write};
1586
+ use serialport::{self, SerialPort};
1587
+ use std::time::Duration;
1588
+
1589
+ struct CustomMockPort {
1590
+ buffer: Vec<u8>,
1591
+ baud_rate: u32,
1592
+ data_bits: serialport::DataBits,
1593
+ flow_control: serialport::FlowControl,
1594
+ parity: serialport::Parity,
1595
+ stop_bits: serialport::StopBits,
1596
+ timeout: Duration,
1597
+ }
1598
+
1599
+ impl CustomMockPort {
1600
+ fn new() -> Self {
1601
+ Self {
1602
+ buffer: Vec::new(),
1603
+ baud_rate: 9600,
1604
+ data_bits: serialport::DataBits::Eight,
1605
+ flow_control: serialport::FlowControl::None,
1606
+ parity: serialport::Parity::None,
1607
+ stop_bits: serialport::StopBits::One,
1608
+ timeout: Duration::from_millis(1000),
1609
+ }
1610
+ }
1611
+ }
1612
+
1613
+ // Implement Read trait for reading data
1614
+ impl Read for CustomMockPort {
1615
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1616
+ let len = std::cmp::min(buf.len(), self.buffer.len());
1617
+ if len > 0 {
1618
+ buf[..len].copy_from_slice(&self.buffer[..len]);
1619
+ self.buffer.drain(..len);
1620
+ }
1621
+ Ok(len)
1622
+ }
1623
+ }
1624
+
1625
+ // Implement Write trait for writing data
1626
+ impl Write for CustomMockPort {
1627
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1628
+ self.buffer.extend_from_slice(buf);
1629
+ Ok(buf.len())
1630
+ }
1631
+
1632
+ fn flush(&mut self) -> io::Result<()> {
1633
+ Ok(())
1634
+ }
1635
+ }
1636
+
1637
+ // Implement SerialPort trait for port configuration
1638
+ impl SerialPort for CustomMockPort {
1639
+ fn name(&self) -> Option<String> {
1640
+ Some("CUSTOM_PORT".to_string())
1641
+ }
1642
+
1643
+ fn baud_rate(&self) -> serialport::Result<u32> {
1644
+ Ok(self.baud_rate)
1645
+ }
1646
+
1647
+ fn data_bits(&self) -> serialport::Result<serialport::DataBits> {
1648
+ Ok(self.data_bits)
1649
+ }
1650
+
1651
+ // ... implement other required methods ...
1652
+ }
1653
+ ```
1654
+
1655
+ For a complete implementation example, see the mock port implementation in the plugin's test directory:
1656
+ [`src/tests/mock.rs`](https://github.com/s00d/tauri-plugin-serialplugin/blob/main/src/tests/mock.rs)
1657
+
1658
+ The example includes:
1659
+ - Full implementation of all required traits
1660
+ - Buffer management for read/write operations
1661
+ - Control signal emulation
1662
+ - Port configuration handling
1663
+ - Error handling
1664
+ - Thread safety considerations
1665
+
1666
+ You can use this implementation as a reference when creating your own mock port with custom behavior for specific testing scenarios.
1667
+
1668
+ ---
1669
+
1670
+ ## Partners
1671
+
1672
+ If you find this plugin valuable and would like to support further development, feel free to donate via [DonationAlerts](https://www.donationalerts.com/r/s00d88). Any contribution is greatly appreciated!
1673
+
1674
+ ---
1675
+
1676
+ ## License
1677
+
1678
+ This code is dual-licensed under MIT or Apache-2.0, where applicable, © 2019–2025 Tauri Programme within The Commons Conservancy.