From 7b9075130e72e0f6fab6b07c0171e42e1b9802a1 Mon Sep 17 00:00:00 2001 From: Lasse Dalegaard Date: Sat, 4 Mar 2023 10:36:10 +0100 Subject: [PATCH] embassy_usb: Add split() for cdc_acm --- embassy-usb/src/class/cdc_acm.rs | 100 +++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index ff82ad40d..a341e10da 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -276,6 +276,106 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { pub async fn wait_connection(&mut self) { self.read_ep.wait_enabled().await } + + /// Split the class into a sender and receiver. + /// + /// This allows concurrently sending and receiving packets from separate tasks. + pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) { + ( + Sender { + write_ep: self.write_ep, + control: self.control, + }, + Receiver { + read_ep: self.read_ep, + control: self.control, + }, + ) + } +} + +/// CDC ACM class packet sender. +/// +/// You can obtain a `Sender` with [`CdcAcmClass::split`] +pub struct Sender<'d, D: Driver<'d>> { + write_ep: D::EndpointIn, + control: &'d ControlShared, +} + +impl<'d, D: Driver<'d>> Sender<'d, D> { + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.write_ep.info().max_packet_size + } + + /// Gets the current line coding. The line coding contains information that's mainly relevant + /// for USB to UART serial port emulators, and can be ignored if not relevant. + pub fn line_coding(&self) -> LineCoding { + self.control.line_coding.lock(|x| x.get()) + } + + /// Gets the DTR (data terminal ready) state + pub fn dtr(&self) -> bool { + self.control.dtr.load(Ordering::Relaxed) + } + + /// Gets the RTS (request to send) state + pub fn rts(&self) -> bool { + self.control.rts.load(Ordering::Relaxed) + } + + /// Writes a single packet into the IN endpoint. + pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { + self.write_ep.write(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.write_ep.wait_enabled().await + } +} + +/// CDC ACM class packet receiver. +/// +/// You can obtain a `Receiver` with [`CdcAcmClass::split`] +pub struct Receiver<'d, D: Driver<'d>> { + read_ep: D::EndpointOut, + control: &'d ControlShared, +} + +impl<'d, D: Driver<'d>> Receiver<'d, D> { + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.read_ep.info().max_packet_size + } + + /// Gets the current line coding. The line coding contains information that's mainly relevant + /// for USB to UART serial port emulators, and can be ignored if not relevant. + pub fn line_coding(&self) -> LineCoding { + self.control.line_coding.lock(|x| x.get()) + } + + /// Gets the DTR (data terminal ready) state + pub fn dtr(&self) -> bool { + self.control.dtr.load(Ordering::Relaxed) + } + + /// Gets the RTS (request to send) state + pub fn rts(&self) -> bool { + self.control.rts.load(Ordering::Relaxed) + } + + /// Reads a single packet from the OUT endpoint. + pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { + self.read_ep.read(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.read_ep.wait_enabled().await + } } /// Number of stop bits for LineCoding