Skip to main content

android_usb_serial/
fake.rs

1//! In-memory transport for golden parity and on-device harness.
2//!
3//! Enable with Cargo feature `fake-transport`. Script control/bulk responses, then open a port
4//! with [`crate::open_port`] exactly as on hardware.
5
6use crate::error::{ReadOutcome, Result, UsbSerialError};
7use crate::transport::{BulkIn, BulkOut, ControlRequest, EndpointInfo, InterfaceInfo, Transport};
8use std::collections::VecDeque;
9use std::sync::{Arc, Mutex};
10
11/// Captured control transfer (for golden parity assertions).
12#[derive(Debug, Clone)]
13pub struct RecordedControl {
14    pub request_type: u8,
15    pub request: u8,
16    pub value: u16,
17    pub index: u16,
18    pub data: Vec<u8>,
19}
20
21/// Captured bulk OUT payload.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct RecordedBulkOut {
24    pub endpoint: u8,
25    pub data: Vec<u8>,
26}
27
28#[derive(Debug, Default)]
29struct FakeState {
30    device_descriptor: [u8; 18],
31    raw_descriptors: Vec<u8>,
32    interfaces: Vec<InterfaceInfo>,
33    endpoints: Vec<(u8, EndpointInfo)>,
34    recorded: Vec<RecordedControl>,
35    recorded_bulk_out: Vec<RecordedBulkOut>,
36    control_in_responses: Vec<Vec<u8>>,
37    interrupt_in_queue: VecDeque<u8>,
38    rx_queue: VecDeque<u8>,
39    tx_log: Vec<u8>,
40    bulk_read_error: Option<String>,
41    claimed: Vec<u8>,
42    /// Mimic nusb: endpoint address may only be opened once until dropped.
43    open_endpoints: Vec<u8>,
44}
45
46/// Thread-safe fake USB device for tests ([`crate::Transport`] implementor).
47#[derive(Debug, Clone)]
48pub struct FakeTransport {
49    inner: Arc<Mutex<FakeState>>,
50}
51
52impl Default for FakeTransport {
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58impl FakeTransport {
59    /// Same as [`Self::cdc_single_iface`].
60    pub fn new() -> Self {
61        Self::cdc_single_iface()
62    }
63
64    /// Single CDC ACM interface with bulk IN/OUT endpoints (castrated single-iface layout).
65    pub fn cdc_single_iface() -> Self {
66        let t = Self {
67            inner: Arc::new(Mutex::new(FakeState::default())),
68        };
69        {
70            let mut s = t.inner.lock().unwrap();
71            s.device_descriptor = [
72                18, 1, 0x00, 0x02, 0x02, 0x00, 0x00, 64, 0x34, 0x12, 0x78, 0x56, 0x00, 0x01, 0x01,
73                0x02, 0x00, 1,
74            ];
75            s.interfaces = vec![InterfaceInfo {
76                id: 0,
77                class: 2,
78                subclass: 2,
79                protocol: 0,
80            }];
81            s.endpoints = vec![
82                (
83                    0,
84                    EndpointInfo {
85                        address: 0x81,
86                        attributes: 2,
87                        max_packet_size: 64,
88                        interval: 0,
89                    },
90                ),
91                (
92                    0,
93                    EndpointInfo {
94                        address: 0x02,
95                        attributes: 2,
96                        max_packet_size: 64,
97                        interval: 0,
98                    },
99                ),
100            ];
101        }
102        t
103    }
104
105    /// FT232R-shaped single-interface layout (`0403:6001`).
106    pub fn ftdi_ft232r() -> Self {
107        let t = Self::cdc_single_iface();
108        t.set_vendor_product(0x0403, 0x6001);
109        t.set_interfaces(vec![InterfaceInfo {
110            id: 0,
111            class: 255,
112            subclass: 0,
113            protocol: 0,
114        }]);
115        t.configure_endpoints(&[(
116            0,
117            vec![
118                EndpointInfo {
119                    address: 0x81,
120                    attributes: 2,
121                    max_packet_size: 64,
122                    interval: 0,
123                },
124                EndpointInfo {
125                    address: 0x02,
126                    attributes: 2,
127                    max_packet_size: 64,
128                    interval: 0,
129                },
130            ],
131        )]);
132        t
133    }
134
135    pub fn ftdi_ft2232() -> Self {
136        let t = Self::ftdi_ft232r();
137        t.set_vendor_product(0x0403, 0x6010);
138        t.set_interfaces(vec![
139            InterfaceInfo {
140                id: 0,
141                class: 255,
142                subclass: 0,
143                protocol: 0,
144            },
145            InterfaceInfo {
146                id: 1,
147                class: 255,
148                subclass: 0,
149                protocol: 0,
150            },
151        ]);
152        t.configure_endpoints(&[
153            (
154                0,
155                vec![
156                    EndpointInfo {
157                        address: 0x81,
158                        attributes: 2,
159                        max_packet_size: 64,
160                        interval: 0,
161                    },
162                    EndpointInfo {
163                        address: 0x02,
164                        attributes: 2,
165                        max_packet_size: 64,
166                        interval: 0,
167                    },
168                ],
169            ),
170            (
171                1,
172                vec![
173                    EndpointInfo {
174                        address: 0x83,
175                        attributes: 2,
176                        max_packet_size: 64,
177                        interval: 0,
178                    },
179                    EndpointInfo {
180                        address: 0x04,
181                        attributes: 2,
182                        max_packet_size: 64,
183                        interval: 0,
184                    },
185                ],
186            ),
187        ]);
188        t.patch_device_descriptor(|d| d[13] = 7);
189        t
190    }
191
192    pub fn cp2102() -> Self {
193        Self::ftdi_ft232r().also(|t| t.set_vendor_product(0x10C4, 0xEA60))
194    }
195
196    pub fn cp2105() -> Self {
197        let t = Self::cp2102();
198        t.set_vendor_product(0x10C4, 0xEA70);
199        t.set_interfaces(vec![
200            InterfaceInfo {
201                id: 0,
202                class: 255,
203                subclass: 0,
204                protocol: 0,
205            },
206            InterfaceInfo {
207                id: 1,
208                class: 255,
209                subclass: 0,
210                protocol: 0,
211            },
212        ]);
213        t.configure_endpoints(&[
214            (
215                0,
216                vec![
217                    EndpointInfo {
218                        address: 0x81,
219                        attributes: 2,
220                        max_packet_size: 64,
221                        interval: 0,
222                    },
223                    EndpointInfo {
224                        address: 0x02,
225                        attributes: 2,
226                        max_packet_size: 64,
227                        interval: 0,
228                    },
229                ],
230            ),
231            (
232                1,
233                vec![
234                    EndpointInfo {
235                        address: 0x83,
236                        attributes: 2,
237                        max_packet_size: 64,
238                        interval: 0,
239                    },
240                    EndpointInfo {
241                        address: 0x04,
242                        attributes: 2,
243                        max_packet_size: 64,
244                        interval: 0,
245                    },
246                ],
247            ),
248        ]);
249        t
250    }
251
252    pub fn ch340_dual_iface() -> Self {
253        let t = Self::cdc_single_iface();
254        t.set_vendor_product(0x1A86, 0x7523);
255        t.set_interfaces(vec![
256            InterfaceInfo {
257                id: 0,
258                class: 255,
259                subclass: 0,
260                protocol: 0,
261            },
262            InterfaceInfo {
263                id: 1,
264                class: 255,
265                subclass: 0,
266                protocol: 0,
267            },
268        ]);
269        t.configure_endpoints(&[(
270            1,
271            vec![
272                EndpointInfo {
273                    address: 0x82,
274                    attributes: 2,
275                    max_packet_size: 64,
276                    interval: 0,
277                },
278                EndpointInfo {
279                    address: 0x03,
280                    attributes: 2,
281                    max_packet_size: 64,
282                    interval: 0,
283                },
284            ],
285        )]);
286        t
287    }
288
289    pub fn pl2303_hx() -> Self {
290        let t = Self::cdc_single_iface();
291        t.set_vendor_product(0x067B, 0x2303);
292        t.patch_device_descriptor(|d| d[4] = 0);
293        t.configure_endpoints(&[(
294            0,
295            vec![
296                EndpointInfo {
297                    address: 0x81,
298                    attributes: 3,
299                    max_packet_size: 64,
300                    interval: 1,
301                },
302                EndpointInfo {
303                    address: 0x02,
304                    attributes: 2,
305                    max_packet_size: 64,
306                    interval: 0,
307                },
308                EndpointInfo {
309                    address: 0x83,
310                    attributes: 2,
311                    max_packet_size: 64,
312                    interval: 0,
313                },
314            ],
315        )]);
316        t.set_interfaces(vec![InterfaceInfo {
317            id: 0,
318            class: 255,
319            subclass: 0,
320            protocol: 0,
321        }]);
322        t
323    }
324
325    pub fn pl2303_hxn() -> Self {
326        let t = Self::pl2303_hx();
327        t.patch_device_descriptor(|d| {
328            d[4] = 0x00;
329            d[7] = 64;
330            d[2] = 0x00;
331            d[3] = 0x02;
332        });
333        t
334    }
335
336    pub fn pl2303_type01() -> Self {
337        let t = Self::pl2303_hx();
338        t.patch_device_descriptor(|d| d[4] = 0x02);
339        t
340    }
341
342    pub fn pl2303_ta() -> Self {
343        let t = Self::pl2303_hx();
344        t.patch_device_descriptor(|d| {
345            d[2] = 0x00;
346            d[3] = 0x02;
347            d[12] = 0x00;
348            d[13] = 0x03;
349        });
350        t
351    }
352
353    pub fn cdc_iad() -> Self {
354        let t = Self::cdc_single_iface();
355        t.set_vendor_product(0x2341, 0x0043);
356        t.patch_device_descriptor(|d| {
357            d[4] = 0xEF;
358            d[5] = 0x02;
359            d[6] = 0x01;
360        });
361        let i0 = InterfaceInfo {
362            id: 0,
363            class: 2,
364            subclass: 2,
365            protocol: 0,
366        };
367        let i1 = InterfaceInfo {
368            id: 1,
369            class: 10,
370            subclass: 0,
371            protocol: 0,
372        };
373        t.set_interfaces(vec![i0, i1]);
374        t.configure_endpoints(&[
375            (
376                0,
377                vec![EndpointInfo {
378                    address: 0x81,
379                    attributes: 3,
380                    max_packet_size: 64,
381                    interval: 1,
382                }],
383            ),
384            (
385                1,
386                vec![
387                    EndpointInfo {
388                        address: 0x82,
389                        attributes: 2,
390                        max_packet_size: 64,
391                        interval: 0,
392                    },
393                    EndpointInfo {
394                        address: 0x03,
395                        attributes: 2,
396                        max_packet_size: 64,
397                        interval: 0,
398                    },
399                ],
400            ),
401        ]);
402        // minimal IAD descriptor in raw config
403        t.set_raw_descriptors(vec![
404            9, 4, 0, 0, 1, 2, 2, 0, 0, 7, 5, 0x81, 3, 64, 0, 1, 9, 4, 1, 0, 2, 10, 0, 0, 7, 5,
405            0x82, 2, 64, 0, 7, 5, 0x03, 2, 64, 0, 8, 11, 0, 2, 2, 2, 0, 0,
406        ]);
407        t
408    }
409
410    pub fn cdc_multi() -> Self {
411        let t = Self::cdc_iad();
412        t.set_interfaces(vec![
413            InterfaceInfo {
414                id: 0,
415                class: 2,
416                subclass: 2,
417                protocol: 0,
418            },
419            InterfaceInfo {
420                id: 1,
421                class: 10,
422                subclass: 0,
423                protocol: 0,
424            },
425            InterfaceInfo {
426                id: 2,
427                class: 2,
428                subclass: 2,
429                protocol: 0,
430            },
431            InterfaceInfo {
432                id: 3,
433                class: 10,
434                subclass: 0,
435                protocol: 0,
436            },
437        ]);
438        t.configure_endpoints(&[
439            (
440                1,
441                vec![
442                    EndpointInfo {
443                        address: 0x82,
444                        attributes: 2,
445                        max_packet_size: 64,
446                        interval: 0,
447                    },
448                    EndpointInfo {
449                        address: 0x03,
450                        attributes: 2,
451                        max_packet_size: 64,
452                        interval: 0,
453                    },
454                ],
455            ),
456            (
457                3,
458                vec![
459                    EndpointInfo {
460                        address: 0x84,
461                        attributes: 2,
462                        max_packet_size: 64,
463                        interval: 0,
464                    },
465                    EndpointInfo {
466                        address: 0x05,
467                        attributes: 2,
468                        max_packet_size: 64,
469                        interval: 0,
470                    },
471                ],
472            ),
473        ]);
474        t
475    }
476
477    pub fn gsm_modem() -> Self {
478        let t = Self::cdc_single_iface();
479        t.set_vendor_product(0x1782, 0x4D10);
480        t.set_interfaces(vec![InterfaceInfo {
481            id: 0,
482            class: 255,
483            subclass: 0,
484            protocol: 0,
485        }]);
486        t.configure_endpoints(&[(
487            0,
488            vec![
489                EndpointInfo {
490                    address: 0x81,
491                    attributes: 2,
492                    max_packet_size: 64,
493                    interval: 0,
494                },
495                EndpointInfo {
496                    address: 0x02,
497                    attributes: 2,
498                    max_packet_size: 64,
499                    interval: 0,
500                },
501            ],
502        )]);
503        t
504    }
505
506    pub fn chrome_ccd_3port() -> Self {
507        let t = Self::cdc_single_iface();
508        t.set_vendor_product(0x18D1, 0x5014);
509        let mut ifaces = Vec::new();
510        let mut eps = Vec::new();
511        for n in 0..3u8 {
512            ifaces.push(InterfaceInfo {
513                id: n,
514                class: 255,
515                subclass: 0,
516                protocol: 0,
517            });
518            eps.push((
519                n,
520                vec![
521                    EndpointInfo {
522                        address: 0x81 + n * 2,
523                        attributes: 2,
524                        max_packet_size: 64,
525                        interval: 0,
526                    },
527                    EndpointInfo {
528                        address: 0x02 + n * 2,
529                        attributes: 2,
530                        max_packet_size: 64,
531                        interval: 0,
532                    },
533                ],
534            ));
535        }
536        t.set_interfaces(ifaces);
537        t.configure_endpoints(&eps);
538        t
539    }
540
541    fn also<F: FnOnce(&Self)>(self, f: F) -> Self {
542        f(&self);
543        self
544    }
545
546    pub fn recorded_bulk_out(&self) -> Vec<RecordedBulkOut> {
547        self.inner.lock().unwrap().recorded_bulk_out.clone()
548    }
549
550    pub fn push_rx(&self, data: &[u8]) {
551        let mut s = self.inner.lock().unwrap();
552        s.rx_queue.extend(data);
553    }
554
555    pub fn push_interrupt_in(&self, data: &[u8]) {
556        let mut s = self.inner.lock().unwrap();
557        s.interrupt_in_queue.extend(data);
558    }
559
560    /// Drain and return bytes written to bulk OUT (test asserts).
561    pub fn take_tx(&self) -> Vec<u8> {
562        let mut s = self.inner.lock().unwrap();
563        std::mem::take(&mut s.tx_log)
564    }
565
566    /// Snapshot recorded control transfers.
567    pub fn recorded_controls(&self) -> Vec<RecordedControl> {
568        self.inner.lock().unwrap().recorded.clone()
569    }
570
571    pub fn clear_recorded(&self) {
572        let mut s = self.inner.lock().unwrap();
573        s.recorded.clear();
574        s.recorded_bulk_out.clear();
575    }
576
577    pub fn claimed_interfaces(&self) -> Vec<u8> {
578        self.inner.lock().unwrap().claimed.clone()
579    }
580
581    /// Queue the next `control_in` response payload (FIFO).
582    pub fn script_control_in_response(&self, data: Vec<u8>) {
583        self.inner.lock().unwrap().control_in_responses.push(data);
584    }
585
586    pub fn inject_bulk_read_error(&self, msg: impl Into<String>) {
587        self.inner.lock().unwrap().bulk_read_error = Some(msg.into());
588    }
589
590    pub fn set_interfaces(&self, interfaces: Vec<InterfaceInfo>) {
591        self.inner.lock().unwrap().interfaces = interfaces;
592    }
593
594    pub fn configure_endpoints(&self, layout: &[(u8, Vec<EndpointInfo>)]) {
595        let mut s = self.inner.lock().unwrap();
596        s.endpoints = layout
597            .iter()
598            .flat_map(|(iface, eps)| eps.iter().map(move |ep| (*iface, *ep)))
599            .collect();
600    }
601
602    pub fn set_raw_descriptors(&self, raw: Vec<u8>) {
603        self.inner.lock().unwrap().raw_descriptors = raw;
604    }
605
606    pub fn set_vendor_product(&self, vendor_id: u16, product_id: u16) {
607        let mut s = self.inner.lock().unwrap();
608        s.device_descriptor[8] = (vendor_id & 0xff) as u8;
609        s.device_descriptor[9] = (vendor_id >> 8) as u8;
610        s.device_descriptor[10] = (product_id & 0xff) as u8;
611        s.device_descriptor[11] = (product_id >> 8) as u8;
612    }
613
614    pub fn patch_device_descriptor(&self, mut patch: impl FnMut(&mut [u8; 18])) {
615        let mut s = self.inner.lock().unwrap();
616        patch(&mut s.device_descriptor);
617    }
618}
619
620struct FakeBulkIn {
621    inner: Arc<Mutex<FakeState>>,
622    interrupt: bool,
623    endpoint: u8,
624}
625
626impl Drop for FakeBulkIn {
627    fn drop(&mut self) {
628        if let Ok(mut s) = self.inner.lock() {
629            s.open_endpoints.retain(|&e| e != self.endpoint);
630        }
631    }
632}
633
634impl BulkIn for FakeBulkIn {
635    fn read(&mut self, buf: &mut [u8], _timeout_ms: u32) -> Result<ReadOutcome> {
636        let mut s = self.inner.lock().unwrap();
637        if let Some(err) = s.bulk_read_error.take() {
638            return Err(UsbSerialError::Io(err));
639        }
640        let queue = if self.interrupt {
641            &mut s.interrupt_in_queue
642        } else {
643            &mut s.rx_queue
644        };
645        if queue.is_empty() {
646            return Ok(ReadOutcome::TimedOut);
647        }
648        let n = buf.len().min(queue.len());
649        for (i, byte) in queue.drain(..n).enumerate() {
650            buf[i] = byte;
651        }
652        Ok(ReadOutcome::Data(buf[..n].to_vec()))
653    }
654
655    fn cancel_all(&mut self) {}
656
657    fn clear_halt(&mut self) -> Result<()> {
658        Ok(())
659    }
660}
661
662struct FakeBulkOut {
663    inner: Arc<Mutex<FakeState>>,
664    endpoint: u8,
665}
666
667impl Drop for FakeBulkOut {
668    fn drop(&mut self) {
669        if let Ok(mut s) = self.inner.lock() {
670            s.open_endpoints.retain(|&e| e != self.endpoint);
671        }
672    }
673}
674
675impl BulkOut for FakeBulkOut {
676    fn write(&mut self, data: &[u8], _timeout_ms: u32) -> Result<usize> {
677        let mut s = self.inner.lock().unwrap();
678        s.tx_log.extend_from_slice(data);
679        s.recorded_bulk_out.push(RecordedBulkOut {
680            endpoint: self.endpoint,
681            data: data.to_vec(),
682        });
683        Ok(data.len())
684    }
685
686    fn clear_halt(&mut self) -> Result<()> {
687        Ok(())
688    }
689}
690
691impl Transport for FakeTransport {
692    fn raw_device_descriptor(&self) -> [u8; 18] {
693        self.inner.lock().unwrap().device_descriptor
694    }
695
696    fn raw_descriptors(&self) -> Vec<u8> {
697        self.inner.lock().unwrap().raw_descriptors.clone()
698    }
699
700    fn device_class(&self) -> u8 {
701        self.raw_device_descriptor()[4]
702    }
703
704    fn interfaces(&self) -> Vec<InterfaceInfo> {
705        self.inner.lock().unwrap().interfaces.clone()
706    }
707
708    fn endpoints(&self, interface: u8) -> Vec<EndpointInfo> {
709        self.inner
710            .lock()
711            .unwrap()
712            .endpoints
713            .iter()
714            .filter(|(iface, _)| *iface == interface)
715            .map(|(_, ep)| *ep)
716            .collect()
717    }
718
719    fn claim_interface(&self, interface: u8) -> Result<()> {
720        self.inner.lock().unwrap().claimed.push(interface);
721        Ok(())
722    }
723
724    fn release_interface(&self, interface: u8) -> Result<()> {
725        let mut s = self.inner.lock().unwrap();
726        s.claimed.retain(|&i| i != interface);
727        Ok(())
728    }
729
730    fn control_out(&self, req: &ControlRequest) -> Result<usize> {
731        let mut s = self.inner.lock().unwrap();
732        s.recorded.push(RecordedControl {
733            request_type: req.request_type,
734            request: req.request,
735            value: req.value,
736            index: req.index,
737            data: req.data.clone(),
738        });
739        Ok(req.data.len())
740    }
741
742    fn control_in(&self, req: &ControlRequest) -> Result<Vec<u8>> {
743        let mut s = self.inner.lock().unwrap();
744        s.recorded.push(RecordedControl {
745            request_type: req.request_type,
746            request: req.request,
747            value: req.value,
748            index: req.index,
749            data: req.data.clone(),
750        });
751        if let Some(resp) = s.control_in_responses.pop() {
752            return Ok(resp);
753        }
754        Ok(req.data.clone())
755    }
756
757    fn open_bulk_in(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkIn>> {
758        self.mark_endpoint_open(endpoint)?;
759        Ok(Box::new(FakeBulkIn {
760            inner: self.inner.clone(),
761            interrupt: false,
762            endpoint,
763        }))
764    }
765
766    fn open_bulk_out(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkOut>> {
767        self.mark_endpoint_open(endpoint)?;
768        Ok(Box::new(FakeBulkOut {
769            inner: self.inner.clone(),
770            endpoint,
771        }))
772    }
773
774    fn open_interrupt_in(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkIn>> {
775        self.mark_endpoint_open(endpoint)?;
776        Ok(Box::new(FakeBulkIn {
777            inner: self.inner.clone(),
778            interrupt: true,
779            endpoint,
780        }))
781    }
782}
783
784impl FakeTransport {
785    fn mark_endpoint_open(&self, endpoint: u8) -> Result<()> {
786        let mut s = self.inner.lock().unwrap();
787        if s.open_endpoints.contains(&endpoint) {
788            return Err(UsbSerialError::Io("endpoint already in use".into()));
789        }
790        s.open_endpoints.push(endpoint);
791        Ok(())
792    }
793}