Skip to main content

android_usb_serial/drivers/
ftdi.rs

1//! FTDI driver (vendor control + 2-byte RX header strip).
2
3use super::{Driver, EndpointPair, ModemStatus};
4use crate::config::{
5    DataBits, FlowControl, LineConfig, Parity, PurgeKind, StopBits, CHAR_XOFF, CHAR_XON,
6};
7use crate::error::{Result, UsbSerialError};
8use crate::reader::SerialReader;
9use crate::rx_filter::{FtdiHeaderFilter, XonXoffRxFilter};
10use crate::transport::{ControlRequest, SharedTransport};
11
12pub struct FtdiDriver {
13    port_index: usize,
14    iface: u8,
15    dtr: bool,
16    rts: bool,
17    baud_with_port: bool,
18    flow: FlowControl,
19    break_enabled: bool,
20    data_config: u16,
21    endpoints: Option<EndpointPair>,
22    transport: Option<SharedTransport>,
23    reader: Option<SerialReader>,
24}
25
26impl FtdiDriver {
27    pub fn new(port_index: usize) -> Self {
28        Self {
29            port_index,
30            iface: port_index as u8,
31            dtr: false,
32            rts: false,
33            baud_with_port: false,
34            flow: FlowControl::None,
35            break_enabled: false,
36            data_config: 0,
37            endpoints: None,
38            transport: None,
39            reader: None,
40        }
41    }
42
43    fn w_index(&self) -> u16 {
44        (self.port_index + 1) as u16
45    }
46
47    fn vendor_out(&self, request: u8, value: u16, index: u16) -> Result<()> {
48        self.transport
49            .as_ref()
50            .unwrap()
51            .control_out(&ControlRequest::vendor_out(request, value, index, vec![]))?;
52        Ok(())
53    }
54
55    fn vendor_in(&self, request: u8, value: u16, index: u16, len: usize) -> Result<Vec<u8>> {
56        self.transport
57            .as_ref()
58            .unwrap()
59            .control_in(&ControlRequest::vendor_in(request, value, index, len))
60    }
61}
62
63impl Driver for FtdiDriver {
64    fn open(&mut self, transport: &SharedTransport) -> Result<()> {
65        self.transport = Some(transport.clone());
66        self.iface = self.port_index as u8;
67        transport.claim_interface(self.iface)?;
68        self.endpoints = Some(EndpointPair::open(transport, self.iface)?);
69        self.vendor_out(0, 0, self.w_index())?;
70        let modem = if self.dtr { 0x0101 } else { 0x0100 } | if self.rts { 0x0202 } else { 0x0200 };
71        self.vendor_out(1, modem, self.w_index())?;
72        self.set_flow_control(FlowControl::None)?;
73        self.baud_with_port = transport.interfaces().len() > 1;
74        let raw = transport.raw_descriptors();
75        if raw.len() >= 14 {
76            let device_type = raw[13];
77            self.baud_with_port =
78                self.baud_with_port || device_type == 7 || device_type == 8 || device_type == 9;
79        }
80        Ok(())
81    }
82
83    fn close(&mut self) -> Result<()> {
84        if let Some(mut r) = self.reader.take() {
85            r.stop();
86        }
87        if let Some(t) = &self.transport {
88            let _ = t.release_interface(self.iface);
89        }
90        self.endpoints = None;
91        Ok(())
92    }
93
94    fn write(&mut self, data: &[u8]) -> Result<usize> {
95        let t = self.transport.as_ref().unwrap();
96        self.endpoints.as_mut().unwrap().write(t, data)
97    }
98
99    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
100        if let Some(reader) = &mut self.reader {
101            return reader.try_read(buf);
102        }
103        Ok(0)
104    }
105
106    fn set_line_config(&mut self, cfg: LineConfig) -> Result<()> {
107        self.set_baud(cfg.baud_rate)?;
108        match cfg.data_bits {
109            DataBits::Seven | DataBits::Eight => {}
110            _ => return Err(UsbSerialError::Unsupported("data bits".into())),
111        }
112        if cfg.stop_bits == StopBits::OnePointFive {
113            return Err(UsbSerialError::Unsupported("stop bits".into()));
114        }
115        self.data_config = ftdi_line_config_value(cfg, self.break_enabled);
116        self.vendor_out(4, self.data_config, self.w_index())
117    }
118
119    fn set_flow_control(&mut self, flow: FlowControl) -> Result<()> {
120        self.flow = flow;
121        let mut value = 0u16;
122        let mut index = self.w_index();
123        match flow {
124            FlowControl::None => {}
125            FlowControl::RtsCts => index |= 0x100,
126            FlowControl::DtrDsr => index |= 0x200,
127            FlowControl::XonXoffInline => {
128                value = u16::from(CHAR_XON) | (u16::from(CHAR_XOFF) << 8);
129                index |= 0x400;
130            }
131            _ => return Err(UsbSerialError::Unsupported("flow control".into())),
132        }
133        self.vendor_out(2, value, index)
134    }
135
136    fn set_dtr(&mut self, value: bool) -> Result<()> {
137        self.dtr = value;
138        let v = if value { 0x0101 } else { 0x0100 };
139        self.vendor_out(1, v, self.w_index())
140    }
141
142    fn set_rts(&mut self, value: bool) -> Result<()> {
143        self.rts = value;
144        let v = if value { 0x0202 } else { 0x0200 };
145        self.vendor_out(1, v, self.w_index())
146    }
147
148    fn set_break(&mut self, enabled: bool) -> Result<()> {
149        self.break_enabled = enabled;
150        if enabled {
151            self.data_config |= 0x4000;
152        } else {
153            self.data_config &= !0x4000;
154        }
155        self.vendor_out(4, self.data_config, self.w_index())
156    }
157
158    fn purge(&mut self, kind: PurgeKind) -> Result<()> {
159        match kind {
160            PurgeKind::Rx => self.vendor_out(0, 1, self.w_index()),
161            PurgeKind::Tx => self.vendor_out(0, 2, self.w_index()),
162            PurgeKind::Both => {
163                self.vendor_out(0, 1, self.w_index())?;
164                self.vendor_out(0, 2, self.w_index())
165            }
166        }
167    }
168
169    fn modem_status(&mut self) -> Result<ModemStatus> {
170        let data = self.vendor_in(5, 0, self.w_index(), 2)?;
171        let status = data.first().copied().unwrap_or(0);
172        Ok(ModemStatus {
173            cts: status & 0x10 != 0,
174            dsr: status & 0x20 != 0,
175            ri: status & 0x40 != 0,
176            cd: status & 0x80 != 0,
177        })
178    }
179
180    fn bulk_in_mps(&self) -> u16 {
181        self.endpoints.as_ref().map(|e| e.mps).unwrap_or(64)
182    }
183
184    fn take_bulk_in(&mut self) -> Option<Box<dyn crate::transport::BulkIn>> {
185        let transport = self.transport.as_ref()?;
186        self.endpoints.as_mut()?.take_in(transport)
187    }
188
189    fn rx_filters(&self) -> Vec<Box<dyn crate::rx_filter::RxFilter>> {
190        let mut filters: Vec<Box<dyn crate::rx_filter::RxFilter>> =
191            vec![Box::new(FtdiHeaderFilter::new(self.bulk_in_mps()))];
192        if self.flow == FlowControl::XonXoffInline {
193            filters.push(Box::new(XonXoffRxFilter::new(true)));
194        }
195        filters
196    }
197}
198
199impl FtdiDriver {
200    fn set_baud(&self, baud: u32) -> Result<()> {
201        if baud > 3_500_000 {
202            return Err(UsbSerialError::Unsupported("baud too high".into()));
203        }
204        let (value, index) = ftdi_baud_encoding(baud, self.baud_with_port, self.port_index)?;
205        self.vendor_out(3, value, index)
206    }
207}
208
209fn ftdi_line_config_value(cfg: LineConfig, break_enabled: bool) -> u16 {
210    let mut config = match cfg.data_bits {
211        DataBits::Seven => 7,
212        DataBits::Eight => 8,
213        _ => 0,
214    };
215    config |= match cfg.parity {
216        Parity::None => 0,
217        Parity::Odd => 0x100,
218        Parity::Even => 0x200,
219        Parity::Mark => 0x300,
220        Parity::Space => 0x400,
221    };
222    if cfg.stop_bits == StopBits::Two {
223        config |= 0x1000;
224    }
225    if break_enabled {
226        config |= 0x4000;
227    }
228    config
229}
230
231/// FTDI baud encoding (ported from FtdiSerialDriver.java).
232pub fn ftdi_baud_encoding(
233    baud: u32,
234    baud_with_port: bool,
235    port_index: usize,
236) -> Result<(u16, u16)> {
237    let (divisor, subdivisor, _) = if baud >= 2_500_000 {
238        (0u32, 0u32, 3_000_000u32)
239    } else if baud >= 1_750_000 {
240        (1, 0, 2_000_000)
241    } else {
242        let mut d = (24_000_000u32 << 1) / baud;
243        d = (d + 1) >> 1;
244        let sub = d & 0x07;
245        d >>= 3;
246        if d > 0x3fff {
247            return Err(UsbSerialError::Unsupported("baud too low".into()));
248        }
249        let effective = (24_000_000u32 << 1) / ((d << 3) + sub);
250        let effective = (effective + 1) >> 1;
251        let err = (1.0 - (effective as f64 / baud as f64)).abs();
252        if err >= 0.031 {
253            return Err(UsbSerialError::Unsupported(format!(
254                "baud deviation {:.1}%",
255                err * 100.0
256            )));
257        }
258        (d, sub, effective)
259    };
260    let mut value = divisor as u16;
261    let mut index = 0u16;
262    match subdivisor {
263        0 => {}
264        4 => value |= 0x4000,
265        2 => value |= 0x8000,
266        1 => value |= 0xc000,
267        3 => index |= 1,
268        5 => {
269            value |= 0x4000;
270            index |= 1;
271        }
272        6 => {
273            value |= 0x8000;
274            index |= 1;
275        }
276        7 => {
277            value |= 0xc000;
278            index |= 1;
279        }
280        _ => {}
281    }
282    if baud_with_port {
283        index = (index << 8) | (port_index as u16 + 1);
284    }
285    Ok((value, index))
286}