1use crate::{
9 Child, ChildKiller, CommandBuilder, ExitStatus, MasterPty, PtyPair, PtySize,
10 PtySystem, SlavePty,
11};
12use anyhow::{ensure, Context};
13use filedescriptor::FileDescriptor;
14use serial::{
15 BaudRate, CharSize, FlowControl, Parity, PortSettings, SerialPort, StopBits,
16 SystemPort,
17};
18use std::ffi::{OsStr, OsString};
19use std::io::{Read, Result as IoResult, Write};
20use std::sync::{Arc, Mutex};
21use std::time::Duration;
22
23type Handle = Arc<Mutex<SystemPort>>;
24
25pub struct SerialTty {
26 port: OsString,
27 baud: BaudRate,
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: BaudRate::Baud9600,
39 char_size: CharSize::Bits8,
40 parity: Parity::ParityNone,
41 stop_bits: StopBits::Stop1,
42 flow_control: FlowControl::FlowSoftware,
43 }
44 }
45
46 pub fn set_baud_rate(&mut self, baud: BaudRate) {
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 = serial::open(&self.port)
70 .with_context(|| format!("openpty on serial port {:?}", self.port))?;
71
72 let settings = PortSettings {
73 baud_rate: self.baud,
74 char_size: self.char_size,
75 parity: self.parity,
76 stop_bits: self.stop_bits,
77 flow_control: self.flow_control,
78 };
79 log::debug!("serial settings: {:#?}", settings);
80 port.configure(&settings)?;
81
82 port.set_timeout(Duration::from_millis(50))?;
88
89 let port: Handle = Arc::new(Mutex::new(port));
90
91 Ok(PtyPair {
92 slave: Box::new(Slave {
93 port: Arc::clone(&port),
94 }),
95 master: Box::new(Master { port }),
96 })
97 }
98}
99
100struct Slave {
101 port: Handle,
102}
103
104impl SlavePty for Slave {
105 fn spawn_command(
106 &self,
107 cmd: CommandBuilder,
108 ) -> anyhow::Result<Box<dyn Child + Send + Sync>> {
109 ensure!(
110 cmd.is_default_prog(),
111 "can only use default prog commands with serial tty implementations"
112 );
113 Ok(Box::new(SerialChild {
114 port: Arc::clone(&self.port),
115 }))
116 }
117}
118
119struct SerialChild {
122 port: Handle,
123}
124
125impl std::fmt::Debug for SerialChild {
127 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
128 fmt.debug_struct("SerialChild").finish()
129 }
130}
131
132impl Child for SerialChild {
133 fn try_wait(&mut self) -> IoResult<Option<ExitStatus>> {
134 Ok(None)
135 }
136
137 fn wait(&mut self) -> IoResult<ExitStatus> {
138 loop {
148 std::thread::sleep(Duration::from_secs(5));
149
150 let mut port = self.port.lock().unwrap();
151 if let Err(err) = port.read_cd() {
152 log::error!("Error reading carrier detect: {:#}", err);
153 return Ok(ExitStatus::with_exit_code(1));
154 }
155 }
156 }
157
158 fn process_id(&self) -> Option<u32> {
159 None
160 }
161
162 #[cfg(windows)]
163 fn as_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
164 None
165 }
166}
167
168impl ChildKiller for SerialChild {
169 fn kill(&mut self) -> IoResult<()> {
170 Ok(())
171 }
172
173 fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
174 Box::new(SerialChildKiller)
175 }
176}
177
178#[derive(Debug)]
179struct SerialChildKiller;
180
181impl ChildKiller for SerialChildKiller {
182 fn kill(&mut self) -> IoResult<()> {
183 Ok(())
184 }
185
186 fn clone_killer(&self) -> Box<dyn ChildKiller + Send + Sync> {
187 Box::new(SerialChildKiller)
188 }
189}
190
191struct Master {
192 port: Handle,
193}
194
195impl Write for Master {
196 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
197 self.port.lock().unwrap().write(buf)
198 }
199
200 fn flush(&mut self) -> Result<(), std::io::Error> {
201 self.port.lock().unwrap().flush()
202 }
203}
204
205impl MasterPty for Master {
206 fn resize(&self, _size: PtySize) -> anyhow::Result<()> {
207 Ok(())
209 }
210
211 fn get_size(&self) -> anyhow::Result<PtySize> {
212 Ok(PtySize::default())
214 }
215
216 fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Send>> {
217 let fd = FileDescriptor::dup(&*self.port.lock().unwrap())?;
221 Ok(Box::new(Reader { fd }))
222 }
223
224 fn try_clone_writer(&self) -> anyhow::Result<Box<dyn std::io::Write + Send>> {
225 let port = Arc::clone(&self.port);
226 Ok(Box::new(Master { port }))
227 }
228
229 #[cfg(unix)]
230 fn process_group_leader(&self) -> Option<libc::pid_t> {
231 None
233 }
234}
235
236struct Reader {
237 fd: FileDescriptor,
238}
239
240impl Read for Reader {
241 fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
242 loop {
246 #[cfg(unix)]
247 {
248 use filedescriptor::{poll, pollfd, AsRawSocketDescriptor, POLLIN};
249 let mut poll_array = [pollfd {
253 fd: self.fd.as_socket_descriptor(),
254 events: POLLIN,
255 revents: 0,
256 }];
257 let _ = poll(&mut poll_array, None);
258 }
259
260 match self.fd.read(buf) {
261 Ok(0) => {
262 if cfg!(windows) {
263 continue;
266 }
267 return Err(std::io::Error::new(
268 std::io::ErrorKind::UnexpectedEof,
269 "EOF on serial port",
270 ));
271 }
272 Ok(size) => {
273 return Ok(size);
274 }
275 Err(e) => {
276 if e.kind() == std::io::ErrorKind::WouldBlock {
277 continue;
278 }
279 log::error!("serial read error: {}", e);
280 return Err(e);
281 }
282 }
283 }
284 }
285}