Skip to main content

android_usb_serial/drivers/
prolific.rs

1//! Prolific PL2303 driver (ported from ProlificSerialDriver.java).
2
3use super::{line_coding_bytes, Driver, ModemStatus, WRITE_TIMEOUT_MS};
4use crate::config::{DataBits, FlowControl, LineConfig, Parity, PurgeKind, StopBits};
5use crate::error::{Result, UsbSerialError};
6use crate::reader::SerialReader;
7use crate::rx_filter::XonXoffRxFilter;
8use crate::transport::{BulkIn, ControlRequest, EndpointInfo, SharedTransport};
9use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
10use std::sync::{Arc, Mutex};
11use std::thread::{self, JoinHandle};
12
13const WRITE_ENDPOINT: u8 = 0x02;
14const READ_ENDPOINT: u8 = 0x83;
15const INTERRUPT_ENDPOINT: u8 = 0x81;
16
17const VENDOR_READ_REQUEST: u8 = 0x01;
18const VENDOR_WRITE_REQUEST: u8 = 0x01;
19const VENDOR_READ_HXN_REQUEST: u8 = 0x81;
20const VENDOR_WRITE_HXN_REQUEST: u8 = 0x80;
21
22const RESET_HXN_REQUEST: u8 = 0x07;
23const FLUSH_RX_REQUEST: u8 = 0x08;
24const FLUSH_TX_REQUEST: u8 = 0x09;
25const SET_LINE_REQUEST: u8 = 0x20;
26const SET_CONTROL_REQUEST: u8 = 0x22;
27const SEND_BREAK_REQUEST: u8 = 0x23;
28const GET_CONTROL_HXN_REQUEST: u8 = 0x80;
29const GET_CONTROL_REQUEST: u8 = 0x87;
30const STATUS_NOTIFICATION: u8 = 0xa1;
31
32const RESET_HXN_RX_PIPE: u16 = 1;
33const RESET_HXN_TX_PIPE: u16 = 2;
34
35const CONTROL_DTR: u16 = 0x01;
36const CONTROL_RTS: u16 = 0x02;
37
38const GET_CONTROL_FLAG_CD: u8 = 0x02;
39const GET_CONTROL_FLAG_DSR: u8 = 0x04;
40const GET_CONTROL_FLAG_RI: u8 = 0x01;
41const GET_CONTROL_FLAG_CTS: u8 = 0x08;
42
43const GET_CONTROL_HXN_FLAG_CD: u8 = 0x40;
44const GET_CONTROL_HXN_FLAG_DSR: u8 = 0x20;
45const GET_CONTROL_HXN_FLAG_RI: u8 = 0x80;
46const GET_CONTROL_HXN_FLAG_CTS: u8 = 0x08;
47
48const STATUS_FLAG_CD: u8 = 0x01;
49const STATUS_FLAG_DSR: u8 = 0x02;
50const STATUS_FLAG_RI: u8 = 0x08;
51const STATUS_FLAG_CTS: u8 = 0x80;
52
53const STATUS_BUFFER_SIZE: usize = 10;
54const STATUS_BYTE_IDX: usize = 8;
55
56const STANDARD_BAUD_RATES: &[u32] = &[
57    75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600,
58    115200, 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400, 806400, 921600,
59    1228800, 2457600, 3000000, 6000000,
60];
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63enum DeviceType {
64    Type01,
65    TypeT,
66    TypeHx,
67    TypeHxn,
68}
69
70struct ProlificEndpoints {
71    data: super::EndpointPair,
72    interrupt_ep: u8,
73    interrupt_mps: u16,
74}
75
76pub struct ProlificDriver {
77    #[allow(dead_code)]
78    port_index: usize,
79    iface: u8,
80    device_type: DeviceType,
81    control_lines: u16,
82    flow: FlowControl,
83    baud_rate: i32,
84    data_bits: i32,
85    stop_bits: i32,
86    parity: i32,
87    endpoints: Option<ProlificEndpoints>,
88    transport: Option<SharedTransport>,
89    reader: Option<SerialReader>,
90    status: Arc<AtomicU8>,
91    status_thread: Option<JoinHandle<()>>,
92    stop_status_thread: Arc<AtomicBool>,
93    status_error: Arc<Mutex<Option<String>>>,
94    status_started: bool,
95}
96
97impl ProlificDriver {
98    pub fn new(port_index: usize) -> Self {
99        Self {
100            port_index,
101            iface: 0,
102            device_type: DeviceType::TypeHx,
103            control_lines: 0,
104            flow: FlowControl::None,
105            baud_rate: -1,
106            data_bits: -1,
107            stop_bits: -1,
108            parity: -1,
109            endpoints: None,
110            transport: None,
111            reader: None,
112            status: Arc::new(AtomicU8::new(0)),
113            status_thread: None,
114            stop_status_thread: Arc::new(AtomicBool::new(false)),
115            status_error: Arc::new(Mutex::new(None)),
116            status_started: false,
117        }
118    }
119
120    fn vendor_read_request(&self) -> u8 {
121        if self.device_type == DeviceType::TypeHxn {
122            VENDOR_READ_HXN_REQUEST
123        } else {
124            VENDOR_READ_REQUEST
125        }
126    }
127
128    fn vendor_write_request(&self) -> u8 {
129        if self.device_type == DeviceType::TypeHxn {
130            VENDOR_WRITE_HXN_REQUEST
131        } else {
132            VENDOR_WRITE_REQUEST
133        }
134    }
135
136    fn vendor_in(&self, value: u16, index: u16, length: usize) -> Result<Vec<u8>> {
137        self.transport
138            .as_ref()
139            .unwrap()
140            .control_in(&ControlRequest {
141                request_type: 0xC0,
142                request: self.vendor_read_request(),
143                value,
144                index,
145                data: vec![0; length],
146                timeout_ms: WRITE_TIMEOUT_MS,
147            })
148    }
149
150    fn vendor_out(&self, value: u16, index: u16, data: Vec<u8>) -> Result<()> {
151        self.transport
152            .as_ref()
153            .unwrap()
154            .control_out(&ControlRequest {
155                request_type: 0x40,
156                request: self.vendor_write_request(),
157                value,
158                index,
159                data,
160                timeout_ms: WRITE_TIMEOUT_MS,
161            })?;
162        Ok(())
163    }
164
165    fn ctrl_out(&self, request: u8, value: u16, index: u16, data: Vec<u8>) -> Result<()> {
166        self.transport
167            .as_ref()
168            .unwrap()
169            .control_out(&ControlRequest::class_out(request, value, index, data))?;
170        Ok(())
171    }
172
173    fn detect_device_type(&mut self, transport: &SharedTransport) -> Result<()> {
174        let raw = transport.raw_descriptors();
175        let desc = if raw.len() >= 14 {
176            raw
177        } else {
178            transport.raw_device_descriptor().to_vec()
179        };
180        if desc.len() < 14 {
181            return Err(UsbSerialError::Io(
182                "could not get device descriptors".into(),
183            ));
184        }
185        let usb_version = u16::from_le_bytes([desc[2], desc[3]]);
186        let device_version = u16::from_le_bytes([desc[12], desc[13]]);
187        let max_packet_size0 = desc[7];
188        let device_class = transport.device_class();
189
190        self.device_type = if device_class == 0x02 || max_packet_size0 != 64 {
191            DeviceType::Type01
192        } else if usb_version == 0x200 {
193            if (device_version == 0x300 || device_version == 0x500) && self.test_hx_status() {
194                DeviceType::TypeT
195            } else {
196                DeviceType::TypeHxn
197            }
198        } else {
199            DeviceType::TypeHx
200        };
201        Ok(())
202    }
203
204    fn test_hx_status(&self) -> bool {
205        self.transport
206            .as_ref()
207            .unwrap()
208            .control_in(&ControlRequest {
209                request_type: 0xC0,
210                request: VENDOR_READ_REQUEST,
211                value: 0x8080,
212                index: 0,
213                data: vec![0; 1],
214                timeout_ms: WRITE_TIMEOUT_MS,
215            })
216            .is_ok()
217    }
218
219    fn reset_device(&self) -> Result<()> {
220        self.purge_hw_buffers(true, true)
221    }
222
223    fn purge_hw_buffers(&self, purge_write: bool, purge_read: bool) -> Result<()> {
224        if self.device_type == DeviceType::TypeHxn {
225            let mut index = 0u16;
226            if purge_write {
227                index |= RESET_HXN_RX_PIPE;
228            }
229            if purge_read {
230                index |= RESET_HXN_TX_PIPE;
231            }
232            if index != 0 {
233                self.vendor_out(RESET_HXN_REQUEST as u16, index, vec![])?;
234            }
235        } else {
236            if purge_write {
237                self.vendor_out(FLUSH_RX_REQUEST as u16, 0, vec![])?;
238            }
239            if purge_read {
240                self.vendor_out(FLUSH_TX_REQUEST as u16, 0, vec![])?;
241            }
242        }
243        Ok(())
244    }
245
246    fn do_black_magic(&self) -> Result<()> {
247        if self.device_type == DeviceType::TypeHxn {
248            return Ok(());
249        }
250        self.vendor_in(0x8484, 0, 1)?;
251        self.vendor_out(0x0404, 0, vec![])?;
252        self.vendor_in(0x8484, 0, 1)?;
253        self.vendor_in(0x8383, 0, 1)?;
254        self.vendor_in(0x8484, 0, 1)?;
255        self.vendor_out(0x0404, 1, vec![])?;
256        self.vendor_in(0x8484, 0, 1)?;
257        self.vendor_in(0x8383, 0, 1)?;
258        self.vendor_out(0, 1, vec![])?;
259        self.vendor_out(1, 0, vec![])?;
260        let magic = if self.device_type == DeviceType::Type01 {
261            0x24u16
262        } else {
263            0x44
264        };
265        self.vendor_out(2, magic, vec![])
266    }
267
268    fn set_control_lines(&mut self, value: u16) -> Result<()> {
269        self.ctrl_out(SET_CONTROL_REQUEST, value, 0, vec![])?;
270        self.control_lines = value;
271        Ok(())
272    }
273
274    fn open_endpoints(transport: &SharedTransport, iface: u8) -> Result<ProlificEndpoints> {
275        let eps = transport.endpoints(iface);
276        let find = |addr: u8| -> Result<EndpointInfo> {
277            eps.iter()
278                .find(|e| e.address == addr)
279                .copied()
280                .ok_or_else(|| {
281                    UsbSerialError::ProbeFailed(format!("missing endpoint 0x{addr:02x}"))
282                })
283        };
284        let in_ep = find(READ_ENDPOINT)?;
285        let out_ep = find(WRITE_ENDPOINT)?;
286        let int_ep = find(INTERRUPT_ENDPOINT)?;
287        Ok(ProlificEndpoints {
288            data: super::EndpointPair::from_addresses(
289                in_ep.address,
290                out_ep.address,
291                in_ep.max_packet_size,
292            ),
293            interrupt_ep: int_ep.address,
294            interrupt_mps: int_ep.max_packet_size,
295        })
296    }
297
298    fn ensure_status_thread(&mut self) -> Result<()> {
299        if self.status_started {
300            return Ok(());
301        }
302        self.status.store(0, Ordering::Relaxed);
303
304        let initial = if self.device_type == DeviceType::TypeHxn {
305            let data = self.vendor_in(GET_CONTROL_HXN_REQUEST as u16, 0, 1)?;
306            decode_vendor_status_hxn(data[0])
307        } else {
308            let data = self.vendor_in(GET_CONTROL_REQUEST as u16, 0, 1)?;
309            decode_vendor_status(data[0])
310        };
311        self.status.store(initial, Ordering::Relaxed);
312
313        let transport = self.transport.as_ref().unwrap().clone();
314        let interrupt_ep = self.endpoints.as_ref().unwrap().interrupt_ep;
315        let interrupt_mps = self.endpoints.as_ref().unwrap().interrupt_mps;
316        let stop = self.stop_status_thread.clone();
317        let status = self.status.clone();
318        let status_error = self.status_error.clone();
319
320        stop.store(false, Ordering::Relaxed);
321        let handle = thread::spawn(move || {
322            let mut interrupt = match transport.open_interrupt_in(interrupt_ep, interrupt_mps) {
323                Ok(ep) => ep,
324                Err(e) => {
325                    *status_error.lock().unwrap() = Some(e.to_string());
326                    return;
327                }
328            };
329            let mut buffer = vec![0u8; STATUS_BUFFER_SIZE];
330            while !stop.load(Ordering::Relaxed) {
331                match interrupt.read(&mut buffer, 500) {
332                    Ok(crate::error::ReadOutcome::Data(data)) => {
333                        if data.len() != STATUS_BUFFER_SIZE {
334                            *status_error.lock().unwrap() = Some(format!(
335                                "invalid status notification, expected {STATUS_BUFFER_SIZE} bytes, got {}",
336                                data.len()
337                            ));
338                            break;
339                        }
340                        if data[0] != STATUS_NOTIFICATION {
341                            *status_error.lock().unwrap() = Some(format!(
342                                "invalid status notification, expected 0x{STATUS_NOTIFICATION:02x}, got 0x{:02x}",
343                                data[0]
344                            ));
345                            break;
346                        }
347                        status.store(data[STATUS_BYTE_IDX], Ordering::Relaxed);
348                    }
349                    Ok(crate::error::ReadOutcome::TimedOut)
350                    | Ok(crate::error::ReadOutcome::Cancelled) => {}
351                    Err(e) => {
352                        if !stop.load(Ordering::Relaxed) {
353                            *status_error.lock().unwrap() = Some(e.to_string());
354                        }
355                        break;
356                    }
357                }
358            }
359        });
360        self.status_thread = Some(handle);
361        self.status_started = true;
362        Ok(())
363    }
364
365    fn get_status(&mut self) -> Result<u8> {
366        self.ensure_status_thread()?;
367        if let Some(msg) = self.status_error.lock().unwrap().take() {
368            return Err(UsbSerialError::Io(msg));
369        }
370        Ok(self.status.load(Ordering::Relaxed))
371    }
372
373    fn stop_status_thread(&mut self) {
374        self.stop_status_thread.store(true, Ordering::Relaxed);
375        if let Some(handle) = self.status_thread.take() {
376            let _ = handle.join();
377        }
378        self.stop_status_thread.store(false, Ordering::Relaxed);
379        self.status_started = false;
380        *self.status_error.lock().unwrap() = None;
381    }
382
383    fn filter_baud_rate(&self, baud_rate: u32) -> Result<u32> {
384        if baud_rate == 0 {
385            return Err(UsbSerialError::Unsupported(format!(
386                "invalid baud rate: {baud_rate}"
387            )));
388        }
389        if self.device_type == DeviceType::TypeHxn {
390            return Ok(baud_rate);
391        }
392        if STANDARD_BAUD_RATES.contains(&baud_rate) {
393            return Ok(baud_rate);
394        }
395
396        let baseline = 12000000u64 * 32;
397        let mut mantissa = (baseline / baud_rate as u64) as u32;
398        if mantissa == 0 {
399            return Err(UsbSerialError::Unsupported("baud rate too high".into()));
400        }
401
402        let (buf, effective) = if self.device_type == DeviceType::TypeT {
403            let mut exponent = 0u32;
404            while mantissa >= 2048 {
405                if exponent < 15 {
406                    mantissa >>= 1;
407                    exponent += 1;
408                } else {
409                    return Err(UsbSerialError::Unsupported("baud rate too low".into()));
410                }
411            }
412            let buf = mantissa + ((exponent & !1) << 12) + ((exponent & 1) << 16) + (1 << 31);
413            let effective = (baseline / mantissa as u64) >> exponent;
414            (buf, effective)
415        } else {
416            let mut exponent = 0u32;
417            while mantissa >= 512 {
418                if exponent < 7 {
419                    mantissa >>= 2;
420                    exponent += 1;
421                } else {
422                    return Err(UsbSerialError::Unsupported("baud rate too low".into()));
423                }
424            }
425            let buf = mantissa + (exponent << 9) + (1 << 31);
426            let effective = (baseline / mantissa as u64) >> (exponent * 2);
427            (buf, effective)
428        };
429
430        let error = (1.0 - (effective as f64 / baud_rate as f64)).abs();
431        if error >= 0.031 {
432            return Err(UsbSerialError::Unsupported(format!(
433                "baud rate deviation {:.1}% is higher than allowed 3%",
434                error * 100.0
435            )));
436        }
437        Ok(buf)
438    }
439
440    fn line_request_data(&self, cfg: &LineConfig, baud: u32) -> Result<Vec<u8>> {
441        let stop = match cfg.stop_bits {
442            StopBits::One => 0u8,
443            StopBits::OnePointFive => 1,
444            StopBits::Two => 2,
445        };
446        let parity = match cfg.parity {
447            Parity::None => 0,
448            Parity::Odd => 1,
449            Parity::Even => 2,
450            Parity::Mark => 3,
451            Parity::Space => 4,
452        };
453        let data_bits = match cfg.data_bits {
454            DataBits::Five => 5,
455            DataBits::Six => 6,
456            DataBits::Seven => 7,
457            DataBits::Eight => 8,
458        };
459        let mut line = line_coding_bytes(cfg);
460        line[0] = (baud & 0xff) as u8;
461        line[1] = ((baud >> 8) & 0xff) as u8;
462        line[2] = ((baud >> 16) & 0xff) as u8;
463        line[3] = ((baud >> 24) & 0xff) as u8;
464        line[4] = stop;
465        line[5] = parity;
466        line[6] = data_bits;
467        Ok(line.to_vec())
468    }
469}
470
471fn decode_vendor_status(byte: u8) -> u8 {
472    let mut status = 0u8;
473    if byte & GET_CONTROL_FLAG_CTS == 0 {
474        status |= STATUS_FLAG_CTS;
475    }
476    if byte & GET_CONTROL_FLAG_DSR == 0 {
477        status |= STATUS_FLAG_DSR;
478    }
479    if byte & GET_CONTROL_FLAG_CD == 0 {
480        status |= STATUS_FLAG_CD;
481    }
482    if byte & GET_CONTROL_FLAG_RI == 0 {
483        status |= STATUS_FLAG_RI;
484    }
485    status
486}
487
488fn decode_vendor_status_hxn(byte: u8) -> u8 {
489    let mut status = 0u8;
490    if byte & GET_CONTROL_HXN_FLAG_CTS == 0 {
491        status |= STATUS_FLAG_CTS;
492    }
493    if byte & GET_CONTROL_HXN_FLAG_DSR == 0 {
494        status |= STATUS_FLAG_DSR;
495    }
496    if byte & GET_CONTROL_HXN_FLAG_CD == 0 {
497        status |= STATUS_FLAG_CD;
498    }
499    if byte & GET_CONTROL_HXN_FLAG_RI == 0 {
500        status |= STATUS_FLAG_RI;
501    }
502    status
503}
504
505fn status_flag_to_modem(status: u8) -> ModemStatus {
506    ModemStatus {
507        cts: status & STATUS_FLAG_CTS != 0,
508        dsr: status & STATUS_FLAG_DSR != 0,
509        ri: status & STATUS_FLAG_RI != 0,
510        cd: status & STATUS_FLAG_CD != 0,
511    }
512}
513
514impl Driver for ProlificDriver {
515    fn open(&mut self, transport: &SharedTransport) -> Result<()> {
516        self.transport = Some(transport.clone());
517        self.iface = 0;
518        transport.claim_interface(self.iface)?;
519        self.endpoints = Some(Self::open_endpoints(transport, self.iface)?);
520        self.detect_device_type(transport)?;
521        self.reset_device()?;
522        self.do_black_magic()?;
523        self.set_control_lines(self.control_lines)?;
524        self.set_flow_control(self.flow)?;
525        Ok(())
526    }
527
528    fn close(&mut self) -> Result<()> {
529        if let Some(mut r) = self.reader.take() {
530            r.stop();
531        }
532        self.stop_status_thread();
533        let _ = self.reset_device();
534        if let Some(t) = &self.transport {
535            let _ = t.release_interface(self.iface);
536        }
537        self.endpoints = None;
538        Ok(())
539    }
540
541    fn write(&mut self, data: &[u8]) -> Result<usize> {
542        let t = self.transport.as_ref().unwrap();
543        self.endpoints.as_mut().unwrap().data.write(t, data)
544    }
545
546    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
547        if let Some(reader) = &mut self.reader {
548            return reader.try_read(buf);
549        }
550        Ok(0)
551    }
552
553    fn set_line_config(&mut self, cfg: LineConfig) -> Result<()> {
554        let baud = self.filter_baud_rate(cfg.baud_rate)?;
555        let data_bits = match cfg.data_bits {
556            DataBits::Five => 5,
557            DataBits::Six => 6,
558            DataBits::Seven => 7,
559            DataBits::Eight => 8,
560        };
561        let stop_bits = match cfg.stop_bits {
562            StopBits::One => 1,
563            StopBits::OnePointFive => 3,
564            StopBits::Two => 2,
565        };
566        let parity = match cfg.parity {
567            Parity::None => 0,
568            Parity::Odd => 1,
569            Parity::Even => 2,
570            Parity::Mark => 3,
571            Parity::Space => 4,
572        };
573
574        if self.baud_rate == baud as i32
575            && self.data_bits == data_bits
576            && self.stop_bits == stop_bits
577            && self.parity == parity
578        {
579            return Ok(());
580        }
581
582        let line = self.line_request_data(&cfg, baud)?;
583        self.ctrl_out(SET_LINE_REQUEST, 0, 0, line)?;
584        self.reset_device()?;
585
586        self.baud_rate = baud as i32;
587        self.data_bits = data_bits;
588        self.stop_bits = stop_bits;
589        self.parity = parity;
590        Ok(())
591    }
592
593    fn set_flow_control(&mut self, flow: FlowControl) -> Result<()> {
594        match flow {
595            FlowControl::None => {
596                if self.device_type == DeviceType::TypeHxn {
597                    self.vendor_out(0x0a, 0xff, vec![])?;
598                } else {
599                    self.vendor_out(0, 0, vec![])?;
600                }
601            }
602            FlowControl::RtsCts => {
603                if self.device_type == DeviceType::TypeHxn {
604                    self.vendor_out(0x0a, 0xfa, vec![])?;
605                } else {
606                    self.vendor_out(0, 0x61, vec![])?;
607                }
608            }
609            FlowControl::XonXoffInline => {
610                if self.device_type == DeviceType::TypeHxn {
611                    self.vendor_out(0x0a, 0xee, vec![])?;
612                } else {
613                    self.vendor_out(0, 0xc1, vec![])?;
614                }
615            }
616            _ => return Err(UsbSerialError::Unsupported("flow control".into())),
617        }
618        self.flow = flow;
619        Ok(())
620    }
621
622    fn set_dtr(&mut self, value: bool) -> Result<()> {
623        let new_lines = if value {
624            self.control_lines | CONTROL_DTR
625        } else {
626            self.control_lines & !CONTROL_DTR
627        };
628        self.set_control_lines(new_lines)
629    }
630
631    fn set_rts(&mut self, value: bool) -> Result<()> {
632        let new_lines = if value {
633            self.control_lines | CONTROL_RTS
634        } else {
635            self.control_lines & !CONTROL_RTS
636        };
637        self.set_control_lines(new_lines)
638    }
639
640    fn set_break(&mut self, enabled: bool) -> Result<()> {
641        let value = if enabled { 0xffffu16 } else { 0 };
642        self.ctrl_out(SEND_BREAK_REQUEST, value, 0, vec![])
643    }
644
645    fn purge(&mut self, kind: PurgeKind) -> Result<()> {
646        match kind {
647            PurgeKind::Rx => self.purge_hw_buffers(true, false),
648            PurgeKind::Tx => self.purge_hw_buffers(false, true),
649            PurgeKind::Both => self.purge_hw_buffers(true, true),
650        }
651    }
652
653    fn modem_status(&mut self) -> Result<ModemStatus> {
654        let status = self.get_status()?;
655        Ok(status_flag_to_modem(status))
656    }
657
658    fn bulk_in_mps(&self) -> u16 {
659        self.endpoints.as_ref().map(|e| e.data.mps).unwrap_or(64)
660    }
661
662    fn take_bulk_in(&mut self) -> Option<Box<dyn BulkIn>> {
663        let transport = self.transport.as_ref()?;
664        self.endpoints.as_mut()?.data.take_in(transport)
665    }
666
667    fn rx_filters(&self) -> Vec<Box<dyn crate::rx_filter::RxFilter>> {
668        if self.flow == FlowControl::XonXoffInline {
669            vec![Box::new(XonXoffRxFilter::new(true))]
670        } else {
671            vec![]
672        }
673    }
674}
675
676#[cfg(test)]
677mod tests {
678    use super::*;
679
680    #[test]
681    fn filter_standard_baud() {
682        let mut d = ProlificDriver::new(0);
683        d.device_type = DeviceType::TypeHx;
684        assert_eq!(d.filter_baud_rate(115200).unwrap(), 115200);
685    }
686
687    #[test]
688    fn filter_custom_baud_hx() {
689        let mut d = ProlificDriver::new(0);
690        d.device_type = DeviceType::TypeHx;
691        let encoded = d.filter_baud_rate(500_000).unwrap();
692        assert_ne!(encoded, 500_000);
693        assert!(encoded & (1 << 31) != 0);
694    }
695}