android_usbser/
ser_cdc.rs

1use std::{
2    io::{self, Error, ErrorKind, Read, Write},
3    time::Duration,
4};
5
6use crate::SerialConfig;
7use crate::{
8    usb::{self, DeviceInfo, InterfaceInfo, SyncReader, SyncWriter},
9    UsbSerial,
10};
11use nusb::transfer::{Control, ControlType, Direction, Queue, Recipient, RequestBuffer};
12
13use serialport::{DataBits, Parity, SerialPort, StopBits};
14
15const USB_INTR_CLASS_COMM: u8 = 0x02;
16const USB_INTR_SUBCLASS_ACM: u8 = 0x02;
17const USB_INTR_CLASS_CDC_DATA: u8 = 0x0A;
18
19const SET_LINE_CODING: u8 = 0x20;
20const SET_CONTROL_LINE_STATE: u8 = 0x22;
21const SEND_BREAK: u8 = 0x23;
22
23/// This is currently a thin wrapper of USB operations, it requires hardware buffers
24/// at the device side. It uses the CDC ACM Data Interface Class to transfer data
25/// (the Communication Interface Class is used for probing and serial configuration).
26///
27/// Reference: *USB Class Definitions for Communication Devices, Version 1.1*,
28/// especially section 3.6.2.1, 5.2.3.2 and 6.2(.13).
29pub struct CdcSerial {
30    usb_path_name: String,      // the name from `android.hardware.usb.UsbDevice`
31    ctrl_index: u16,            // communication interface id as the control transfer index
32    intr_comm: nusb::Interface, // communication interface keeper
33    reader: SyncReader,         // for the bulk IN endpoint of data interface
34    writer: SyncWriter,         // for the bulk OUT endpoint of data interface
35
36    timeout: Duration,              // standard `Read` and `Write` timeout
37    ser_conf: Option<SerialConfig>, // keeps the latest settings
38    dtr_rts: (bool, bool),          // keeps the latest settings, (false, false) by default
39}
40
41impl CdcSerial {
42    /// Probes for CDC-ACM devices. It checks the current configuration of each device.
43    /// Returns an empty vector if no device is found.
44    pub fn probe() -> io::Result<Vec<DeviceInfo>> {
45        let devs = usb::list_devices()?;
46        Ok(devs
47            .into_iter()
48            .filter(|dev| Self::find_interfaces(dev).is_some())
49            .collect())
50    }
51
52    /// Connects to the CDC-ACM device, returns the `CdcSerial` handler.
53    /// Please get permission for the device before calling this function.
54    /// - `timeout`: Set for standard `Read` and `Write` traits.
55    pub fn build(dev_info: &DeviceInfo, timeout: Duration) -> io::Result<Self> {
56        let (intr_comm, intr_data) = Self::find_interfaces(dev_info)
57            .ok_or(Error::new(ErrorKind::InvalidInput, "Not a CDC-ACM device"))?;
58        let ctrl_index = intr_comm.interface_number() as u16;
59
60        let device = dev_info.open_device()?;
61        let intr_comm = device.detach_and_claim_interface(intr_comm.interface_number())?;
62        let intr_data = device.detach_and_claim_interface(intr_data.interface_number())?;
63
64        // Note: It doesn't select a setting with the highest bandwidth.
65        let (mut addr_r, mut addr_w) = (None, None);
66        for alt in intr_data.descriptors() {
67            let endps: Vec<_> = alt.endpoints().collect();
68            let endp_r = endps.iter().find(|endp| endp.direction() == Direction::In);
69            let endp_w = endps.iter().find(|endp| endp.direction() == Direction::Out);
70            if let (Some(endp_r), Some(endp_w)) = (endp_r, endp_w) {
71                addr_r = Some(endp_r.address());
72                addr_w = Some(endp_w.address());
73                break;
74            }
75        }
76        let (reader, writer) = if let (Some(r), Some(w)) = (addr_r, addr_w) {
77            (
78                SyncReader::new(intr_data.bulk_in_queue(r)),
79                SyncWriter::new(intr_data.bulk_out_queue(w)),
80            )
81        } else {
82            return Err(Error::new(ErrorKind::NotFound, "Data endpoints not found"));
83        };
84
85        Ok(Self {
86            usb_path_name: dev_info.path_name().clone(),
87            ctrl_index,
88            intr_comm,
89            reader,
90            writer,
91            timeout,
92            ser_conf: None,
93            dtr_rts: (false, false),
94        })
95    }
96
97    /// Returns (intr_comm, intr_data) if it is a CDC-ACM device.
98    fn find_interfaces(dev_info: &DeviceInfo) -> Option<(InterfaceInfo, InterfaceInfo)> {
99        let (comm, data) = (
100            dev_info.interfaces().find(|intr| {
101                intr.class() == USB_INTR_CLASS_COMM && intr.sub_class() == USB_INTR_SUBCLASS_ACM
102            }),
103            dev_info
104                .interfaces()
105                .find(|intr| intr.class() == USB_INTR_CLASS_CDC_DATA),
106        );
107        if let (Some(comm), Some(data)) = (comm, data) {
108            Some((*comm, *data))
109        } else {
110            None
111        }
112    }
113
114    /// Applies serial parameters.
115    pub fn set_config(&mut self, conf: SerialConfig) -> io::Result<()> {
116        let conf_bytes: [u8; 7] = conf.line_coding_bytes();
117        self.control_set(SET_LINE_CODING, 0, &conf_bytes)?;
118        self.ser_conf.replace(conf);
119        Ok(())
120    }
121
122    /// Sets DTR and RTS states.
123    fn set_dtr_rts(&mut self, dtr: bool, rts: bool) -> io::Result<()> {
124        let val_dtr = if dtr { 0x1 } else { 0x0 };
125        let val_rts = if rts { 0x2 } else { 0x0 };
126        let val = (val_dtr | val_rts) as u16;
127        self.control_set(SET_CONTROL_LINE_STATE, val, &[])?;
128        self.dtr_rts = (dtr, rts);
129        Ok(())
130    }
131
132    /// Sets the break state.
133    fn set_break_state(&self, val: bool) -> io::Result<()> {
134        let val = if val { 0xffff } else { 0 } as u16;
135        self.control_set(SEND_BREAK, val, &[])
136    }
137
138    fn control_set(&self, request: u8, value: u16, buf: &[u8]) -> io::Result<()> {
139        use nusb::transfer::TransferError;
140        let sz_write = self
141            .intr_comm
142            .control_out_blocking(
143                Control {
144                    control_type: ControlType::Class,
145                    recipient: Recipient::Interface,
146                    request,
147                    value,
148                    index: self.ctrl_index,
149                },
150                buf,
151                self.timeout * 2,
152            )
153            .map_err(|e| match e {
154                TransferError::Disconnected => Error::from(ErrorKind::NotConnected),
155                _ => Error::other(e),
156            })?;
157        if sz_write == buf.len() {
158            Ok(())
159        } else {
160            Err(Error::new(
161                ErrorKind::Interrupted,
162                "control_set(), wrong written size",
163            ))
164        }
165    }
166}
167
168impl Read for CdcSerial {
169    #[inline]
170    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
171        self.reader.read(buf, self.timeout)
172    }
173}
174
175impl Write for CdcSerial {
176    #[inline]
177    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
178        self.writer.write(buf, self.timeout)
179    }
180    /// Does nothing.
181    fn flush(&mut self) -> io::Result<()> {
182        Ok(())
183    }
184}
185
186impl SerialConfig {
187    fn line_coding_bytes(&self) -> [u8; 7] {
188        let mut bytes = [0u8; 7];
189        bytes[..4].copy_from_slice(&self.baud_rate.to_le_bytes());
190        bytes[4] = match self.stop_bits {
191            StopBits::One => 0u8,
192            StopBits::Two => 2u8,
193        };
194        bytes[5] = match self.parity {
195            Parity::None => 0u8,
196            Parity::Odd => 1u8,
197            Parity::Even => 2u8,
198        };
199        bytes[6] = match self.data_bits {
200            DataBits::Five => 5,
201            DataBits::Six => 6,
202            DataBits::Seven => 7,
203            DataBits::Eight => 8,
204        };
205        bytes
206    }
207}
208
209#[inline(always)]
210fn err_map_to_serialport(err: Error) -> serialport::Error {
211    let desc = err.to_string();
212    let kind = match err.kind() {
213        ErrorKind::NotConnected => serialport::ErrorKind::NoDevice,
214        ErrorKind::InvalidInput => serialport::ErrorKind::InvalidInput,
215        _ => serialport::ErrorKind::Io(err.kind()),
216    };
217    serialport::Error::new(kind, desc)
218}
219
220fn err_unsupported_op() -> serialport::Error {
221    err_map_to_serialport(Error::new(
222        ErrorKind::Unsupported,
223        "unsupported function in trait `Serialport`",
224    ))
225}
226
227impl CdcSerial {
228    #[inline]
229    fn get_conf_for_serialport(&self) -> Result<&SerialConfig, serialport::Error> {
230        self.ser_conf.as_ref().ok_or(serialport::Error::new(
231            serialport::ErrorKind::Io(std::io::ErrorKind::NotFound),
232            "serial configuration haven't been set",
233        ))
234    }
235}
236
237impl SerialPort for CdcSerial {
238    fn name(&self) -> Option<String> {
239        Some(self.usb_path_name.clone())
240    }
241
242    fn baud_rate(&self) -> serialport::Result<u32> {
243        Ok(self.get_conf_for_serialport()?.baud_rate)
244    }
245    fn data_bits(&self) -> serialport::Result<serialport::DataBits> {
246        Ok(self.get_conf_for_serialport()?.data_bits)
247    }
248    fn parity(&self) -> serialport::Result<serialport::Parity> {
249        Ok(self.get_conf_for_serialport()?.parity)
250    }
251    fn stop_bits(&self) -> serialport::Result<serialport::StopBits> {
252        Ok(self.get_conf_for_serialport()?.stop_bits)
253    }
254
255    fn flow_control(&self) -> serialport::Result<serialport::FlowControl> {
256        Ok(serialport::FlowControl::None)
257    }
258
259    fn timeout(&self) -> Duration {
260        self.timeout
261    }
262
263    fn set_baud_rate(&mut self, baud_rate: u32) -> serialport::Result<()> {
264        let mut conf = self.ser_conf.unwrap_or_default();
265        conf.baud_rate = baud_rate;
266        self.set_config(conf).map_err(err_map_to_serialport)
267    }
268
269    fn set_data_bits(&mut self, data_bits: serialport::DataBits) -> serialport::Result<()> {
270        let mut conf = self.ser_conf.unwrap_or_default();
271        conf.data_bits = data_bits;
272        self.set_config(conf).map_err(err_map_to_serialport)
273    }
274
275    fn set_parity(&mut self, parity: serialport::Parity) -> serialport::Result<()> {
276        let mut conf = self.ser_conf.unwrap_or_default();
277        conf.parity = parity;
278        self.set_config(conf).map_err(err_map_to_serialport)
279    }
280
281    fn set_stop_bits(&mut self, stop_bits: serialport::StopBits) -> serialport::Result<()> {
282        let mut conf = self.ser_conf.unwrap_or_default();
283        conf.stop_bits = stop_bits;
284        self.set_config(conf).map_err(err_map_to_serialport)
285    }
286
287    fn set_flow_control(
288        &mut self,
289        _flow_control: serialport::FlowControl,
290    ) -> serialport::Result<()> {
291        Err(err_unsupported_op())
292    }
293
294    /// Sets timeout for standard `Read` and `Write` implementations to do USB bulk transfers.
295    fn set_timeout(&mut self, timeout: Duration) -> serialport::Result<()> {
296        self.timeout = timeout;
297        Ok(())
298    }
299
300    #[inline(always)]
301    fn write_request_to_send(&mut self, value: bool) -> serialport::Result<()> {
302        let (dtr, _) = self.dtr_rts;
303        let rts = value;
304        self.set_dtr_rts(dtr, rts).map_err(err_map_to_serialport)
305    }
306
307    #[inline(always)]
308    fn write_data_terminal_ready(&mut self, value: bool) -> serialport::Result<()> {
309        let (_, rts) = self.dtr_rts;
310        let dtr = value;
311        self.set_dtr_rts(dtr, rts).map_err(err_map_to_serialport)
312    }
313
314    /// Unsupported.
315    fn read_clear_to_send(&mut self) -> serialport::Result<bool> {
316        Err(err_unsupported_op())
317    }
318    /// Unsupported.
319    fn read_data_set_ready(&mut self) -> serialport::Result<bool> {
320        Err(err_unsupported_op())
321    }
322    /// Unsupported.
323    fn read_ring_indicator(&mut self) -> serialport::Result<bool> {
324        Err(err_unsupported_op())
325    }
326    /// Unsupported.
327    fn read_carrier_detect(&mut self) -> serialport::Result<bool> {
328        Err(err_unsupported_op())
329    }
330
331    /// Returns 0 because no buffer is maintained here, and all operations are synchronous.
332    #[inline(always)]
333    fn bytes_to_read(&self) -> serialport::Result<u32> {
334        Ok(0)
335    }
336    /// Returns 0 because no buffer is maintained here, and all operations are synchronous.
337    #[inline(always)]
338    fn bytes_to_write(&self) -> serialport::Result<u32> {
339        Ok(0)
340    }
341    /// Does nothing.
342    fn clear(&self, _buffer_to_clear: serialport::ClearBuffer) -> serialport::Result<()> {
343        Ok(())
344    }
345
346    #[inline(always)]
347    fn set_break(&self) -> serialport::Result<()> {
348        self.set_break_state(true).map_err(err_map_to_serialport)
349    }
350    #[inline(always)]
351    fn clear_break(&self) -> serialport::Result<()> {
352        self.set_break_state(false).map_err(err_map_to_serialport)
353    }
354
355    /// Unsupported.
356    fn try_clone(&self) -> serialport::Result<Box<dyn serialport::SerialPort>> {
357        Err(err_unsupported_op())
358    }
359}
360
361impl UsbSerial for CdcSerial {
362    fn configure(&mut self, conf: &SerialConfig) -> std::io::Result<()> {
363        self.set_config(*conf)
364    }
365
366    fn into_queues(self) -> (Queue<RequestBuffer>, Queue<Vec<u8>>) {
367        (self.reader.into(), self.writer.into())
368    }
369
370    fn sealer(_: crate::private::Internal) {}
371}