1use core::marker::PhantomData;
45
46use embassy_sync::blocking_mutex::raw::{NoopRawMutex, RawMutex};
47use embassy_sync::mutex::Mutex;
48use embassy_usb_driver::host::{PipeError, SplitInfo, UsbHostAllocator, UsbPipe, pipe};
49use embassy_usb_driver::{Direction as UsbDirection, EndpointAddress, EndpointInfo, EndpointType};
50
51use crate::control::SetupPacket;
52use crate::descriptor::ConfigurationDescriptor;
53use crate::handler::EnumerationInfo;
54
55pub mod id {
57 pub const VID_SILABS: u16 = 0x10C4;
59 pub const PID_CP210X: u16 = 0xEA60;
61 pub const PID_CP210X_ALT: u16 = 0xEA70;
63}
64
65const IFC_ENABLE: u8 = 0x00;
67const SET_BAUDDIV: u8 = 0x01;
68const GET_BAUDDIV: u8 = 0x02;
69const SET_LINE_CTL: u8 = 0x03;
70const GET_LINE_CTL: u8 = 0x04;
71const SET_BREAK: u8 = 0x05;
72const SET_MHS: u8 = 0x07;
73const GET_MDMSTS: u8 = 0x08;
74const PURGE: u8 = 0x12;
75const SET_FLOW: u8 = 0x13;
76const GET_FLOW: u8 = 0x14;
77const GET_BAUDRATE: u8 = 0x1D;
78const SET_BAUDRATE: u8 = 0x1E;
79
80const VENDOR_CLASS: u8 = 0xFF;
81
82const BAUD_CLOCK: u32 = 3_686_400;
84
85#[derive(Copy, Clone, PartialEq, Eq)]
87enum BaudMode {
88 Unknown,
90 Direct,
93 Divisor,
95}
96
97struct CtrlState<P> {
99 pipe: P,
100 baud_mode: BaudMode,
101}
102
103async fn vendor_out<P>(pipe: &mut P, interface: u8, request: u8, value: u16, data: &[u8]) -> Result<(), Cp210xError>
104where
105 P: UsbPipe<pipe::Control, pipe::InOut>,
106{
107 let setup = SetupPacket::vendor_interface_out(request, value, interface as u16, data.len() as u16);
108 pipe.control_out(&setup.to_bytes(), data).await?;
109 Ok(())
110}
111
112async fn vendor_in<P>(pipe: &mut P, interface: u8, request: u8, value: u16, buf: &mut [u8]) -> Result<(), Cp210xError>
113where
114 P: UsbPipe<pipe::Control, pipe::InOut>,
115{
116 let setup = SetupPacket::vendor_interface_in(request, value, interface as u16, buf.len() as u16);
117 let n = pipe.control_in(&setup.to_bytes(), buf).await?;
118 if n != buf.len() {
119 return Err(Cp210xError::InvalidResponse);
120 }
121 Ok(())
122}
123
124async fn set_baud_rate_direct<P>(pipe: &mut P, interface: u8, baud: u32) -> Result<(), Cp210xError>
125where
126 P: UsbPipe<pipe::Control, pipe::InOut>,
127{
128 vendor_out(pipe, interface, SET_BAUDRATE, 0, &baud.to_le_bytes()).await
129}
130
131async fn set_baud_rate_divisor<P>(pipe: &mut P, interface: u8, baud: u32) -> Result<(), Cp210xError>
132where
133 P: UsbPipe<pipe::Control, pipe::InOut>,
134{
135 let div = (BAUD_CLOCK + baud / 2) / baud;
136 if div == 0 || div > u16::MAX as u32 {
137 return Err(Cp210xError::InvalidArgument);
138 }
139 vendor_out(pipe, interface, SET_BAUDDIV, div as u16, &[]).await
140}
141
142async fn get_baud_rate_direct<P>(pipe: &mut P, interface: u8) -> Result<u32, Cp210xError>
143where
144 P: UsbPipe<pipe::Control, pipe::InOut>,
145{
146 let mut buf = [0u8; 4];
147 vendor_in(pipe, interface, GET_BAUDRATE, 0, &mut buf).await?;
148 Ok(u32::from_le_bytes(buf))
149}
150
151async fn get_baud_rate_divisor<P>(pipe: &mut P, interface: u8) -> Result<u32, Cp210xError>
152where
153 P: UsbPipe<pipe::Control, pipe::InOut>,
154{
155 let mut buf = [0u8; 2];
156 vendor_in(pipe, interface, GET_BAUDDIV, 0, &mut buf).await?;
157 let div = u16::from_le_bytes(buf);
158 if div == 0 {
159 return Err(Cp210xError::InvalidResponse);
160 }
161 Ok(BAUD_CLOCK / div as u32)
162}
163
164#[derive(Copy, Clone, Debug, PartialEq, Eq)]
166#[cfg_attr(feature = "defmt", derive(defmt::Format))]
167#[repr(u8)]
168pub enum Parity {
169 None = 0,
171 Odd = 1,
173 Even = 2,
175 Mark = 3,
177 Space = 4,
179}
180
181impl Parity {
182 fn from_bits(b: u8) -> Option<Self> {
183 Some(match b {
184 0 => Self::None,
185 1 => Self::Odd,
186 2 => Self::Even,
187 3 => Self::Mark,
188 4 => Self::Space,
189 _ => return None,
190 })
191 }
192}
193
194#[derive(Copy, Clone, Debug, PartialEq, Eq)]
196#[cfg_attr(feature = "defmt", derive(defmt::Format))]
197#[repr(u8)]
198pub enum StopBits {
199 One = 0,
201 OneAndHalf = 1,
203 Two = 2,
205}
206
207impl StopBits {
208 fn from_bits(b: u8) -> Option<Self> {
209 Some(match b {
210 0 => Self::One,
211 1 => Self::OneAndHalf,
212 2 => Self::Two,
213 _ => return None,
214 })
215 }
216}
217
218#[derive(Copy, Clone, Debug, PartialEq, Eq)]
220#[cfg_attr(feature = "defmt", derive(defmt::Format))]
221pub struct LineCoding {
222 pub baud_rate: u32,
224 pub data_bits: u8,
226 pub parity: Parity,
228 pub stop_bits: StopBits,
230}
231
232impl Default for LineCoding {
233 fn default() -> Self {
234 Self {
235 baud_rate: 115200,
236 data_bits: 8,
237 parity: Parity::None,
238 stop_bits: StopBits::One,
239 }
240 }
241}
242
243macro_rules! bitflags {
244 ($($tt:tt)*) => {
245 #[cfg(feature = "defmt")]
246 defmt::bitflags! { $($tt)* }
247 #[cfg(not(feature = "defmt"))]
248 bitflags::bitflags! { #[derive(Debug, Clone, PartialEq)] $($tt)* }
249 };
250}
251
252bitflags! {
253 pub struct ModemStatus: u8 {
255 const DTR = 1 << 0;
257 const RTS = 1 << 1;
259 const CTS = 1 << 4;
261 const DSR = 1 << 5;
263 const RI = 1 << 6;
265 const DCD = 1 << 7;
267 }
268}
269
270bitflags! {
271 pub struct PurgeMask: u16 {
273 const TX = (1 << 0) | (1 << 2);
275 const RX = (1 << 1) | (1 << 3);
277 const ALL = Self::TX.bits() | Self::RX.bits();
279 }
280}
281
282#[derive(Copy, Clone, Debug, PartialEq, Eq)]
284#[cfg_attr(feature = "defmt", derive(defmt::Format))]
285#[repr(u8)]
286pub enum DtrMode {
287 Inactive = 0,
289 Active = 1,
291 FlowControl = 2,
293}
294
295#[derive(Copy, Clone, Debug, PartialEq, Eq)]
297#[cfg_attr(feature = "defmt", derive(defmt::Format))]
298#[repr(u8)]
299pub enum RtsMode {
300 Inactive = 0,
302 Active = 1,
304 FlowControl = 2,
306 TxActive = 3,
308}
309
310#[derive(Copy, Clone, Debug, PartialEq, Eq)]
317#[cfg_attr(feature = "defmt", derive(defmt::Format))]
318pub struct FlowControl {
319 pub dtr: DtrMode,
321 pub rts: RtsMode,
323 pub cts_handshake: bool,
325 pub dsr_handshake: bool,
327 pub dcd_handshake: bool,
329 pub dsr_sensitivity: bool,
331 pub auto_transmit: bool,
333 pub auto_receive: bool,
335 pub xon_limit: u32,
337 pub xoff_limit: u32,
339}
340
341impl Default for FlowControl {
342 fn default() -> Self {
343 Self {
344 dtr: DtrMode::Active,
345 rts: RtsMode::Active,
346 cts_handshake: false,
347 dsr_handshake: false,
348 dcd_handshake: false,
349 dsr_sensitivity: false,
350 auto_transmit: false,
351 auto_receive: false,
352 xon_limit: 0,
353 xoff_limit: 0,
354 }
355 }
356}
357
358impl FlowControl {
359 fn to_bytes(self) -> [u8; 16] {
360 let mut ctrl = self.dtr as u32;
361 if self.cts_handshake {
362 ctrl |= 1 << 3;
363 }
364 if self.dsr_handshake {
365 ctrl |= 1 << 4;
366 }
367 if self.dcd_handshake {
368 ctrl |= 1 << 5;
369 }
370 if self.dsr_sensitivity {
371 ctrl |= 1 << 6;
372 }
373
374 let mut repl = 0u32;
375 if self.auto_transmit {
376 repl |= 1 << 0;
377 }
378 if self.auto_receive {
379 repl |= 1 << 1;
380 }
381 repl |= (self.rts as u32) << 6;
382
383 let mut buf = [0u8; 16];
384 buf[0..4].copy_from_slice(&ctrl.to_le_bytes());
385 buf[4..8].copy_from_slice(&repl.to_le_bytes());
386 buf[8..12].copy_from_slice(&self.xon_limit.to_le_bytes());
387 buf[12..16].copy_from_slice(&self.xoff_limit.to_le_bytes());
388 buf
389 }
390
391 fn from_bytes(buf: &[u8; 16]) -> Self {
392 let ctrl = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
393 let repl = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]);
394 let xon = u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]);
395 let xoff = u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]);
396
397 let dtr = match ctrl & 0b11 {
398 0 => DtrMode::Inactive,
399 1 => DtrMode::Active,
400 _ => DtrMode::FlowControl,
401 };
402 let rts = match (repl >> 6) & 0b11 {
403 0 => RtsMode::Inactive,
404 1 => RtsMode::Active,
405 2 => RtsMode::FlowControl,
406 _ => RtsMode::TxActive,
407 };
408
409 Self {
410 dtr,
411 rts,
412 cts_handshake: ctrl & (1 << 3) != 0,
413 dsr_handshake: ctrl & (1 << 4) != 0,
414 dcd_handshake: ctrl & (1 << 5) != 0,
415 dsr_sensitivity: ctrl & (1 << 6) != 0,
416 auto_transmit: repl & (1 << 0) != 0,
417 auto_receive: repl & (1 << 1) != 0,
418 xon_limit: xon,
419 xoff_limit: xoff,
420 }
421 }
422}
423
424#[derive(Debug)]
426#[cfg_attr(feature = "defmt", derive(defmt::Format))]
427pub enum Cp210xError {
428 Transfer(PipeError),
430 NoInterface,
432 NoPipe,
434 InvalidResponse,
436 InvalidArgument,
438}
439
440impl From<PipeError> for Cp210xError {
441 fn from(e: PipeError) -> Self {
442 Self::Transfer(e)
443 }
444}
445
446impl core::fmt::Display for Cp210xError {
447 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
448 match self {
449 Self::Transfer(_) => write!(f, "Transfer error"),
450 Self::NoInterface => write!(f, "No CP210x interface found"),
451 Self::NoPipe => write!(f, "No free pipe"),
452 Self::InvalidResponse => write!(f, "Invalid response from device"),
453 Self::InvalidArgument => write!(f, "Invalid argument"),
454 }
455 }
456}
457
458impl core::error::Error for Cp210xError {}
459
460impl embedded_io_async::Error for Cp210xError {
461 fn kind(&self) -> embedded_io_async::ErrorKind {
462 match self {
463 Self::Transfer(e) => match e {
464 PipeError::Disconnected => embedded_io_async::ErrorKind::NotConnected,
465 PipeError::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory,
466 PipeError::Timeout => embedded_io_async::ErrorKind::TimedOut,
467 _ => embedded_io_async::ErrorKind::Other,
468 },
469 Self::NoInterface => embedded_io_async::ErrorKind::NotFound,
470 Self::NoPipe => embedded_io_async::ErrorKind::OutOfMemory,
471 Self::InvalidResponse => embedded_io_async::ErrorKind::InvalidData,
472 Self::InvalidArgument => embedded_io_async::ErrorKind::InvalidInput,
473 }
474 }
475}
476
477#[derive(Copy, Clone, Debug)]
479#[cfg_attr(feature = "defmt", derive(defmt::Format))]
480pub struct Cp210xInfo {
481 pub interface: u8,
483 pub bulk_in_ep: u8,
485 pub bulk_in_mps: u16,
487 pub bulk_out_ep: u8,
489 pub bulk_out_mps: u16,
491}
492
493pub fn find_cp210x(config_desc: &[u8], interface_idx: u8) -> Option<Cp210xInfo> {
499 let cfg = ConfigurationDescriptor::try_from_slice(config_desc).ok()?;
500
501 let mut seen = 0u8;
502 for iface in cfg.iter_interface() {
503 if iface.interface_class != VENDOR_CLASS || iface.alternate_setting != 0 {
504 continue;
505 }
506
507 let mut in_ep = None;
508 let mut out_ep = None;
509 for ep in iface.iter_endpoints() {
510 if ep.ep_type() != EndpointType::Bulk {
511 continue;
512 }
513 if ep.is_in() {
514 in_ep = Some((ep.endpoint_address, ep.max_packet_size));
515 } else {
516 out_ep = Some((ep.endpoint_address, ep.max_packet_size));
517 }
518 }
519
520 if let (Some((in_a, in_m)), Some((out_a, out_m))) = (in_ep, out_ep) {
521 if seen == interface_idx {
522 return Some(Cp210xInfo {
523 interface: iface.interface_number,
524 bulk_in_ep: in_a,
525 bulk_in_mps: in_m,
526 bulk_out_ep: out_a,
527 bulk_out_mps: out_m,
528 });
529 }
530 seen += 1;
531 }
532 }
533
534 None
535}
536
537pub struct Cp210xDevice<'d, A, M = NoopRawMutex>
556where
557 A: UsbHostAllocator<'d>,
558 M: RawMutex,
559{
560 alloc: A,
561 ctrl: Mutex<M, CtrlState<A::Pipe<pipe::Control, pipe::InOut>>>,
565 device_address: u8,
566 split: Option<SplitInfo>,
567 _phantom: PhantomData<&'d ()>,
568}
569
570impl<'d, A> Cp210xDevice<'d, A, NoopRawMutex>
571where
572 A: UsbHostAllocator<'d>,
573{
574 pub fn new(alloc: &A, enum_info: &EnumerationInfo) -> Result<Self, Cp210xError> {
584 Self::new_with_raw_mutex(alloc, enum_info)
585 }
586}
587
588impl<'d, A, M> Cp210xDevice<'d, A, M>
589where
590 A: UsbHostAllocator<'d>,
591 M: RawMutex,
592{
593 pub fn new_with_raw_mutex(alloc: &A, enum_info: &EnumerationInfo) -> Result<Self, Cp210xError> {
602 let ctrl_ep_info = EndpointInfo {
603 addr: EndpointAddress::from_parts(0, UsbDirection::In),
604 ep_type: EndpointType::Control,
605 max_packet_size: enum_info.device_desc.max_packet_size0 as u16,
606 interval_ms: 0,
607 };
608
609 let device_address = enum_info.device_address;
610 let split = enum_info.split();
611
612 let ctrl = alloc
613 .alloc_pipe::<pipe::Control, pipe::InOut>(device_address, &ctrl_ep_info, split)
614 .map_err(|_| Cp210xError::NoPipe)?;
615
616 Ok(Self {
617 alloc: alloc.clone(),
618 ctrl: Mutex::new(CtrlState {
619 pipe: ctrl,
620 baud_mode: BaudMode::Unknown,
621 }),
622 device_address,
623 split,
624 _phantom: PhantomData,
625 })
626 }
627
628 pub fn port<'dev>(
642 &'dev self,
643 config_desc: &[u8],
644 interface_idx: u8,
645 ) -> Result<Cp210xPort<'dev, 'd, A, M>, Cp210xError> {
646 let info = find_cp210x(config_desc, interface_idx).ok_or(Cp210xError::NoInterface)?;
647
648 let in_ep_info = EndpointInfo {
649 addr: EndpointAddress::from_parts((info.bulk_in_ep & 0x0F) as usize, UsbDirection::In),
650 ep_type: EndpointType::Bulk,
651 max_packet_size: info.bulk_in_mps,
652 interval_ms: 0,
653 };
654
655 let out_ep_info = EndpointInfo {
656 addr: EndpointAddress::from_parts((info.bulk_out_ep & 0x0F) as usize, UsbDirection::Out),
657 ep_type: EndpointType::Bulk,
658 max_packet_size: info.bulk_out_mps,
659 interval_ms: 0,
660 };
661
662 let in_ch = self
663 .alloc
664 .alloc_pipe::<pipe::Bulk, pipe::In>(self.device_address, &in_ep_info, self.split)
665 .map_err(|_| Cp210xError::NoPipe)?;
666 let out_ch = self
667 .alloc
668 .alloc_pipe::<pipe::Bulk, pipe::Out>(self.device_address, &out_ep_info, self.split)
669 .map_err(|_| Cp210xError::NoPipe)?;
670
671 Ok(Cp210xPort {
672 device: self,
673 in_ch,
674 out_ch,
675 interface: info.interface,
676 })
677 }
678}
679
680pub struct Cp210xPort<'dev, 'd, A, M = NoopRawMutex>
685where
686 A: UsbHostAllocator<'d>,
687 M: RawMutex,
688{
689 device: &'dev Cp210xDevice<'d, A, M>,
690 in_ch: A::Pipe<pipe::Bulk, pipe::In>,
691 out_ch: A::Pipe<pipe::Bulk, pipe::Out>,
692 interface: u8,
693}
694
695impl<'dev, 'd, A, M> Cp210xPort<'dev, 'd, A, M>
696where
697 A: UsbHostAllocator<'d>,
698 M: RawMutex,
699{
700 pub fn interface(&self) -> u8 {
702 self.interface
703 }
704
705 async fn vendor_out(&mut self, request: u8, value: u16, data: &[u8]) -> Result<(), Cp210xError> {
706 let mut ctrl = self.device.ctrl.lock().await;
707 vendor_out(&mut ctrl.pipe, self.interface, request, value, data).await
708 }
709
710 async fn vendor_in(&mut self, request: u8, value: u16, buf: &mut [u8]) -> Result<(), Cp210xError> {
711 let mut ctrl = self.device.ctrl.lock().await;
712 vendor_in(&mut ctrl.pipe, self.interface, request, value, buf).await
713 }
714
715 pub async fn enable(&mut self) -> Result<(), Cp210xError> {
719 self.vendor_out(IFC_ENABLE, 1, &[]).await
720 }
721
722 pub async fn disable(&mut self) -> Result<(), Cp210xError> {
726 self.vendor_out(IFC_ENABLE, 0, &[]).await
727 }
728
729 pub async fn set_baud_rate(&mut self, baud: u32) -> Result<(), Cp210xError> {
737 if baud == 0 {
738 return Err(Cp210xError::InvalidArgument);
739 }
740 let iface = self.interface;
741 let mut ctrl = self.device.ctrl.lock().await;
742 let CtrlState { pipe, baud_mode } = &mut *ctrl;
743 match *baud_mode {
744 BaudMode::Direct => set_baud_rate_direct(pipe, iface, baud).await,
745 BaudMode::Divisor => set_baud_rate_divisor(pipe, iface, baud).await,
746 BaudMode::Unknown => match set_baud_rate_direct(pipe, iface, baud).await {
747 Ok(()) => {
748 *baud_mode = BaudMode::Direct;
749 Ok(())
750 }
751 Err(Cp210xError::Transfer(PipeError::Stall)) => {
752 *baud_mode = BaudMode::Divisor;
753 set_baud_rate_divisor(pipe, iface, baud).await
754 }
755 Err(e) => Err(e),
756 },
757 }
758 }
759
760 pub async fn baud_rate(&mut self) -> Result<u32, Cp210xError> {
766 let iface = self.interface;
767 let mut ctrl = self.device.ctrl.lock().await;
768 let CtrlState { pipe, baud_mode } = &mut *ctrl;
769 match *baud_mode {
770 BaudMode::Direct => get_baud_rate_direct(pipe, iface).await,
771 BaudMode::Divisor => get_baud_rate_divisor(pipe, iface).await,
772 BaudMode::Unknown => match get_baud_rate_direct(pipe, iface).await {
773 Ok(b) => {
774 *baud_mode = BaudMode::Direct;
775 Ok(b)
776 }
777 Err(Cp210xError::Transfer(PipeError::Stall)) => {
778 *baud_mode = BaudMode::Divisor;
779 get_baud_rate_divisor(pipe, iface).await
780 }
781 Err(e) => Err(e),
782 },
783 }
784 }
785
786 pub async fn set_line_coding(&mut self, coding: &LineCoding) -> Result<(), Cp210xError> {
797 if !matches!(coding.data_bits, 5..=8) {
798 return Err(Cp210xError::InvalidArgument);
799 }
800 let line_ctl = (coding.stop_bits as u16) | ((coding.parity as u16) << 4) | ((coding.data_bits as u16) << 8);
801 self.vendor_out(SET_LINE_CTL, line_ctl, &[]).await?;
802 self.set_baud_rate(coding.baud_rate).await
803 }
804
805 pub async fn line_coding(&mut self) -> Result<LineCoding, Cp210xError> {
809 let mut buf = [0u8; 2];
810 self.vendor_in(GET_LINE_CTL, 0, &mut buf).await?;
811 let ctl = u16::from_le_bytes(buf);
812 let stop_bits = StopBits::from_bits((ctl & 0xF) as u8).ok_or(Cp210xError::InvalidResponse)?;
813 let parity = Parity::from_bits(((ctl >> 4) & 0xF) as u8).ok_or(Cp210xError::InvalidResponse)?;
814 let data_bits = (ctl >> 8) as u8;
815 if !matches!(data_bits, 5..=8) {
816 return Err(Cp210xError::InvalidResponse);
817 }
818 let baud_rate = self.baud_rate().await?;
819 Ok(LineCoding {
820 baud_rate,
821 data_bits,
822 parity,
823 stop_bits,
824 })
825 }
826
827 pub async fn set_control_line_state(&mut self, dtr: bool, rts: bool) -> Result<(), Cp210xError> {
833 let value = (dtr as u16) | ((rts as u16) << 1) | (1 << 8) | (1 << 9);
834 self.vendor_out(SET_MHS, value, &[]).await
835 }
836
837 pub async fn modem_status(&mut self) -> Result<ModemStatus, Cp210xError> {
842 let mut buf = [0u8; 1];
843 self.vendor_in(GET_MDMSTS, 0, &mut buf).await?;
844 Ok(ModemStatus::from_bits_truncate(buf[0]))
845 }
846
847 pub async fn set_break(&mut self, asserted: bool) -> Result<(), Cp210xError> {
851 self.vendor_out(SET_BREAK, asserted as u16, &[]).await
852 }
853
854 pub async fn purge(&mut self, mask: PurgeMask) -> Result<(), Cp210xError> {
860 self.vendor_out(PURGE, mask.bits(), &[]).await
861 }
862
863 pub async fn set_flow_control(&mut self, fc: &FlowControl) -> Result<(), Cp210xError> {
868 let bytes = fc.to_bytes();
869 self.set_flow_control_raw(&bytes).await
870 }
871
872 pub async fn set_flow_control_raw(&mut self, raw: &[u8; 16]) -> Result<(), Cp210xError> {
878 self.vendor_out(SET_FLOW, 0, raw).await
879 }
880
881 pub async fn flow_control(&mut self) -> Result<FlowControl, Cp210xError> {
885 let mut buf = [0u8; 16];
886 self.vendor_in(GET_FLOW, 0, &mut buf).await?;
887 Ok(FlowControl::from_bytes(&buf))
888 }
889
890 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Cp210xError> {
897 Ok(self.in_ch.request_in(buf).await?)
898 }
899
900 pub async fn write(&mut self, data: &[u8]) -> Result<usize, Cp210xError> {
907 self.out_ch.request_out(data, false).await?;
908 Ok(data.len())
909 }
910}
911
912impl<'dev, 'd, A, M> embedded_io_async::ErrorType for Cp210xPort<'dev, 'd, A, M>
913where
914 A: UsbHostAllocator<'d>,
915 M: RawMutex,
916{
917 type Error = Cp210xError;
918}
919
920impl<'dev, 'd, A, M> embedded_io_async::Read for Cp210xPort<'dev, 'd, A, M>
921where
922 A: UsbHostAllocator<'d>,
923 M: RawMutex,
924{
925 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
926 Cp210xPort::read(self, buf).await
927 }
928}
929
930impl<'dev, 'd, A, M> embedded_io_async::Write for Cp210xPort<'dev, 'd, A, M>
931where
932 A: UsbHostAllocator<'d>,
933 M: RawMutex,
934{
935 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
936 Cp210xPort::write(self, buf).await
937 }
938
939 async fn flush(&mut self) -> Result<(), Self::Error> {
940 Ok(())
941 }
942}