aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src
diff options
context:
space:
mode:
authorMatt Spencer <[email protected]>2023-09-19 15:42:26 +0100
committerMatt Spencer <[email protected]>2023-09-19 15:42:26 +0100
commita402aed3d1738a2afee4b78d01344cba636f6a1d (patch)
treee9e99525b1055169d244ddf78eca7f9c50ec832d /embassy-usb/src
parent183824fbddb2a05aed4ed854f6eb08fe4ba7e7c1 (diff)
Add async interface for CDC control changes
Signed-off-by: Matt Spencer <[email protected]>
Diffstat (limited to 'embassy-usb/src')
-rw-r--r--embassy-usb/src/class/cdc_acm.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index a341e10da..0c708464d 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -1,10 +1,13 @@
1//! CDC-ACM class implementation, aka Serial over USB. 1//! CDC-ACM class implementation, aka Serial over USB.
2 2
3use core::cell::Cell; 3use core::cell::{Cell, RefCell};
4use core::future::poll_fn;
4use core::mem::{self, MaybeUninit}; 5use core::mem::{self, MaybeUninit};
5use core::sync::atomic::{AtomicBool, Ordering}; 6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::Poll;
6 8
7use embassy_sync::blocking_mutex::CriticalSectionMutex; 9use embassy_sync::blocking_mutex::CriticalSectionMutex;
10use embassy_sync::waitqueue::WakerRegistration;
8 11
9use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; 12use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
10use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 13use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
@@ -76,6 +79,9 @@ struct ControlShared {
76 line_coding: CriticalSectionMutex<Cell<LineCoding>>, 79 line_coding: CriticalSectionMutex<Cell<LineCoding>>,
77 dtr: AtomicBool, 80 dtr: AtomicBool,
78 rts: AtomicBool, 81 rts: AtomicBool,
82
83 waker: RefCell<WakerRegistration>,
84 changed: AtomicBool,
79} 85}
80 86
81impl Default for ControlShared { 87impl Default for ControlShared {
@@ -89,10 +95,28 @@ impl Default for ControlShared {
89 parity_type: ParityType::None, 95 parity_type: ParityType::None,
90 data_rate: 8_000, 96 data_rate: 8_000,
91 })), 97 })),
98 waker: RefCell::new(WakerRegistration::new()),
99 changed: AtomicBool::new(false),
92 } 100 }
93 } 101 }
94} 102}
95 103
104impl ControlShared {
105 async fn changed(&self) {
106 poll_fn(|cx| match self.changed.load(Ordering::Relaxed) {
107 true => {
108 self.changed.store(false, Ordering::Relaxed);
109 Poll::Ready(())
110 }
111 false => {
112 self.waker.borrow_mut().register(cx.waker());
113 Poll::Pending
114 }
115 })
116 .await
117 }
118}
119
96impl<'a> Control<'a> { 120impl<'a> Control<'a> {
97 fn shared(&mut self) -> &'a ControlShared { 121 fn shared(&mut self) -> &'a ControlShared {
98 self.shared 122 self.shared
@@ -105,6 +129,9 @@ impl<'d> Handler for Control<'d> {
105 shared.line_coding.lock(|x| x.set(LineCoding::default())); 129 shared.line_coding.lock(|x| x.set(LineCoding::default()));
106 shared.dtr.store(false, Ordering::Relaxed); 130 shared.dtr.store(false, Ordering::Relaxed);
107 shared.rts.store(false, Ordering::Relaxed); 131 shared.rts.store(false, Ordering::Relaxed);
132
133 shared.changed.store(true, Ordering::Relaxed);
134 shared.waker.borrow_mut().wake();
108 } 135 }
109 136
110 fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> { 137 fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
@@ -127,9 +154,13 @@ impl<'d> Handler for Control<'d> {
127 parity_type: data[5].into(), 154 parity_type: data[5].into(),
128 data_bits: data[6], 155 data_bits: data[6],
129 }; 156 };
130 self.shared().line_coding.lock(|x| x.set(coding)); 157 let shared = self.shared();
158 shared.line_coding.lock(|x| x.set(coding));
131 debug!("Set line coding to: {:?}", coding); 159 debug!("Set line coding to: {:?}", coding);
132 160
161 shared.changed.store(true, Ordering::Relaxed);
162 shared.waker.borrow_mut().wake();
163
133 Some(OutResponse::Accepted) 164 Some(OutResponse::Accepted)
134 } 165 }
135 REQ_SET_CONTROL_LINE_STATE => { 166 REQ_SET_CONTROL_LINE_STATE => {
@@ -141,6 +172,9 @@ impl<'d> Handler for Control<'d> {
141 shared.rts.store(rts, Ordering::Relaxed); 172 shared.rts.store(rts, Ordering::Relaxed);
142 debug!("Set dtr {}, rts {}", dtr, rts); 173 debug!("Set dtr {}, rts {}", dtr, rts);
143 174
175 shared.changed.store(true, Ordering::Relaxed);
176 shared.waker.borrow_mut().wake();
177
144 Some(OutResponse::Accepted) 178 Some(OutResponse::Accepted)
145 } 179 }
146 _ => Some(OutResponse::Rejected), 180 _ => Some(OutResponse::Rejected),
@@ -292,6 +326,38 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
292 }, 326 },
293 ) 327 )
294 } 328 }
329
330 /// Split the class into sender, receiver and control
331 ///
332 /// Allows concurrently sending and receiving packets whilst monitoring for
333 /// control changes (dtr, rts)
334 pub fn split_with_control(self) -> (Sender<'d, D>, Receiver<'d, D>, ControlChanged<'d>) {
335 (
336 Sender {
337 write_ep: self.write_ep,
338 control: self.control,
339 },
340 Receiver {
341 read_ep: self.read_ep,
342 control: self.control,
343 },
344 ControlChanged { control: self.control },
345 )
346 }
347}
348
349/// CDC ACM Control status change monitor
350///
351/// You can obtain a `ControlChanged` with [`CdcAcmClass::split_with_control`]
352pub struct ControlChanged<'d> {
353 control: &'d ControlShared,
354}
355
356impl<'d> ControlChanged<'d> {
357 /// Return a future for when the control settings change
358 pub async fn control_changed(&self) {
359 self.control.changed().await
360 }
295} 361}
296 362
297/// CDC ACM class packet sender. 363/// CDC ACM class packet sender.