tuiserial_core/
config.rs

1//! Serial port configuration types
2//!
3//! This module defines the serial port configuration structure and related
4//! settings for establishing serial connections.
5
6use serde::{Deserialize, Serialize};
7
8use crate::types::{FlowControl, Parity};
9
10/// Serial port configuration
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct SerialConfig {
13    pub port: String,
14    pub baud_rate: u32,
15    pub data_bits: u8,
16    pub parity: Parity,
17    pub stop_bits: u8,
18    pub flow_control: FlowControl,
19}
20
21impl Default for SerialConfig {
22    fn default() -> Self {
23        Self {
24            port: String::new(),
25            baud_rate: 9600,
26            data_bits: 8,
27            parity: Parity::None,
28            stop_bits: 1,
29            flow_control: FlowControl::None,
30        }
31    }
32}
33
34impl SerialConfig {
35    /// Create a new serial configuration with default values
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    /// Create a configuration with specified port and default other values
41    pub fn with_port(port: impl Into<String>) -> Self {
42        Self {
43            port: port.into(),
44            ..Default::default()
45        }
46    }
47
48    /// Validate the configuration
49    pub fn validate(&self) -> Result<(), String> {
50        if self.port.is_empty() {
51            return Err("Port cannot be empty".to_string());
52        }
53
54        if self.baud_rate == 0 {
55            return Err("Baud rate must be greater than 0".to_string());
56        }
57
58        if self.data_bits < 5 || self.data_bits > 8 {
59            return Err("Data bits must be between 5 and 8".to_string());
60        }
61
62        if self.stop_bits < 1 || self.stop_bits > 2 {
63            return Err("Stop bits must be 1 or 2".to_string());
64        }
65
66        Ok(())
67    }
68
69    /// Format configuration as a human-readable string
70    pub fn format_display(&self) -> String {
71        let parity_char = match self.parity {
72            Parity::None => 'N',
73            Parity::Even => 'E',
74            Parity::Odd => 'O',
75        };
76
77        format!(
78            "{} @ {} bps, {}-{}-{}",
79            self.port, self.baud_rate, self.data_bits, parity_char, self.stop_bits
80        )
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_default_config() {
90        let config = SerialConfig::default();
91        assert_eq!(config.port, "");
92        assert_eq!(config.baud_rate, 9600);
93        assert_eq!(config.data_bits, 8);
94        assert_eq!(config.stop_bits, 1);
95    }
96
97    #[test]
98    fn test_with_port() {
99        let config = SerialConfig::with_port("/dev/ttyUSB0");
100        assert_eq!(config.port, "/dev/ttyUSB0");
101        assert_eq!(config.baud_rate, 9600);
102    }
103
104    #[test]
105    fn test_validate() {
106        let mut config = SerialConfig::default();
107        assert!(config.validate().is_err()); // Empty port
108
109        config.port = "/dev/ttyUSB0".to_string();
110        assert!(config.validate().is_ok());
111
112        config.baud_rate = 0;
113        assert!(config.validate().is_err());
114
115        config.baud_rate = 9600;
116        config.data_bits = 9;
117        assert!(config.validate().is_err());
118    }
119
120    #[test]
121    fn test_format_display() {
122        let config = SerialConfig {
123            port: "/dev/ttyUSB0".to_string(),
124            baud_rate: 115200,
125            data_bits: 8,
126            parity: Parity::None,
127            stop_bits: 1,
128            flow_control: FlowControl::None,
129        };
130
131        let display = config.format_display();
132        assert_eq!(display, "/dev/ttyUSB0 @ 115200 bps, 8-N-1");
133    }
134}