1#![deny(
5 missing_docs,
6 missing_debug_implementations,
7 missing_copy_implementations,
8 dead_code,
9 while_true
10)]
11use std::io::ErrorKind;
12
13#[allow(unused)]
14const XON: i8 = 17;
15#[allow(unused)]
16const XOFF: i8 = 19;
17#[allow(unused)]
18const CR: i8 = 13;
19#[allow(unused)]
20const LF: i8 = 10;
21
22#[cfg(unix)]
23pub mod posix;
24
25#[cfg(windows)]
26pub mod windows;
27
28pub type SerialResult<T> = std::result::Result<T, SerialError>;
30
31pub enum SerialError {
33 IoError(std::io::Error),
35 OsError {
37 code: u32,
39 desc: String,
41 },
42 LibraryError(String)
44}
45
46impl std::fmt::Debug for SerialError {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match self {
49 Self::IoError(arg0) => f.debug_tuple("IoError").field(arg0).finish(),
50 Self::OsError { code, desc } => f
51 .debug_struct("OsError")
52 .field("code", code)
53 .field("desc", desc)
54 .finish(),
55 SerialError::LibraryError(e) => f.debug_tuple("LibraryError").field(e).finish(),
56 }
57 }
58}
59
60impl std::fmt::Display for SerialError {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 match self {
63 SerialError::IoError(e) => {
64 write!(f, "IoError {}", e)
65 }
66 SerialError::OsError { code, desc } => write!(f, "OsError {code} ({desc})"),
67 SerialError::LibraryError(e) => write!(f, "Serial-RS Lib error '{e}'"),
68 }
69 }
70}
71
72impl std::error::Error for SerialError {
73 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
74 if let Self::IoError(e) = self {
75 Some(e)
76 } else {
77 None
78 }
79 }
80}
81
82#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
84pub struct SerialPortSettings {
85 baud_rate: u32,
86 byte_size: ByteSize,
87 parity: Parity,
88 stop_bits: StopBits,
89 read_timeout: Option<u128>,
90 flow_control: FlowControl,
91 write_timeout: Option<u128>,
92 inter_byte_timeout: Option<u128>,
93 blocking: bool
94}
95
96impl Default for SerialPortSettings {
97 fn default() -> Self {
98 Self {
99 baud_rate: 9600,
100 byte_size: ByteSize::Eight,
101 parity: Parity::None,
102 stop_bits: StopBits::One,
103 read_timeout: None,
104 write_timeout: None,
105 flow_control: FlowControl::None,
106 inter_byte_timeout: None,
107 blocking: true
108 }
109 }
110}
111
112#[allow(missing_docs)]
113impl SerialPortSettings {
114 pub fn baud(mut self, baud: u32) -> Self {
116 self.baud_rate = baud;
117 self
118 }
119
120 pub fn read_timeout(mut self, timeout: Option<u128>) -> Self {
121 self.read_timeout = timeout;
122 self
123 }
124
125 pub fn byte_size(mut self, byte_size: ByteSize) -> Self {
126 self.byte_size = byte_size;
127 self
128 }
129
130 pub fn write_timeout(mut self, timeout: Option<u128>) -> Self {
131 self.write_timeout = timeout;
132 self
133 }
134
135 pub fn parity(mut self, parity: Parity) -> Self {
136 self.parity = parity;
137 self
138 }
139
140 pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
141 self.stop_bits = stop_bits;
142 self
143 }
144
145 pub fn set_flow_control(mut self, method: FlowControl) -> Self {
146 self.flow_control = method;
147 self
148 }
149
150 pub fn set_blocking(mut self, blocking: bool) -> Self {
151 self.blocking = blocking;
152 self
153 }
154}
155
156#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
157pub enum FlowControl {
159 None,
161 DsrDtr,
163 XonXoff,
165 RtsCts
167}
168
169#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
170pub enum ByteSize {
172 Five,
174 Six,
176 Seven,
178 Eight,
180}
181
182#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
183pub enum Parity {
185 None,
187 Even,
189 Odd,
191}
192
193#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
194pub enum StopBits {
196 One,
198 OnePointFive,
200 Two,
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
206pub struct PortInfo {
207 port: String,
209 hwid: String,
211 vid: u16,
213 pid: u16,
215 manufacturer: String,
217 description: String,
219}
220
221impl PortInfo {
222 pub fn get_port(&self) -> &str { &self.port }
224 pub fn get_hwid(&self) -> &str { &self.hwid }
226 pub fn get_pid(&self) -> u16 { self.pid }
228 pub fn get_vid(&self) -> u16 { self.vid }
230 pub fn get_manufacturer(&self) -> &str { &self.manufacturer }
232 pub fn get_desc(&self) -> &str { &self.description }
234}
235
236pub trait SerialPort: Send + std::io::Write + std::io::Read {
238 fn reconfigure_port(&mut self) -> SerialResult<()>;
240 fn close(self) -> SerialResult<()>;
242 fn set_buffer_size(&mut self, rx_size: usize, tx_size: usize) -> SerialResult<()>;
244 fn set_output_flow_control(&self, enable: bool) -> SerialResult<()>;
246 fn set_data_terminal_ready(&mut self, enable: bool) -> SerialResult<()>;
248 fn set_request_to_send(&mut self, enable: bool) -> SerialResult<()>;
250 fn set_break_state(&mut self, enable: bool) -> SerialResult<()>;
252 fn read_clear_to_send(&self) -> SerialResult<bool>;
254 fn read_data_set_ready(&self) -> SerialResult<bool>;
256 fn read_ring_indicator(&self) -> SerialResult<bool>;
258 fn read_carrier_detect(&self) -> SerialResult<bool>;
260 fn bytes_to_read(&self) -> SerialResult<usize>;
262 fn bytes_to_write(&self) -> SerialResult<usize>;
264 fn get_path(&self) -> String;
266 fn try_clone(&mut self) -> SerialResult<Box<dyn SerialPort>>;
273 fn clear_input_buffer(&mut self) -> SerialResult<()>;
275 fn clear_output_buffer(&mut self) -> SerialResult<()>;
277}
278
279pub trait PortScanner {
281 fn list_devices(&mut self) -> SerialResult<Vec<PortInfo>>;
283}
284
285impl From<SerialError> for std::io::Error {
286 fn from(e: SerialError) -> Self {
287 match e {
288 SerialError::IoError(i) => i,
289 SerialError::OsError { code: _ , desc } => std::io::Error::new(ErrorKind::Other, desc),
290 SerialError::LibraryError(e) => std::io::Error::new(ErrorKind::Other, e),
291 }
292 }
293}
294
295pub fn new(info: PortInfo, settings: Option<SerialPortSettings>) -> SerialResult<Box<dyn SerialPort>> {
297 #[cfg(unix)]
298 {
299 use posix::*;
300 Ok(Box::new(TTYPort::new(info.port, settings)?))
301 }
302 #[cfg(windows)]
303 {
304 use windows::*;
305 Ok(Box::new(COMPort::new(info.port, settings)?))
306 }
307}
308
309pub fn new_from_path(path: &str, settings: Option<SerialPortSettings>) -> SerialResult<Box<dyn SerialPort>> {
311 #[cfg(unix)]
312 {
313 use posix::*;
314 Ok(Box::new(TTYPort::new(path.to_string(), settings)?))
315 }
316 #[cfg(windows)]
317 {
318 use windows::*;
319 Ok(Box::new(COMPort::new(path.to_string(), settings)?))
320 }
321}
322
323pub fn list_ports() -> SerialResult<Vec<PortInfo>> {
325 #[cfg(unix)]
326 {
327 use posix::port_lister::TTYPortScanner;
328 TTYPortScanner{}.list_devices()
329 }
330 #[cfg(windows)]
331 {
332 use windows::port_lister::COMPortLister;
333 COMPortLister{}.list_devices()
334 }
335}