Skip to main content

android_usb_serial/
serialport_compat.rs

1//! `serialport` crate compatibility layer — full [`serialport::SerialPort`] on Android USB.
2//!
3//! Enable with Cargo feature `serialport-compat` (default). Wrap a [`crate::SerialPortHandle`]
4//! in [`SerialPortAdapter`](crate::serialport_compat::SerialPortAdapter) after
5//! [`crate::open_port`].
6
7use crate::config::{DataBits, FlowControl, LineConfig, Parity, PurgeKind, StopBits};
8use crate::error::UsbSerialError;
9use crate::port::SerialPortHandle;
10use serialport::{
11    ClearBuffer, DataBits as SpDataBits, FlowControl as SpFlowControl, Parity as SpParity,
12    SerialPort, StopBits as SpStopBits,
13};
14use std::collections::VecDeque;
15use std::io::{self, Read, Write};
16use std::sync::{Arc, Mutex};
17use std::thread;
18use std::time::{Duration, Instant};
19
20const DEFAULT_WRITE_CHUNK: usize = 512;
21const READ_POLL_MS: u64 = 1;
22
23/// USB bulk-OUT timeout per chunk: `max(clamp(port_timeout_ms, 1, 600_000), 2000)`.
24pub fn chunk_write_timeout_ms(port_timeout: Duration) -> u32 {
25    let ms = port_timeout.as_millis() as u64;
26    ms.clamp(1, 600_000).max(2000) as u32
27}
28
29fn usb_err(e: UsbSerialError) -> io::Error {
30    // Map fatal USB transport failures to disconnect-class kinds so PortRxHub tears down
31    // (BrokenPipe / …) instead of treating them as soft `ErrorKind::Other` and looping forever.
32    match &e {
33        UsbSerialError::Disconnected => io::Error::new(io::ErrorKind::BrokenPipe, e.to_string()),
34        UsbSerialError::Io(msg) => io::Error::new(io::ErrorKind::BrokenPipe, msg.clone()),
35        other => io::Error::other(other.to_string()),
36    }
37}
38
39fn sp_err(e: UsbSerialError) -> serialport::Error {
40    serialport::Error::new(serialport::ErrorKind::Unknown, e.to_string())
41}
42
43struct SerialPortInner {
44    handle: Mutex<SerialPortHandle>,
45    name: String,
46    timeout: Mutex<Duration>,
47    line_config: Mutex<LineConfig>,
48    flow_control: Mutex<FlowControl>,
49    rx_ring: Mutex<VecDeque<u8>>,
50    write_chunk: usize,
51    reader_started: Mutex<bool>,
52}
53
54impl SerialPortInner {
55    fn new(
56        handle: SerialPortHandle,
57        name: String,
58        line_config: LineConfig,
59        flow_control: FlowControl,
60        write_chunk: usize,
61    ) -> Self {
62        Self {
63            handle: Mutex::new(handle),
64            name,
65            timeout: Mutex::new(Duration::from_millis(1000)),
66            line_config: Mutex::new(line_config),
67            flow_control: Mutex::new(flow_control),
68            rx_ring: Mutex::new(VecDeque::new()),
69            write_chunk: write_chunk.max(64),
70            reader_started: Mutex::new(false),
71        }
72    }
73
74    fn start_reader(&self) -> io::Result<()> {
75        let mut started = self.reader_started.lock().unwrap();
76        if *started {
77            return Ok(());
78        }
79        self.handle
80            .lock()
81            .unwrap()
82            .start_reader()
83            .map_err(usb_err)?;
84        *started = true;
85        Ok(())
86    }
87
88    fn ensure_reader_started(&self) -> io::Result<()> {
89        if *self.reader_started.lock().unwrap() {
90            return Ok(());
91        }
92        self.start_reader()
93    }
94
95    fn timeout(&self) -> Duration {
96        *self.timeout.lock().unwrap()
97    }
98
99    fn drain_ring(&self, buf: &mut [u8]) -> usize {
100        let mut ring = self.rx_ring.lock().unwrap();
101        let n = ring.len().min(buf.len());
102        for (dst, src) in buf[..n].iter_mut().zip(ring.drain(..n)) {
103            *dst = src;
104        }
105        n
106    }
107
108    fn push_ring(&self, data: &[u8]) {
109        if data.is_empty() {
110            return;
111        }
112        self.rx_ring.lock().unwrap().extend(data);
113    }
114
115    fn ring_len(&self) -> usize {
116        self.rx_ring.lock().unwrap().len()
117    }
118
119    fn clear_ring(&self) {
120        self.rx_ring.lock().unwrap().clear();
121    }
122
123    fn refill_from_reader(&self, scratch: &mut [u8]) -> io::Result<usize> {
124        let mut handle = self.handle.lock().unwrap();
125        handle.try_read(scratch).map_err(usb_err)
126    }
127
128    fn map_purge(kind: ClearBuffer) -> PurgeKind {
129        match kind {
130            ClearBuffer::Input => PurgeKind::Rx,
131            ClearBuffer::Output => PurgeKind::Tx,
132            ClearBuffer::All => PurgeKind::Both,
133        }
134    }
135}
136
137/// Shared [`serialport::SerialPort`] adapter over [`SerialPortHandle`] + background reader.
138#[derive(Clone)]
139pub struct SerialPortAdapter {
140    inner: Arc<SerialPortInner>,
141}
142
143impl SerialPortAdapter {
144    /// Wrap an open [`SerialPortHandle`]. Call [`Self::start_reader`] after line/DTR setup.
145    pub fn new(
146        handle: SerialPortHandle,
147        name: impl Into<String>,
148        line_config: LineConfig,
149        flow_control: FlowControl,
150    ) -> io::Result<Self> {
151        Ok(Self {
152            inner: Arc::new(SerialPortInner::new(
153                handle,
154                name.into(),
155                line_config,
156                flow_control,
157                DEFAULT_WRITE_CHUNK,
158            )),
159        })
160    }
161
162    /// Start background bulk-IN reader after line/DTR setup (avoids racing driver init on OTG).
163    pub fn start_reader(&self) -> io::Result<()> {
164        self.inner.start_reader()
165    }
166
167    /// Stop background reader and close the USB driver (idempotent).
168    pub fn shutdown(&self) {
169        let mut handle = self.inner.handle.lock().unwrap();
170        handle.stop_reader();
171        handle.close();
172        self.inner.clear_ring();
173    }
174
175    pub fn with_write_chunk(mut self, chunk: usize) -> Self {
176        if let Some(inner) = Arc::get_mut(&mut self.inner) {
177            inner.write_chunk = chunk.max(64);
178        }
179        self
180    }
181}
182
183impl Read for SerialPortAdapter {
184    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
185        if buf.is_empty() {
186            return Ok(0);
187        }
188        self.inner.ensure_reader_started()?;
189        let deadline = Instant::now() + self.inner.timeout();
190        let mut scratch = [0u8; 4096];
191        loop {
192            let n = self.inner.drain_ring(buf);
193            if n > 0 {
194                return Ok(n);
195            }
196            match self.inner.refill_from_reader(&mut scratch) {
197                Ok(0) => {
198                    if Instant::now() >= deadline {
199                        return Ok(0);
200                    }
201                    thread::sleep(Duration::from_millis(READ_POLL_MS));
202                }
203                Ok(n) => self.inner.push_ring(&scratch[..n]),
204                Err(e) => {
205                    let kind = e.kind();
206                    if kind == io::ErrorKind::TimedOut || kind == io::ErrorKind::WouldBlock {
207                        if Instant::now() >= deadline {
208                            return Ok(0);
209                        }
210                        thread::sleep(Duration::from_millis(READ_POLL_MS));
211                    } else {
212                        return Err(e);
213                    }
214                }
215            }
216        }
217    }
218}
219
220impl Write for SerialPortAdapter {
221    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
222        if buf.is_empty() {
223            return Ok(0);
224        }
225        let chunk = self.inner.write_chunk;
226        let mut handle = self.inner.handle.lock().unwrap();
227        let mut offset = 0usize;
228        while offset < buf.len() {
229            let end = (offset + chunk).min(buf.len());
230            let n = handle.write(&buf[offset..end]).map_err(usb_err)?;
231            if n == 0 {
232                return Err(io::Error::new(
233                    io::ErrorKind::WriteZero,
234                    "USB write returned 0",
235                ));
236            }
237            offset += n;
238        }
239        Ok(buf.len())
240    }
241
242    fn flush(&mut self) -> io::Result<()> {
243        Ok(())
244    }
245}
246
247impl SerialPort for SerialPortAdapter {
248    fn name(&self) -> Option<String> {
249        Some(self.inner.name.clone())
250    }
251
252    fn baud_rate(&self) -> serialport::Result<u32> {
253        Ok(self.inner.line_config.lock().unwrap().baud_rate)
254    }
255
256    fn data_bits(&self) -> serialport::Result<SpDataBits> {
257        Ok(match self.inner.line_config.lock().unwrap().data_bits {
258            DataBits::Five => SpDataBits::Five,
259            DataBits::Six => SpDataBits::Six,
260            DataBits::Seven => SpDataBits::Seven,
261            DataBits::Eight => SpDataBits::Eight,
262        })
263    }
264
265    fn flow_control(&self) -> serialport::Result<SpFlowControl> {
266        Ok(match *self.inner.flow_control.lock().unwrap() {
267            FlowControl::None => SpFlowControl::None,
268            FlowControl::RtsCts | FlowControl::DtrDsr => SpFlowControl::Hardware,
269            FlowControl::XonXoff | FlowControl::XonXoffInline => SpFlowControl::Software,
270        })
271    }
272
273    fn parity(&self) -> serialport::Result<SpParity> {
274        Ok(match self.inner.line_config.lock().unwrap().parity {
275            Parity::None => SpParity::None,
276            Parity::Odd => SpParity::Odd,
277            Parity::Even => SpParity::Even,
278            Parity::Mark | Parity::Space => SpParity::None,
279        })
280    }
281
282    fn stop_bits(&self) -> serialport::Result<SpStopBits> {
283        Ok(match self.inner.line_config.lock().unwrap().stop_bits {
284            StopBits::One | StopBits::OnePointFive => SpStopBits::One,
285            StopBits::Two => SpStopBits::Two,
286        })
287    }
288
289    fn timeout(&self) -> Duration {
290        self.inner.timeout()
291    }
292
293    fn set_baud_rate(&mut self, baud_rate: u32) -> serialport::Result<()> {
294        let mut cfg = self.inner.line_config.lock().unwrap();
295        cfg.baud_rate = baud_rate;
296        self.inner
297            .handle
298            .lock()
299            .unwrap()
300            .set_line_config(*cfg)
301            .map_err(sp_err)
302    }
303
304    fn set_data_bits(&mut self, data_bits: SpDataBits) -> serialport::Result<()> {
305        let mut cfg = self.inner.line_config.lock().unwrap();
306        cfg.data_bits = match data_bits {
307            SpDataBits::Five => DataBits::Five,
308            SpDataBits::Six => DataBits::Six,
309            SpDataBits::Seven => DataBits::Seven,
310            SpDataBits::Eight => DataBits::Eight,
311        };
312        self.inner
313            .handle
314            .lock()
315            .unwrap()
316            .set_line_config(*cfg)
317            .map_err(sp_err)
318    }
319
320    fn set_flow_control(&mut self, flow_control: SpFlowControl) -> serialport::Result<()> {
321        let flow = match flow_control {
322            SpFlowControl::None => FlowControl::None,
323            SpFlowControl::Hardware => FlowControl::RtsCts,
324            SpFlowControl::Software => FlowControl::XonXoff,
325        };
326        *self.inner.flow_control.lock().unwrap() = flow;
327        self.inner
328            .handle
329            .lock()
330            .unwrap()
331            .set_flow_control(flow)
332            .map_err(sp_err)
333    }
334
335    fn set_parity(&mut self, parity: SpParity) -> serialport::Result<()> {
336        let mut cfg = self.inner.line_config.lock().unwrap();
337        cfg.parity = match parity {
338            SpParity::None => Parity::None,
339            SpParity::Odd => Parity::Odd,
340            SpParity::Even => Parity::Even,
341        };
342        self.inner
343            .handle
344            .lock()
345            .unwrap()
346            .set_line_config(*cfg)
347            .map_err(sp_err)
348    }
349
350    fn set_stop_bits(&mut self, stop_bits: SpStopBits) -> serialport::Result<()> {
351        let mut cfg = self.inner.line_config.lock().unwrap();
352        cfg.stop_bits = match stop_bits {
353            SpStopBits::One => StopBits::One,
354            SpStopBits::Two => StopBits::Two,
355        };
356        self.inner
357            .handle
358            .lock()
359            .unwrap()
360            .set_line_config(*cfg)
361            .map_err(sp_err)
362    }
363
364    fn set_timeout(&mut self, timeout: Duration) -> serialport::Result<()> {
365        *self.inner.timeout.lock().unwrap() = timeout;
366        Ok(())
367    }
368
369    fn write_request_to_send(&mut self, level: bool) -> serialport::Result<()> {
370        self.inner
371            .handle
372            .lock()
373            .unwrap()
374            .set_rts(level)
375            .map_err(sp_err)
376    }
377
378    fn write_data_terminal_ready(&mut self, level: bool) -> serialport::Result<()> {
379        self.inner
380            .handle
381            .lock()
382            .unwrap()
383            .set_dtr(level)
384            .map_err(sp_err)
385    }
386
387    fn read_clear_to_send(&mut self) -> serialport::Result<bool> {
388        Ok(self
389            .inner
390            .handle
391            .lock()
392            .unwrap()
393            .modem_status()
394            .map_err(sp_err)?
395            .cts)
396    }
397
398    fn read_data_set_ready(&mut self) -> serialport::Result<bool> {
399        Ok(self
400            .inner
401            .handle
402            .lock()
403            .unwrap()
404            .modem_status()
405            .map_err(sp_err)?
406            .dsr)
407    }
408
409    fn read_ring_indicator(&mut self) -> serialport::Result<bool> {
410        Ok(self
411            .inner
412            .handle
413            .lock()
414            .unwrap()
415            .modem_status()
416            .map_err(sp_err)?
417            .ri)
418    }
419
420    fn read_carrier_detect(&mut self) -> serialport::Result<bool> {
421        Ok(self
422            .inner
423            .handle
424            .lock()
425            .unwrap()
426            .modem_status()
427            .map_err(sp_err)?
428            .cd)
429    }
430
431    fn bytes_to_read(&self) -> serialport::Result<u32> {
432        Ok(self.inner.ring_len() as u32)
433    }
434
435    fn bytes_to_write(&self) -> serialport::Result<u32> {
436        Ok(0)
437    }
438
439    fn clear(&self, buffer_to_clear: ClearBuffer) -> serialport::Result<()> {
440        if matches!(buffer_to_clear, ClearBuffer::Input | ClearBuffer::All) {
441            self.inner.clear_ring();
442        }
443        self.inner
444            .handle
445            .lock()
446            .unwrap()
447            .clear(SerialPortInner::map_purge(buffer_to_clear))
448            .map_err(sp_err)
449    }
450
451    fn try_clone(&self) -> serialport::Result<Box<dyn SerialPort>> {
452        Ok(Box::new(SerialPortAdapter {
453            inner: self.inner.clone(),
454        }))
455    }
456
457    fn set_break(&self) -> serialport::Result<()> {
458        self.inner
459            .handle
460            .lock()
461            .unwrap()
462            .set_break(true)
463            .map_err(sp_err)
464    }
465
466    fn clear_break(&self) -> serialport::Result<()> {
467        self.inner
468            .handle
469            .lock()
470            .unwrap()
471            .set_break(false)
472            .map_err(sp_err)
473    }
474}
475
476pub fn line_config_from_serialport(
477    baud_rate: u32,
478    data_bits: SpDataBits,
479    parity: SpParity,
480    stop_bits: SpStopBits,
481) -> LineConfig {
482    LineConfig {
483        baud_rate,
484        data_bits: match data_bits {
485            SpDataBits::Five => DataBits::Five,
486            SpDataBits::Six => DataBits::Six,
487            SpDataBits::Seven => DataBits::Seven,
488            SpDataBits::Eight => DataBits::Eight,
489        },
490        parity: match parity {
491            SpParity::None => Parity::None,
492            SpParity::Odd => Parity::Odd,
493            SpParity::Even => Parity::Even,
494        },
495        stop_bits: match stop_bits {
496            SpStopBits::One => StopBits::One,
497            SpStopBits::Two => StopBits::Two,
498        },
499    }
500}
501
502pub fn flow_from_serialport(flow: SpFlowControl) -> FlowControl {
503    match flow {
504        SpFlowControl::None => FlowControl::None,
505        SpFlowControl::Hardware => FlowControl::RtsCts,
506        SpFlowControl::Software => FlowControl::XonXoff,
507    }
508}