### Set FlowControl Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Example of opening a serial port and configuring hardware flow control. ```rust use serial2_tokio::{SerialPort, FlowControl}; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_flow_control(FlowControl::Hardware); Ok(settings) })?; ``` -------------------------------- ### Complete Buffer Management Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md A comprehensive example showing buffer clearing, sending a command, and receiving a response using vectored reads if supported, with a fallback to a single buffer read. ```rust use std::io::IoSliceMut; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Before starting, ensure a clean slate port.discard_buffers()?; println!("Buffers cleared"); // Send a command port.write_all(b"*IDN?\r\n").await?; // Receive response into multiple buffers let mut header_buf = [0u8; 32]; let mut body_buf = [0u8; 512]; if port.is_read_vectored() { let mut bufs = [ IoSliceMut::new(&mut header_buf), IoSliceMut::new(&mut body_buf), ]; let n = port.read_vectored(&mut bufs).await?; println!("Read {} bytes across multiple buffers", n); } else { // Fallback for platforms without vectored read support let n = port.read(&mut header_buf).await?; println!("Read {} bytes into header buffer", n); } Ok(()) } ``` -------------------------------- ### Set StopBits Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Example of opening a serial port and configuring it to use one stop bit. ```rust use serial2_tokio::{SerialPort, StopBits}; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_stop_bits(StopBits::One); Ok(settings) })?; ``` -------------------------------- ### Set Parity Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Example of opening a serial port and setting the parity check to Even. ```rust use serial2_tokio::{SerialPort, Parity}; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_parity(Parity::Even); Ok(settings) })?; ``` -------------------------------- ### Complete Buffer Management Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md An example demonstrating complete buffer management, including clearing buffers, sending a command, and receiving a response into multiple buffers using vectored reads if supported, with a fallback to single buffer reads. ```APIDOC ## Complete Buffer Management Example ### Description This example showcases a comprehensive buffer management workflow for a serial port. It includes clearing existing buffers, sending a command, and then attempting to read the response into multiple buffers using `read_vectored` if the platform supports it. If vectored reads are not supported, it falls back to reading into a single buffer. ### Code ```rust use std::io::IoSliceMut; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Before starting, ensure a clean slate port.discard_buffers()?; println!("Buffers cleared"); // Send a command port.write_all(b"*IDN?\r\n").await?; // Receive response into multiple buffers let mut header_buf = [0u8; 32]; let mut body_buf = [0u8; 512]; if port.is_read_vectored() { let mut bufs = [ IoSliceMut::new(&mut header_buf), IoSliceMut::new(&mut body_buf), ]; let n = port.read_vectored(&mut bufs).await?; println!("Read {} bytes across multiple buffers", n); } else { // Fallback for platforms without vectored read support let n = port.read(&mut header_buf).await?; println!("Read {} bytes into header buffer", n); } Ok(()) } ``` ``` -------------------------------- ### Set CharSize Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Example of opening a serial port and setting the character size to 8 bits. ```rust use serial2_tokio::{SerialPort, CharSize}; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_char_size(CharSize::Bits8); Ok(settings) })?; ``` -------------------------------- ### Open Serial Port with Baud Rate Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/README.md Opens a serial port with the specified path and baud rate. This is the simplest way to get started. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; ``` -------------------------------- ### Complete Serial Port Configuration Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Demonstrates a comprehensive configuration of a serial port, including raw mode, communication parameters, and timeouts, within a tokio async runtime. ```rust use serial2_tokio::{SerialPort, CharSize, StopBits, Parity, FlowControl}; use std::time::Duration; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { // Always start with raw mode settings.set_raw()?; // Serial communication parameters settings.set_baud_rate(19200)?; settings.set_char_size(CharSize::Bits8); settings.set_stop_bits(StopBits::One); settings.set_parity(Parity::None); settings.set_flow_control(FlowControl::Hardware); // Timeouts for blocking operations settings.set_read_timeout(Duration::from_secs(2))?; settings.set_write_timeout(Duration::from_secs(1))?; Ok(settings) })?; // Verify configuration let config = port.get_configuration()?; println!("Baud rate: {}", config.baud_rate()?); println!("Parity: {:?}", config.parity()?); Ok(()) } ``` -------------------------------- ### Full Settings Configuration Example Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Demonstrates opening a serial port and configuring multiple settings including raw mode, baud rate, character size, stop bits, parity, and flow control. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_raw()?; settings.set_baud_rate(9600)?; settings.set_char_size(serial2_tokio::CharSize::Bits8); settings.set_stop_bits(serial2_tokio::StopBits::One); settings.set_parity(serial2_tokio::Parity::None); settings.set_flow_control(serial2_tokio::FlowControl::None); Ok(settings) })?; ``` -------------------------------- ### Settings Struct Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Contains all configurable serial port parameters and provides methods to set and get them. ```APIDOC ## Settings Struct ### Description A structure containing all configurable serial port parameters. ### Public Methods - `set_baud_rate(rate: u32) -> std::io::Result<&mut Self>` — Set baud rate - `baud_rate(&self) -> std::io::Result` — Get current baud rate - `set_char_size(size: CharSize)` — Set character size - `char_size(&self) -> std::io::Result` — Get character size - `set_stop_bits(bits: StopBits)` — Set number of stop bits - `stop_bits(&self) -> std::io::Result` — Get stop bits - `set_parity(parity: Parity)` — Set parity mode - `parity(&self) -> std::io::Result` — Get parity mode - `set_flow_control(flow: FlowControl)` — Set flow control - `flow_control(&self) -> std::io::Result` — Get flow control - `set_read_timeout(timeout: std::time::Duration) -> std::io::Result<&mut Self>` — Set read timeout - `read_timeout(&self) -> std::io::Result` — Get read timeout - `set_write_timeout(timeout: std::time::Duration) -> std::io::Result<&mut Self>` — Set write timeout - `write_timeout(&self) -> std::io::Result` — Get write timeout - `set_raw(&mut self) -> std::io::Result<&mut Self>` — Set raw mode (recommended before custom configuration) ### Used By - `SerialPort::open()` - `SerialPort::set_configuration()` - `SerialPort::get_configuration()` - `IntoSettings` trait ### Example ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_raw()?; settings.set_baud_rate(9600)?; settings.set_char_size(serial2_tokio::CharSize::Bits8); settings.set_stop_bits(serial2_tokio::StopBits::One); settings.set_parity(serial2_tokio::Parity::None); settings.set_flow_control(serial2_tokio::FlowControl::None); Ok(settings) })?; ``` ``` -------------------------------- ### Example: Using is_write_vectored Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Demonstrates how to use the `is_write_vectored` method to conditionally inform the user about the platform's support for vectored writes. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; if port.is_write_vectored() { println!("Platform supports vectored writes: all buffers will be sent"); } else { println!("Platform does not support vectored writes: only first buffer will be sent"); } ``` -------------------------------- ### Example Usage of AsyncReadExt with SerialPort Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/AsyncRead-AsyncWrite-Traits.md Demonstrates how to use methods from tokio::io::AsyncReadExt, such as read_exact and read_to_end, with a SerialPort instance. Ensure the port path and baud rate are correctly specified. ```rust use tokio::io::AsyncReadExt; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Read exactly 10 bytes let mut buf = [0u8; 10]; port.read_exact(&mut buf).await?; println!("Read: {:?}", &buf); // Read until EOF (useful when port closes) let mut all_data = Vec::new(); port.read_to_end(&mut all_data).await?; println!("All data: {:?}", all_data); Ok(()) } ``` -------------------------------- ### Custom Baud Rate Selection Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/usage-patterns.md Allows users to select a baud rate from a predefined list of common rates. This example shows how to display options and open a port with a chosen rate. ```rust use serial2_tokio::{SerialPort, COMMON_BAUD_RATES}; use std::io::Write; #[tokio::main] async fn main() -> std::io::Result<()> { // Display available baud rates println!("Available baud rates:"); for (i, &rate) in COMMON_BAUD_RATES.iter().enumerate() { println!(" {{}}: {{}}", i + 1, rate); } // Get user choice (simplified, would normally read stdin) let choice = 6; // Default to 115200 let baud_rate = COMMON_BAUD_RATES[choice - 1]; // Open port with selected baud rate let port = SerialPort::open("/dev/ttyUSB0", baud_rate)?; println!("Opened port at {{}} baud", baud_rate); Ok(()) } ``` -------------------------------- ### Control and Read Serial Port Lines Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Platform-Specific-Extensions.md Demonstrates how to assert control lines (RTS, DTR), read modem status lines (CTS, DSR, RI, CD), and send a break signal. This example uses Tokio for asynchronous operations. ```rust use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Control output lines port.set_rts(true)?; port.set_dtr(true)?; println!("RTS and DTR asserted"); // Read input lines let cts = port.read_cts()?; let dsr = port.read_dsr()?; let ri = port.read_ri()?; let cd = port.read_cd()?; println!("CTS: {}, DSR: {}, RI: {}, CD: {}", cts, dsr, ri, cd); // Send a break signal port.set_break(true)?; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; port.set_break(false)?; println!("Break signal sent"); Ok(()) } ``` -------------------------------- ### Open Serial Port and Echo Data Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/README.md Opens a serial port and echoes all received data back to the port. Ensure the correct port name and baud rate are used for your system. This example assumes a successful port opening and continuous read/write operations. ```rust use serial2_tokio::SerialPort; // On Windows, use something like "COM1" or "COM15". let port = SerialPort::open("/dev/ttyUSB0", 115200)?; let mut buffer = [0; 256]; loop { let read = port.read(&mut buffer).await?; port.write_all(&buffer[..read]).await?; } ``` -------------------------------- ### Configure RS-485 Transceiver Mode on Linux Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Configures a serial port to use RS-485 transceiver mode on Linux, provided the 'rs4xx' feature is enabled. This example demonstrates setting the mode after opening the port. ```rust #[cfg(all(feature = "rs4xx", target_os = "linux"))] { use serial2_tokio::SerialPort; use serial2_tokio::rs4xx; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; port.set_rs4xx_mode(rs4xx::TransceiverMode::Rs485)?; } ``` -------------------------------- ### Reconfigure an Open Serial Port Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Shows how to modify the settings of an already open serial port. This involves getting the current configuration, modifying it, and then applying the new settings. ```rust let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Get current configuration let mut settings = port.get_configuration()?; // Modify settings settings.set_baud_rate(9600)?; settings.set_flow_control(FlowControl::Software); // Apply new configuration port.set_configuration(&settings)?; ``` -------------------------------- ### Typical Pattern for Discarding Input Buffer (Rust) Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Illustrates a common pattern where unsolicited data is discarded from the input buffer before sending a command and reading its response. This ensures the read operation gets the intended reply without interference. ```rust // Device may have sent unsolicited data port.discard_input_buffer()?; // Send a command port.write_all(b"STATUS?").await?; // Read the response (clean input) let mut buf = [0u8; 256]; let n = port.read(&mut buf).await?; ``` -------------------------------- ### Get RS-4xx Transceiver Mode (Linux) Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Platform-Specific-Extensions.md Gets the current RS-4xx transceiver mode on Linux. This requires the `rs4xx` feature to be enabled. Note that not all serial port drivers or hardware fully support this feature. ```rust #[cfg(all(feature = "rs4xx", target_os = "linux"))] { use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; match port.get_rs4xx_mode() { Ok(mode) => println!("Current mode: {:?}", mode), Err(e) => eprintln!("Could not read mode: {}", e), } } ``` -------------------------------- ### Set Custom Baud Rate Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Demonstrates how to set a custom baud rate and handle potential errors. Ensure the baud rate is supported by your hardware and operating system. ```rust match settings.set_baud_rate(300000) { Ok(_) => println!("Custom baud rate set"), Err(e) => eprintln!("Failed to set baud rate: {}", e), } ``` -------------------------------- ### get_rs4xx_mode Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Platform-Specific-Extensions.md Gets the current RS-4xx transceiver mode (RS-485/RS-422). This method is available only on Linux and requires the 'rs4xx' feature to be enabled. ```APIDOC ## get_rs4xx_mode ### Description Gets the current RS-4xx transceiver mode. This function is platform-specific and only available on Linux with the `rs4xx` feature enabled. ### Method `get_rs4xx_mode()` ### Returns `std::io::Result` — The transceiver mode or an I/O error. ### Availability - Linux only. - Requires `rs4xx` feature enabled. ### Platform Support - Supported on Linux via `ioctl` syscalls - Not supported on Windows, macOS, or other Unix variants - Not all serial port drivers implement this interface ### Transceiver Modes - `TransceiverMode::Default` — Normal RS-232 - `TransceiverMode::Rs485` — RS-485 half-duplex - `TransceiverMode::Rs422` — RS-422 full-duplex ### Errors - `std::io::Error` — If the operation fails or the driver does not support it - `ENOTTY` (25) — Device does not support this operation - `EINVAL` (22) — Invalid mode or request ### Hardware Limitations - Not all serial ports support software-configurable transceiver modes - Some hardware uses fixed modes set by jumpers or hardware switches - Some drivers report `Default` mode even when in RS-485 mode ### Example ```rust #[cfg(all(feature = "rs4xx", target_os = "linux"))] { use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; match port.get_rs4xx_mode() { Ok(mode) => println!("Current mode: {:?}", mode), Err(e) => eprintln!("Could not read mode: {}", e), } } ``` ``` -------------------------------- ### Modem Control Line Monitoring Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/usage-patterns.md Monitor modem control lines like CTS while performing I/O operations. This example demonstrates setting DTR and asynchronously monitoring CTS. ```rust use serial2_tokio::SerialPort; use tokio::time::{sleep, Duration}; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Set DTR to indicate we're ready port.set_dtr(true)?; // Monitor CTS in background let monitor_task = { let port = port.clone(); tokio::spawn(async move { loop { if let Ok(cts) = port.read_cts() { println!("CTS: {}", if cts { "HIGH" } else { "LOW" }); } sleep(Duration::from_millis(500)).await; } }) }; // Main I/O task let mut buf = [0u8; 256]; for _ in 0..10 { if let Ok(n) = port.read(&mut buf).await { println!("Received: {} bytes", n); } sleep(Duration::from_secs(1)).await; } monitor_task.abort(); Ok(()) } ``` -------------------------------- ### Reading and Writing with Trait Methods Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/AsyncRead-AsyncWrite-Traits.md Shows how to use standard AsyncRead and AsyncWrite trait methods like `read_exact` and `write_all`. ```rust use tokio::io::{AsyncReadExt, AsyncWriteExt}; let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Using trait methods let mut buf = [0u8; 256]; port.read_exact(&mut buf).await?; port.write_all(b"response").await?; ``` -------------------------------- ### Open Serial Port with Settings Object Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Opens a serial port using an existing `Settings` object. This allows for detailed configuration before opening the port. ```rust let mut settings = port.get_configuration()?; settings.set_baud_rate(9600)?; let port2 = SerialPort::open("/dev/ttyUSB0", settings)?; ``` -------------------------------- ### Writing Data with AsyncWriteExt Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/AsyncRead-AsyncWrite-Traits.md Demonstrates writing all bytes and partial writes using AsyncWriteExt methods. Includes flushing the buffer. ```rust use tokio::io::AsyncWriteExt; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Write all bytes port.write_all(b"Hello, world!").await?; // Write some bytes (may not write all) let n = port.write(b"Partial").await?; println!("Wrote {} bytes", n); // Flush (no-op but doesn't hurt) port.flush().await?; Ok(()) } ``` -------------------------------- ### Discard All Kernel Buffers (Rust) Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Clears both input and output kernel buffers. Use this to ensure a completely clean state before starting new communication or recovering from errors. This operation is immediate and does not wait for data transmission. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Clear all buffers before starting fresh communication port.discard_buffers()?; // Now send a command and receive response port.write_all(b"*IDN?").await?; let mut buf = [0u8; 256]; let n = port.read(&mut buf).await?; println!("Response: {}", String::from_utf8_lossy(&buf[..n])); ``` -------------------------------- ### Buffered Read/Write with AsyncReadExt/AsyncWriteExt Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/AsyncRead-AsyncWrite-Traits.md Demonstrates using AsyncReadExt and AsyncWriteExt with buffering for reading lines and writing responses, suitable for text-based protocols. ```rust use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Wrap with buffering let (reader, writer) = tokio::io::split(port); let mut reader = BufReader::new(reader); let mut writer = BufWriter::new(writer); // Read a line (won't work well with serial ports, but demonstrates the pattern) let mut line = String::new(); reader.read_line(&mut line).await?; writer.write_all(b"Response\n").await?; writer.flush().await?; Ok(()) } ``` -------------------------------- ### SerialPort::open Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/SerialPort.md Opens and configures a serial port by path or name. It supports various configuration methods, including direct baud rate, a Settings struct, or a closure for custom settings. ```APIDOC ## SerialPort::open ### Description Opens and configures a serial port by path or name. Supports various configuration methods. ### Method `pub fn open(path: impl AsRef, settings: impl IntoSettings) -> std::io::Result` ### Parameters #### Path - `path` (`impl AsRef`) - Required - On Unix: path to a TTY device. On Windows: COM device name (e.g., "COM1", "COM2", "COM15"). #### Settings - `settings` (`impl IntoSettings`) - Required - Configuration settings. Can be a `u32` baud rate, a `Settings` struct, a `KeepSettings` marker, or a closure receiving `Settings`. ### Returns - `std::io::Result` — A configured `SerialPort` or an I/O error. ### Errors - `std::io::Error` — If the port cannot be opened or configured. ### Example ```rust use serial2_tokio::SerialPort; // Simple baud rate configuration let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // On Windows let port = SerialPort::open("COM1", 115200)?; // Custom configuration via closure let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_baud_rate(9600)?; settings.set_char_size(serial2_tokio::CharSize::Bits8); settings.set_stop_bits(serial2_tokio::StopBits::One); Ok(settings) })?; ``` ``` -------------------------------- ### Types and Configuration Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/INDEX.md Reference for all exported types, including enums for serial port settings and the `Settings` struct for detailed configuration. ```APIDOC ## Types and Configuration Reference ### Description This section details all exported types, including enumerations for serial port parameters, the `Settings` struct for comprehensive configuration, and related traits and error types. ### Exported Types - **Enumerations**: - `CharSize`: Represents the character size (e.g., 5, 6, 7, 8 bits). - `FlowControl`: Represents the flow control mode (e.g., `None`, `Software`, `Hardware`). - `Parity`: Represents the parity setting (e.g., `None`, `Even`, `Odd`). - `StopBits`: Represents the number of stop bits (e.g., `One`, `OnePointFive`, `Two`). - **Structs**: - `Settings`: Contains all configurable parameters for a serial port (baud rate, character size, parity, stop bits, flow control, timeouts). - **Marker Types**: - `KeepSettings`: A marker type used with `IntoSettings` to indicate that existing port settings should be preserved. - **Traits**: - `IntoSettings`: A trait that allows various types (like `u32` for baud rate, `Settings` struct, closures) to be converted into serial port settings. - **Error Types**: - `TryFromError`: Represents errors encountered when trying to convert values into settings. - **Constants**: - `COMMON_BAUD_RATES`: A collection of common baud rate values. - **Modules**: - `rs4xx`: Contains types and constants related to RS-485/RS-422 transceiver support. ``` -------------------------------- ### Open Serial Port with Custom Settings Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/README.md Opens a serial port and applies custom configurations such as raw mode, baud rate, character size, parity, and flow control. Requires `serial2_tokio` types. ```rust let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_raw()?; settings.set_baud_rate(9600)?; settings.set_char_size(serial2_tokio::CharSize::Bits8); settings.set_parity(serial2_tokio::Parity::None); settings.set_flow_control(serial2_tokio::FlowControl::None); Ok(settings) })?; ``` -------------------------------- ### Discard Output Kernel Buffer (Rust) Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Discards only the kernel output buffer, removing any untransmitted data. Use this to cancel queued commands before they are sent, for example, to switch to a higher priority command. Be aware that data may have already been transmitted by the time this operation completes. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Queue some data port.write_all(b"SLOW_COMMAND").await?; // Before it's transmitted, decide we need to cancel port.discard_output_buffer()?; // Send a high-priority command instead port.write_all(b"CANCEL").await?; ``` -------------------------------- ### Using Tokio's AsyncRead Utilities Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/usage-patterns.md Showcases how to integrate `serial2-tokio` with Tokio's `AsyncReadExt` trait for more advanced reading operations. This includes reading an exact number of bytes or reading until the end of the stream. ```rust use tokio::io::AsyncReadExt; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Read exactly 10 bytes let mut buf = [0u8; 10]; port.read_exact(&mut buf).await?; println!("Exact read: {:?}", buf); // Read until EOF (useful for short-lived connections) let mut all_data = Vec::new(); port.read_to_end(&mut all_data).await?; println!("All data: {} bytes", all_data.len()); Ok(()) } ``` -------------------------------- ### SerialPort Methods Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/MANIFEST.txt Documentation for the core SerialPort struct and its associated methods, including constructors, port discovery, I/O operations, configuration, and buffer management. ```APIDOC ## SerialPort Methods ### Description Provides access to serial port functionalities, including opening, configuring, reading from, and writing to serial devices. ### Methods - **open()**: Constructor for creating a new `SerialPort` instance. - **pair()**: Creates a Unix pseudo-terminal pair for testing or specific use cases. - **available_ports()**: Discovers and returns a list of available serial ports on the system. - **read/write variants**: Multiple methods for reading and writing data, including basic read/write, vectored I/O, and reading/writing all available data. - **get_configuration() / set_configuration()**: Methods to retrieve and modify the serial port's configuration settings. - **try_clone()**: Creates a clone of the `SerialPort` instance, allowing for concurrent access. - **discard_buffers()**: Methods to clear input and output buffers. - **control_line()**: Methods for controlling modem status lines (e.g., DTR, RTS). - **rs4xx_transceiver()**: Methods for controlling RS-4xx transceiver settings (Linux specific). - **send_break_signal()**: Method to send a serial break signal. ``` -------------------------------- ### Sequential Commands with Buffer Cleanup Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/usage-patterns.md This pattern demonstrates sending a series of commands sequentially, ensuring that any stale data in the input buffer is discarded before each new command is sent. This prevents crosstalk and ensures accurate responses. ```rust use serial2_tokio::SerialPort; use std::time::Duration; #[tokio::main] async fn main() -> std::io::Result<()> { let port = SerialPort::open("/dev/ttyUSB0", 115200)?; let commands = vec!["*RST", "*IDN?", "*OPC?"]; for cmd in commands { // Clear any stale data port.discard_input_buffer()?; // Send command port.write_all(cmd.as_bytes()).await?; port.write_all(b"\r\n").await?; // Read response let mut buf = [0u8; 256]; let n = port.read(&mut buf).await?; println!("{}: {}", cmd, String::from_utf8_lossy(&buf[..n])); // Small delay between commands tokio::time::sleep(Duration::from_millis(100)).await; } Ok(()) } ``` -------------------------------- ### Open Serial Port with Custom Settings Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Opens a serial port with custom configuration defined by a closure. This is useful for setting multiple parameters at once. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_baud_rate(115200)?; Ok(settings) })?; let current_rate = port.get_configuration()?.baud_rate()?; println!("Baud rate: {}", current_rate); ``` -------------------------------- ### Open Serial Port with KeepSettings Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Opens a serial port while preserving its existing settings. Use this when you do not want to modify the current configuration. ```rust use serial2_tokio::KeepSettings; let port = SerialPort::open("/dev/ttyUSB0", KeepSettings)?; ``` -------------------------------- ### Rust: Check Platform Support for Vectored Reads Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Shows how to check if the current platform supports full vectored reads using `is_read_vectored()`. This is important because Windows only uses the first buffer for `read_vectored`, while Unix/Linux uses all provided buffers. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; if port.is_read_vectored() { println!("Platform supports vectored reads: data will fill multiple buffers"); } else { println!("Platform does not support vectored reads: only first buffer will be filled"); } ``` -------------------------------- ### Port Discovery and Auto-Connect Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/usage-patterns.md Automatically discovers available serial ports on the system and attempts to open the first one found. This simplifies connecting to devices without hardcoding port names. ```rust use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { // Find available ports let ports = SerialPort::available_ports()?; if ports.is_empty() { eprintln!("No serial ports found"); return Err(std::io::Error::new( std::io::ErrorKind::NotFound, "No serial ports available", )); } println!("Found ports:"); for port_path in &ports { println!(" {{:?}}", port_path); } // Try to open the first port let port = SerialPort::open(&ports[0], 115200)?; println!("Opened: {{:?}}", ports[0]); let mut buf = [0u8; 256]; let n = port.read(&mut buf).await?; println!("Read: {} bytes", n); Ok(()) } ``` -------------------------------- ### Concurrent Serial Port Read and Write Tasks Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/README.md Demonstrates how to concurrently read from and write to a serial port using tokio tasks. Ensure the serial port is opened and cloned for each task. ```rust let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Reader task let reader = { let port = port.clone(); tokio::spawn(async move { let mut buf = [0u8; 256]; loop { let n = port.read(&mut buf).await.ok()?; println!("Read: {} bytes", n); } }) }; // Writer task let writer = { let port = port.clone(); tokio::spawn(async move { port.write_all(b"data").await.ok()?; }) }; tokio::select! { _ = reader => {}, _ = writer => {} } ``` -------------------------------- ### Settings Configuration Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/MANIFEST.txt Details on configuring serial port settings such as baud rate, character size, stop bits, parity, flow control, and timeouts. ```APIDOC ## Settings Configuration ### Description Allows detailed configuration of serial port parameters to match specific communication requirements. ### Configuration Options - **Baud rate**: Sets the communication speed (bits per second). - **Character size**: Defines the number of data bits per character (e.g., 5, 6, 7, 8). - **Stop bits**: Specifies the number of stop bits to use (e.g., 1, 1.5, 2). - **Parity**: Configures parity checking for error detection (e.g., None, Odd, Even, Mark, Space). - **Flow control**: Enables or disables hardware or software flow control. - **Read timeout**: Sets the timeout for read operations. - **Write timeout**: Sets the timeout for write operations. - **Raw mode**: Enables or disables raw mode for unbuffered I/O. ``` -------------------------------- ### Open Serial Port with Custom Closure Configuration Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/configuration.md Opens a serial port using a closure that allows for detailed and custom configuration of all serial port parameters. ```rust let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_raw()?; settings.set_baud_rate(9600)?; settings.set_char_size(serial2_tokio::CharSize::Bits8); settings.set_stop_bits(serial2_tokio::StopBits::One); settings.set_parity(serial2_tokio::Parity::None); settings.set_flow_control(serial2_tokio::FlowControl::None); Ok(settings) })?; ``` -------------------------------- ### Settings Structure Definition Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Represents all configurable parameters for a serial port. ```rust pub struct Settings { // Opaque internal fields } ``` -------------------------------- ### Platform-Specific Extensions Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/INDEX.md This section details methods for controlling modem lines and specific hardware features, which may vary depending on the operating system and hardware. ```APIDOC ## Platform-Specific Extensions ### Description Provides methods for controlling modem status lines and specific hardware features, offering finer-grained control over the serial port's physical interface. ### Methods - **Modem Control Lines**: - `set_rts(level: bool) -> Result<(), Error>`: Sets the Request To Send (RTS) line. - `read_cts() -> Result`: Reads the state of the Clear To Send (CTS) line. - `set_dtr(level: bool) -> Result<(), Error>`: Sets the Data Terminal Ready (DTR) line. - `read_dsr() -> Result`: Reads the state of the Data Set Ready (DSR) line. - `read_ri() -> Result`: Reads the state of the Ring Indicator (RI) line. - `read_cd() -> Result`: Reads the state of the Carrier Detect (CD) line. - **Signal Control**: - `set_break(state: bool) -> Result<(), Error>`: Sets or clears the serial break condition. - **RS-4xx Transceiver (Linux)**: - `get_rs4xx_mode() -> Result`: Retrieves the RS-4xx transceiver mode. - `set_rs4xx_mode(mode: Rs4xxMode) -> Result<(), Error>`: Sets the RS-4xx transceiver mode. ### Parameters - `level` (bool): `true` to assert the line, `false` to deassert. - `state` (bool): `true` to assert the break condition, `false` to clear it. - `mode` (`Rs4xxMode`): The desired RS-4xx mode (e.g., `HalfDuplex`, `FullDuplex`). ### Returns - `Result<(), Error>`: On success, returns `()`. On failure, returns an `Error`. - `Result`: On success, returns the boolean state of the line. On failure, returns an `Error`. - `Result`: On success, returns the current RS-4xx mode. On failure, returns an `Error`. ### Errors - `Error`: Errors related to unsupported platforms, hardware access failures, or invalid configurations. ``` -------------------------------- ### Handling Partial Writes Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Illustrates the potential for partial writes with `write()` and `write_vectored()`, emphasizing the need for loops or `write_all()` to ensure complete data transmission. Shows a conceptual loop for `write_vectored`. ```rust // Unsafe: partial write silently ignored port.write_all(data).await?; // Correct: loops until complete // For vectored, may need multiple calls let mut bufs = [IoSlice::new(a), IoSlice::new(b)]; let mut written = 0; while written < total_len { let n = port.write_vectored(&bufs).await?; written += n; // Adjust buffer offsets for next iteration... } ``` -------------------------------- ### Iterate and Print Common Baud Rates Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Iterates through the COMMON_BAUD_RATES slice and prints each supported baud rate. Demonstrates how to access and use the predefined baud rates. ```rust use serial2_tokio::COMMON_BAUD_RATES; for baud in COMMON_BAUD_RATES { println!("Supported baud rate: {}", baud); } ``` -------------------------------- ### Open a Pair of Pseudo-terminals for Testing Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/SerialPort.md Creates a connected pair of pseudo-terminals, useful for testing serial communication logic. Data written to one port can be read from the other. This feature is available on Unix-like systems. ```rust #[cfg(unix)] { let (port1, port2) = SerialPort::pair()?; // port1 and port2 are connected; data written to port1 can be read from port2 } ``` -------------------------------- ### Open Serial Port with Custom Settings Closure Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Opens a serial port by providing a closure that customizes the serial port settings. This allows for fine-grained control over parameters like raw mode and baud rate. ```rust use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", |mut settings| { settings.set_raw()?; settings.set_baud_rate(9600)?; Ok(settings) })?; ``` -------------------------------- ### Bidirectional Relay: Stdin to Serial Port and Vice Versa Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/AsyncRead-AsyncWrite-Traits.md This snippet demonstrates how to create a bidirectional relay between standard input and a serial port using Tokio. It spawns two tasks: one to copy data from stdin to the serial port and another to copy data from the serial port to stdout. Ensure the serial port path and baud rate are correctly configured. ```rust use tokio::io::{AsyncReadExt, AsyncWriteExt}; use serial2_tokio::SerialPort; #[tokio::main] async fn main() -> std::io::Result<()> { let mut port = SerialPort::open("/dev/ttyUSB0", 115200)?; let (mut reader, mut writer) = tokio::io::split(tokio::io::stdin()); // Copy stdin to port let port_copy = port.clone(); let stdin_to_port = tokio::spawn(async move { tokio::io::copy(&mut reader, &mut port_copy).await }); // Copy port to stdout let mut stdout = tokio::io::stdout(); let port_to_stdout = tokio::spawn(async move { let mut buf = [0u8; 256]; loop { match port.read(&mut buf).await { Ok(0) => return Ok::<(), std::io::Error>(()), Ok(n) => stdout.write_all(&buf[..n]).await?, Err(e) => return Err(e), } } }); tokio::select! { _ = stdin_to_port => {}, _ = port_to_stdout => {}, } Ok(()) } ``` -------------------------------- ### Buffer Operation Caveats Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Details important considerations and limitations for buffer operations, including handling partial writes, specific behaviors on Windows, and timing aspects of buffer management functions. ```APIDOC ## Buffer Operation Caveats ### Partial Writes Both `write()` and `write_vectored()` may return fewer bytes written than requested. To ensure all data is written, it is necessary to loop until the entire data set has been transmitted, or to use the `write_all()` method which handles this looping internally. For vectored writes, if partial writes occur, multiple calls might be required to send all data. The example below illustrates a loop structure for handling this: ```rust // For vectored, may need multiple calls let mut bufs = [IoSlice::new(a), IoSlice::new(b)]; let mut written = 0; while written < total_len { let n = port.write_vectored(&bufs).await?; written += n; // Adjust buffer offsets for next iteration... } ``` ### Windows Limitations On Windows, the implementation of `write_vectored()` is limited; it only utilizes the first buffer provided in the `IoSlice` array. For code that needs to be cross-platform compatible, consider these approaches: 1. Concatenate all data into a single buffer before sending. 2. Check for platform support using `is_write_vectored()` and adapt accordingly. 3. Implement a fallback mechanism to make separate `write()` calls for each buffer when running on Windows. ### Timing Considerations - The `discard_buffers()` function does not guarantee that data has been transmitted. If confirmation of transmission is required, rely on device acknowledgments or similar mechanisms. - Data may have already been sent by the time `discard_output_buffer()` returns, as it operates on kernel buffers which may have different sizes and behaviors depending on the operating system. - Kernel buffer sizes can vary significantly based on the OS and specific platform configurations. ``` -------------------------------- ### Open Serial Port with KeepSettings Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/types.md Opens a serial port without changing its existing configuration. This is useful when you want to use the port with its current settings. ```rust use serial2_tokio::{SerialPort, KeepSettings}; let port = SerialPort::open("/dev/ttyUSB0", KeepSettings)?; // Port is opened with whatever settings it already had ``` -------------------------------- ### Check Unix Device File Permissions Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/platform-notes.md Verify the permissions of a serial device file on Unix/Linux systems using the 'ls -l' command. ```bash ls -l /dev/ttyUSB0 ``` -------------------------------- ### Windows Async Write Implementation Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/platform-notes.md Implements the asynchronous write operation on Windows using NamedPipeClient's writable() and try_write(). It handles WouldBlock errors by retrying. ```rust pub async fn write(&self, buf: &[u8]) -> std::io::Result { loop { self.io.writable().await?; match self.io.try_write(buf) { Ok(n) => return Ok(n), Err(e) => { if e.kind() == std::io::ErrorKind::WouldBlock { continue } else { return Err(e) } } } } } ``` -------------------------------- ### Rust: Read into Multiple Buffers with read_vectored Source: https://github.com/de-vri-es/serial2-tokio-rs/blob/main/_autodocs/api-reference/Buffer-Operations.md Demonstrates how to read data into multiple pre-allocated buffers using the `read_vectored` method. This is useful for handling fixed-format data or protocol messages where different parts of the data can be placed directly into separate buffers. ```rust use std::io::IoSliceMut; use serial2_tokio::SerialPort; let port = SerialPort::open("/dev/ttyUSB0", 115200)?; // Create multiple buffers let mut buf1 = [0u8; 256]; let mut buf2 = [0u8; 256]; let mut buf3 = [0u8; 256]; // Read into multiple buffers in one call let bufs = &mut [ IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2), IoSliceMut::new(&mut buf3), ]; let bytes_read = port.read_vectored(bufs).await?; println!("Read {} bytes across {} buffers", bytes_read, bufs.len()); ```