1use crate::{
9 Child, ChildKiller, CommandBuilder, ExitStatus, MasterPty, PtyPair, PtySize, PtySystem,
10 SlavePty,
11};
12use anyhow::{ensure, Context};
13use filedescriptor::FileDescriptor;
14use serial2::{CharSize, FlowControl, Parity, SerialPort, StopBits};
15use std::cell::RefCell;
16use std::ffi::{OsStr, OsString};
17use std::io::{Read, Result as IoResult, Write};
18#[cfg(unix)]
19use std::path::PathBuf;
20use std::sync::Arc;
21use std::time::Duration;
22
23type Handle = Arc<SerialPort>;
24
25pub struct SerialTty {
26 port: OsString,
27 baud: u32,
28 char_size: CharSize,
29 parity: Parity,
30 stop_bits: StopBits,
31 flow_control: FlowControl,
32}
33
34impl SerialTty {
35 pub fn new<T: AsRef<OsStr> + ?Sized>(port: &T) -> Self {
36 Self {
37 port: port.as_ref().to_owned(),
38 baud: 9600,
39 char_size: CharSize::Bits8,
40 parity: Parity::None,
41 stop_bits: StopBits::One,
42 flow_control: FlowControl::XonXoff,
43 }
44 }
45
46 pub fn set_baud_rate(&mut self, baud: u32) {
47 self.baud = baud;
48 }
49
50 pub fn set_char_size(&mut self, char_size: CharSize) {
51 self.char_size = char_size;
52 }
53
54 pub fn set_parity(&mut self, parity: Parity) {
55 self.parity = parity;
56 }
57
58 pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
59 self.stop_bits = stop_bits;
60 }
61
62 pub fn set_flow_control(&mut self, flow_control: FlowControl) {
63 self.flow_control = flow_control;
64 }
65}
66
67impl PtySystem for SerialTty {
68 fn openpty(&self, _size: PtySize) -> anyhow::Result<PtyPair> {
69 let mut port = SerialPort::open(&self.port, self.baud)
70 .with_context(|| format!("openpty on serial port {:?}", self.port))?;
71
72 let mut settings = port.get_configuration()?;
73 settings.set_raw();
74 settings.set_baud_rate(self.baud)?;
75 settings.set_char_size(self.char_size);
76 settings.set_flow_control(self.flow_control);
77 settings.set_parity(self.parity);
78 settings.set_stop_bits(self.stop_bits);
79 log::debug!("serial settings: {:#?}", port.get_configuration());
80 port.set_configuration(&settings)?;
81
82 port.set_read_timeout(Duration::from_millis(50))?;
88 port.set_write_timeout(Duration::from_millis(50))?;
89
90 let port: Handle = Arc::new(port);
91
92 Ok(PtyPair {
93 slave: Box::new(Slave {
94 port: Arc::clone(&port),
95 }),
96 master: Box::new(Master {
97 port,
98 took_writer: RefCell::new(false),
99 }),
100 })
101 }
102}
103
104struct Slave {
105 port: Handle,
106}
107
108impl SlavePty for Slave {
109 fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send + Sync>> {
110 ensure!(
111 cmd.is_default_prog(),
112 "can only use default prog commands with serial tty implementations"
113 );
114 Ok(Box::new(SerialChild {
115 port: Arc::clone(&self.port),
116 }))
117 }
118}
119
120struct SerialChild {
123 port: Handle,
124}
125
126impl std::fmt::Debug for SerialChild {
128 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
129 fmt.debug_struct("SerialChild").finish()
130 }
131}
132
133impl Child for SerialChild {
134 fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
135 Ok(None)
136 }
137
138 fn wait(&mut self) -> IoResult<ExitStatus> {
139 loop {
149 std::thread::sleep(Duration::from_secs(5));
150
151 let port = &self.port;
152 if let Err(err) = port.read_cd() {
153 log::error!("Error reading carrier detect: {:#}", err);
154 return Ok(ExitStatus::with_exit_code(1));
155 }
156 }
157 }
158
159 fn process_id(&self) -> Option<u32> {
160 None
161 }
162
163 #[cfg(windows)]
164 fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
165 None
166 }
167}
168
169impl ChildKiller for SerialChild {
170 fn kill(&mut self) -> IoResult<()> {
171 Ok(())
172 }
173
174 fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
175 Box::new(SerialChildKiller)
176 }
177}
178
179#[derive(Debug)]
180struct SerialChildKiller;
181
182impl ChildKiller for SerialChildKiller {
183 fn kill(&mut self) -> IoResult<()> {
184 Ok(())
185 }
186
187 fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
188 Box::new(SerialChildKiller)
189 }
190}
191
192struct Master {
193 port: Handle,
194 took_writer: RefCell<bool>,
195}
196
197struct MasterWriter {
198 port: Handle,
199}
200
201impl Write for MasterWriter {
202 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
203 self.port.write(buf)
204 }
205
206 fn flush(&mut self) -> Result<(), std::io::Error> {
207 self.port.flush()
208 }
209}
210
211impl MasterPty for Master {
212 fn resize(&self, _size: PtySize) -> anyhow::Result<()> {
213 Ok(())
215 }
216
217 fn get_size(&self) -> anyhow::Result<PtySize> {
218 Ok(PtySize::default())
220 }
221
222 fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Send>> {
223 let fd = FileDescriptor::dup(&*self.port)?;
227 Ok(Box::new(Reader { fd }))
228 }
229
230 fn take_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
231 if *self.took_writer.borrow() {
232 anyhow::bail!("cannot take writer more than once");
233 }
234 *self.took_writer.borrow_mut() = true;
235 let port = Arc::clone(&self.port);
236 Ok(Box::new(MasterWriter { port }))
237 }
238
239 #[cfg(unix)]
240 fn process_group_leader(&self) -> Option<libc::pid_t> {
241 None
243 }
244
245 #[cfg(unix)]
246 fn as_raw_fd(&self) -> Option<crate::unix::RawFd> {
247 None
248 }
249
250 #[cfg(unix)]
251 fn tty_name(&self) -> Option<PathBuf> {
252 None
253 }
254}
255
256struct Reader {
257 fd: FileDescriptor,
258}
259
260impl Read for Reader {
261 fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
262 loop {
266 #[cfg(unix)]
267 {
268 use filedescriptor::{poll, pollfd, AsRawSocketDescriptor, POLLIN};
269 let mut poll_array = [pollfd {
273 fd: self.fd.as_socket_descriptor(),
274 events: POLLIN,
275 revents: 0,
276 }];
277 let _ = poll(&mut poll_array, None);
278 }
279
280 match self.fd.read(buf) {
281 Ok(0) => {
282 if cfg!(windows) {
283 continue;
286 }
287 return Err(std::io::Error::new(
288 std::io::ErrorKind::UnexpectedEof,
289 "EOF on serial port",
290 ));
291 }
292 Ok(size) => {
293 return Ok(size);
294 }
295 Err(e) => {
296 if e.kind() == std::io::ErrorKind::WouldBlock {
297 continue;
298 }
299 log::error!("serial read error: {}", e);
300 return Err(e);
301 }
302 }
303 }
304 }
305}