1use std::pin::Pin;
14use std::task::{Context, Poll};
15use std::thread;
16use std::time::Duration;
17
18use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
19use tokio_serial::{SerialPort, SerialPortBuilderExt, SerialStream};
20
21use crate::config::{DataBits, FlowControl, ModemStatus, Parity, SerialConfig, StopBits};
22use crate::error::Result;
23
24pub trait SerialDevice: AsyncRead + AsyncWrite + Send + Unpin {
43 fn set_baud_rate(&mut self, baud: u32) -> Result<()>;
53
54 fn set_data_bits(&mut self, bits: DataBits) -> Result<()>;
60
61 fn set_stop_bits(&mut self, bits: StopBits) -> Result<()>;
67
68 fn set_parity(&mut self, parity: Parity) -> Result<()>;
75
76 fn set_flow_control(&mut self, flow: FlowControl) -> Result<()>;
82
83 fn set_dtr(&mut self, level: bool) -> Result<()>;
89
90 fn set_rts(&mut self, level: bool) -> Result<()>;
96
97 fn send_break(&mut self, duration: Duration) -> Result<()>;
107
108 fn modem_status(&mut self) -> Result<ModemStatus>;
117
118 fn config(&self) -> &SerialConfig;
124}
125
126pub struct SerialPortDevice {
132 stream: SerialStream,
133 config: SerialConfig,
134}
135
136impl SerialPortDevice {
137 pub fn open(path: &str, config: SerialConfig) -> Result<Self> {
146 config.validate()?;
147 let stream = tokio_serial::new(path, config.baud_rate)
148 .data_bits(to_sp_data_bits(config.data_bits))
149 .stop_bits(to_sp_stop_bits(config.stop_bits))
150 .parity(to_sp_parity(config.parity))
151 .flow_control(to_sp_flow(config.flow_control))
152 .timeout(config.read_timeout)
153 .open_native_async()?;
154 Ok(Self { stream, config })
155 }
156
157 #[cfg(unix)]
168 pub fn pair() -> Result<(Self, Self)> {
169 let (a, b) = SerialStream::pair()?;
170 let config = SerialConfig::default();
171 Ok((Self { stream: a, config }, Self { stream: b, config }))
172 }
173}
174
175impl AsyncRead for SerialPortDevice {
176 fn poll_read(
177 mut self: Pin<&mut Self>,
178 cx: &mut Context<'_>,
179 buf: &mut ReadBuf<'_>,
180 ) -> Poll<std::io::Result<()>> {
181 Pin::new(&mut self.stream).poll_read(cx, buf)
182 }
183}
184
185impl AsyncWrite for SerialPortDevice {
186 fn poll_write(
187 mut self: Pin<&mut Self>,
188 cx: &mut Context<'_>,
189 buf: &[u8],
190 ) -> Poll<std::io::Result<usize>> {
191 Pin::new(&mut self.stream).poll_write(cx, buf)
192 }
193
194 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
195 Pin::new(&mut self.stream).poll_flush(cx)
196 }
197
198 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
199 Pin::new(&mut self.stream).poll_shutdown(cx)
200 }
201}
202
203impl SerialDevice for SerialPortDevice {
204 fn set_baud_rate(&mut self, baud: u32) -> Result<()> {
205 if baud == 0 {
206 return Err(crate::Error::InvalidConfig(
207 "baud_rate must be non-zero".into(),
208 ));
209 }
210 self.stream.set_baud_rate(baud)?;
211 self.config.baud_rate = baud;
212 Ok(())
213 }
214
215 fn set_data_bits(&mut self, bits: DataBits) -> Result<()> {
216 self.stream.set_data_bits(to_sp_data_bits(bits))?;
217 self.config.data_bits = bits;
218 Ok(())
219 }
220
221 fn set_stop_bits(&mut self, bits: StopBits) -> Result<()> {
222 self.stream.set_stop_bits(to_sp_stop_bits(bits))?;
223 self.config.stop_bits = bits;
224 Ok(())
225 }
226
227 fn set_parity(&mut self, parity: Parity) -> Result<()> {
228 self.stream.set_parity(to_sp_parity(parity))?;
229 self.config.parity = parity;
230 Ok(())
231 }
232
233 fn set_flow_control(&mut self, flow: FlowControl) -> Result<()> {
234 self.stream.set_flow_control(to_sp_flow(flow))?;
235 self.config.flow_control = flow;
236 Ok(())
237 }
238
239 fn set_dtr(&mut self, level: bool) -> Result<()> {
240 self.stream.write_data_terminal_ready(level)?;
241 Ok(())
242 }
243
244 fn set_rts(&mut self, level: bool) -> Result<()> {
245 self.stream.write_request_to_send(level)?;
246 Ok(())
247 }
248
249 fn send_break(&mut self, duration: Duration) -> Result<()> {
250 self.stream.set_break()?;
251 thread::sleep(duration);
252 self.stream.clear_break()?;
253 Ok(())
254 }
255
256 fn modem_status(&mut self) -> Result<ModemStatus> {
257 Ok(ModemStatus {
258 cts: self.stream.read_clear_to_send()?,
259 dsr: self.stream.read_data_set_ready()?,
260 ri: self.stream.read_ring_indicator()?,
261 cd: self.stream.read_carrier_detect()?,
262 })
263 }
264
265 fn config(&self) -> &SerialConfig {
266 &self.config
267 }
268}
269
270const fn to_sp_data_bits(b: DataBits) -> serialport::DataBits {
271 match b {
272 DataBits::Five => serialport::DataBits::Five,
273 DataBits::Six => serialport::DataBits::Six,
274 DataBits::Seven => serialport::DataBits::Seven,
275 DataBits::Eight => serialport::DataBits::Eight,
276 }
277}
278
279const fn to_sp_stop_bits(b: StopBits) -> serialport::StopBits {
280 match b {
281 StopBits::One => serialport::StopBits::One,
282 StopBits::Two => serialport::StopBits::Two,
283 }
284}
285
286const fn to_sp_parity(p: Parity) -> serialport::Parity {
290 match p {
291 Parity::Even => serialport::Parity::Even,
292 Parity::Odd => serialport::Parity::Odd,
293 Parity::None | Parity::Mark | Parity::Space => serialport::Parity::None,
294 }
295}
296
297const fn to_sp_flow(f: FlowControl) -> serialport::FlowControl {
298 match f {
299 FlowControl::None => serialport::FlowControl::None,
300 FlowControl::Hardware => serialport::FlowControl::Hardware,
301 FlowControl::Software => serialport::FlowControl::Software,
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308
309 #[test]
310 fn data_bits_round_trip() {
311 assert_eq!(
312 to_sp_data_bits(DataBits::Eight),
313 serialport::DataBits::Eight
314 );
315 assert_eq!(to_sp_data_bits(DataBits::Five), serialport::DataBits::Five);
316 }
317
318 #[test]
319 fn stop_bits_round_trip() {
320 assert_eq!(to_sp_stop_bits(StopBits::One), serialport::StopBits::One);
321 assert_eq!(to_sp_stop_bits(StopBits::Two), serialport::StopBits::Two);
322 }
323
324 #[test]
325 fn parity_round_trip() {
326 assert_eq!(to_sp_parity(Parity::Even), serialport::Parity::Even);
327 assert_eq!(to_sp_parity(Parity::Odd), serialport::Parity::Odd);
328 assert_eq!(to_sp_parity(Parity::None), serialport::Parity::None);
329 }
330
331 #[test]
332 fn flow_round_trip() {
333 assert_eq!(to_sp_flow(FlowControl::None), serialport::FlowControl::None);
334 assert_eq!(
335 to_sp_flow(FlowControl::Hardware),
336 serialport::FlowControl::Hardware
337 );
338 assert_eq!(
339 to_sp_flow(FlowControl::Software),
340 serialport::FlowControl::Software
341 );
342 }
343
344 #[cfg(unix)]
345 #[tokio::test]
346 async fn pair_returns_default_config() {
347 let (a, b) = SerialPortDevice::pair().expect("pty pair");
348 assert_eq!(a.config(), &SerialConfig::default());
349 assert_eq!(b.config(), &SerialConfig::default());
350 }
351}