playdate_device/serial/
mod.rs1use std::borrow::Cow;
2use std::cell::RefCell;
3
4
5pub mod discover;
6mod blocking;
7mod r#async;
8
9mod methods;
10pub use methods::*;
11
12
13#[cfg(not(feature = "tokio-serial"))]
14type Port = Box<dyn serialport::SerialPort>;
15#[cfg(feature = "tokio-serial")]
16type Port = Box<tokio_serial::SerialStream>;
17
18pub struct Interface {
19 info: serialport::SerialPortInfo,
20 port: Option<RefCell<Port>>,
21}
22
23
24impl std::fmt::Display for Interface {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 use serialport::SerialPort;
27
28 let port_name = &self.info.port_name;
29 let name = self.port.as_ref().and_then(|p| {
30 p.try_borrow()
31 .ok()
32 .and_then(|p| p.name().filter(|s| s != port_name))
33 });
34
35 write!(f, "serial:{}", name.as_deref().unwrap_or(port_name))
36 }
37}
38
39impl std::fmt::Debug for Interface {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("Interface")
42 .field("name", &self.info.port_name)
43 .field("opened", &self.port.is_some())
44 .finish()
45 }
46}
47
48
49impl Interface {
50 #[cfg_attr(feature = "tracing", tracing::instrument)]
51 pub fn new(info: serialport::SerialPortInfo) -> Self { Self { info, port: None } }
52
53 #[cfg_attr(feature = "tracing", tracing::instrument)]
54 pub fn new_with(port: Port, name: Option<String>) -> Self {
55 use serialport::{SerialPort, SerialPortType, SerialPortInfo};
56
57 let name = port.name().or(name).map(Cow::from).unwrap_or_default();
58 let info = SerialPortInfo { port_name: name.to_string(),
59 port_type: SerialPortType::Unknown };
60
61 let mut result = Self::new(info);
62 result.set_port(port);
63 result
64 }
65
66 pub fn info(&self) -> &serialport::SerialPortInfo { &self.info }
67 pub fn is_open(&self) -> bool { self.port.is_some() }
68
69 #[cfg_attr(feature = "tracing", tracing::instrument)]
70 pub fn set_port(&mut self, port: Port) { self.port = Some(RefCell::new(port)); }
71
72 #[cfg_attr(feature = "tracing", tracing::instrument)]
73 pub fn open(&mut self) -> Result<(), serialport::Error> {
74 if self.port.is_some() {
75 Ok(())
76 } else {
77 let port = open(&self.info.port_name).map(RefCell::new)?;
78 self.port = Some(port);
79 Ok(())
80 }
81 }
82
83
84 #[cfg_attr(feature = "tracing", tracing::instrument)]
85 pub fn close(&mut self) { self.port.take(); }
86}
87
88
89#[cfg_attr(feature = "tracing", tracing::instrument)]
90pub fn open<'a, S>(port_name: S) -> Result<Port, serialport::Error>
91 where S: Into<std::borrow::Cow<'a, str>> + std::fmt::Debug {
92 trace!("opening port {port_name:?}");
93 let builder = port_builder(port_name);
94
95 let port;
96 #[cfg(not(feature = "tokio-serial"))]
97 {
98 port = builder.open()?;
99 }
100 #[cfg(feature = "tokio-serial")]
101 {
102 use tokio_serial::SerialPortBuilderExt;
103 port = builder.open_native_async().map(Box::new)?;
104 }
105
106 {
107 use serialport::SerialPort;
108 let name = port.as_ref().name();
109 let name = name.as_deref().unwrap_or("n/a");
110 trace!("opened port: {name}");
111 }
112 Ok(port)
113}
114
115fn port_builder<'a>(port_name: impl Into<std::borrow::Cow<'a, str>>) -> serialport::SerialPortBuilder {
116 serialport::new(port_name, 115200).data_bits(serialport::DataBits::Eight)
117}
118
119
120unsafe impl Send for Interface {}
125unsafe impl Sync for Interface {}