Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a signal for when the CDC control state changes #1926

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions embassy-usb/src/class/cdc_acm.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! CDC-ACM class implementation, aka Serial over USB.
use core::cell::Cell;
use core::cell::{Cell, RefCell};
use core::future::poll_fn;
use core::mem::{self, MaybeUninit};
use core::sync::atomic::{AtomicBool, Ordering};
use core::task::Poll;

use embassy_sync::blocking_mutex::CriticalSectionMutex;
use embassy_sync::waitqueue::WakerRegistration;

use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
Expand Down Expand Up @@ -76,6 +79,9 @@ struct ControlShared {
line_coding: CriticalSectionMutex<Cell<LineCoding>>,
dtr: AtomicBool,
rts: AtomicBool,

waker: RefCell<WakerRegistration>,
changed: AtomicBool,
}

impl Default for ControlShared {
Expand All @@ -89,10 +95,28 @@ impl Default for ControlShared {
parity_type: ParityType::None,
data_rate: 8_000,
})),
waker: RefCell::new(WakerRegistration::new()),
changed: AtomicBool::new(false),
}
}
}

impl ControlShared {
async fn changed(&self) {
poll_fn(|cx| match self.changed.load(Ordering::Relaxed) {
true => {
self.changed.store(false, Ordering::Relaxed);
Poll::Ready(())
}
false => {
self.waker.borrow_mut().register(cx.waker());
Poll::Pending
}
})
.await
}
}

impl<'a> Control<'a> {
fn shared(&mut self) -> &'a ControlShared {
self.shared
Expand All @@ -105,6 +129,9 @@ impl<'d> Handler for Control<'d> {
shared.line_coding.lock(|x| x.set(LineCoding::default()));
shared.dtr.store(false, Ordering::Relaxed);
shared.rts.store(false, Ordering::Relaxed);

shared.changed.store(true, Ordering::Relaxed);
shared.waker.borrow_mut().wake();
}

fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option<OutResponse> {
Expand All @@ -127,9 +154,13 @@ impl<'d> Handler for Control<'d> {
parity_type: data[5].into(),
data_bits: data[6],
};
self.shared().line_coding.lock(|x| x.set(coding));
let shared = self.shared();
shared.line_coding.lock(|x| x.set(coding));
debug!("Set line coding to: {:?}", coding);

shared.changed.store(true, Ordering::Relaxed);
shared.waker.borrow_mut().wake();

Some(OutResponse::Accepted)
}
REQ_SET_CONTROL_LINE_STATE => {
Expand All @@ -141,6 +172,9 @@ impl<'d> Handler for Control<'d> {
shared.rts.store(rts, Ordering::Relaxed);
debug!("Set dtr {}, rts {}", dtr, rts);

shared.changed.store(true, Ordering::Relaxed);
shared.waker.borrow_mut().wake();

Some(OutResponse::Accepted)
}
_ => Some(OutResponse::Rejected),
Expand Down Expand Up @@ -292,6 +326,38 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
},
)
}

/// Split the class into sender, receiver and control
///
/// Allows concurrently sending and receiving packets whilst monitoring for
/// control changes (dtr, rts)
pub fn split_with_control(self) -> (Sender<'d, D>, Receiver<'d, D>, ControlChanged<'d>) {
(
Sender {
write_ep: self.write_ep,
control: self.control,
},
Receiver {
read_ep: self.read_ep,
control: self.control,
},
ControlChanged { control: self.control },
)
}
}

/// CDC ACM Control status change monitor
///
/// You can obtain a `ControlChanged` with [`CdcAcmClass::split_with_control`]
pub struct ControlChanged<'d> {
control: &'d ControlShared,
}

impl<'d> ControlChanged<'d> {
/// Return a future for when the control settings change
pub async fn control_changed(&self) {
self.control.changed().await
}
}

/// CDC ACM class packet sender.
Expand Down