Remove the feature report reader

This commit is contained in:
alexmoon 2022-03-31 11:25:01 -04:00 committed by Dario Nieuwenhuis
parent cf89c85569
commit a51de5a39a
2 changed files with 43 additions and 66 deletions

View File

@ -60,39 +60,26 @@ impl ReportId {
} }
} }
pub struct State<'a, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> { pub struct State<'a, const IN_N: usize, const OUT_N: usize> {
control: MaybeUninit<Control<'a, OUT_N, FEATURE_N>>, control: MaybeUninit<Control<'a, OUT_N>>,
out_signal: Signal<(usize, [u8; OUT_N])>, out_signal: Signal<(usize, [u8; OUT_N])>,
feature_signal: Signal<(usize, [u8; FEATURE_N])>,
} }
impl<'a, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> {
State<'a, IN_N, OUT_N, FEATURE_N>
{
pub fn new() -> Self { pub fn new() -> Self {
State { State {
control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
out_signal: Signal::new(), out_signal: Signal::new(),
feature_signal: Signal::new(),
} }
} }
} }
pub struct HidClass< pub struct HidClass<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> {
'd,
D: Driver<'d>,
const IN_N: usize,
const OUT_N: usize,
const FEATURE_N: usize,
> {
input: ReportWriter<'d, D, IN_N>, input: ReportWriter<'d, D, IN_N>,
output: ReportReader<'d, D, OUT_N>, output: ReportReader<'d, D, OUT_N>,
feature: ReportReader<'d, D, FEATURE_N>,
} }
impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> HidClass<'d, D, IN_N, OUT_N> {
HidClass<'d, D, IN_N, OUT_N, FEATURE_N>
{
/// Creates a new HidClass. /// Creates a new HidClass.
/// ///
/// poll_ms configures how frequently the host should poll for reading/writing /// poll_ms configures how frequently the host should poll for reading/writing
@ -105,7 +92,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
/// endpoint. /// endpoint.
pub fn new( pub fn new(
builder: &mut UsbDeviceBuilder<'d, D>, builder: &mut UsbDeviceBuilder<'d, D>,
state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, state: &'d mut State<'d, IN_N, OUT_N>,
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
poll_ms: u8, poll_ms: u8,
@ -126,7 +113,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
/// See new() for more details. /// See new() for more details.
pub fn new_ep_in( pub fn new_ep_in(
builder: &mut UsbDeviceBuilder<'d, D>, builder: &mut UsbDeviceBuilder<'d, D>,
state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, state: &'d mut State<'d, IN_N, OUT_N>,
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
poll_ms: u8, poll_ms: u8,
@ -147,7 +134,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
/// See new() for more details. /// See new() for more details.
pub fn new_ep_out( pub fn new_ep_out(
builder: &mut UsbDeviceBuilder<'d, D>, builder: &mut UsbDeviceBuilder<'d, D>,
state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, state: &'d mut State<'d, IN_N, OUT_N>,
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
poll_ms: u8, poll_ms: u8,
@ -166,7 +153,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
fn new_inner( fn new_inner(
builder: &mut UsbDeviceBuilder<'d, D>, builder: &mut UsbDeviceBuilder<'d, D>,
state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, state: &'d mut State<'d, IN_N, OUT_N>,
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
ep_out: Option<D::EndpointOut>, ep_out: Option<D::EndpointOut>,
@ -175,7 +162,6 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
let control = state.control.write(Control::new( let control = state.control.write(Control::new(
report_descriptor, report_descriptor,
&state.out_signal, &state.out_signal,
&state.feature_signal,
request_handler, request_handler,
)); ));
@ -187,10 +173,6 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
ep_out, ep_out,
receiver: &state.out_signal, receiver: &state.out_signal,
}, },
feature: ReportReader {
ep_out: None,
receiver: &state.feature_signal,
},
} }
} }
@ -207,20 +189,9 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
&mut self.output &mut self.output
} }
/// Gets the [`ReportReader`] for feature reports. /// Splits this `HidClass` into seperate readers/writers for input and output reports.
pub fn feature(&mut self) -> &mut ReportReader<'d, D, FEATURE_N> { pub fn split(self) -> (ReportWriter<'d, D, IN_N>, ReportReader<'d, D, OUT_N>) {
&mut self.feature (self.input, self.output)
}
/// Splits this `HidClass` into seperate readers/writers for each report type.
pub fn split(
self,
) -> (
ReportWriter<'d, D, IN_N>,
ReportReader<'d, D, OUT_N>,
ReportReader<'d, D, FEATURE_N>,
) {
(self.input, self.output, self.feature)
} }
} }
@ -314,7 +285,7 @@ impl<'d, D: Driver<'d>, const N: usize> ReportReader<'d, D, N> {
} }
pub trait RequestHandler { pub trait RequestHandler {
/// Read the value of report `id` into `buf` returning the size. /// Reads the value of report `id` into `buf` returning the size.
/// ///
/// Returns `None` if `id` is invalid or no data is available. /// Returns `None` if `id` is invalid or no data is available.
fn get_report(&self, id: ReportId, buf: &mut [u8]) -> Option<usize> { fn get_report(&self, id: ReportId, buf: &mut [u8]) -> Option<usize> {
@ -322,12 +293,13 @@ pub trait RequestHandler {
None None
} }
/// Set the idle rate for `id` to `dur`. /// Sets the value of report `id` to `data`.
/// ///
/// If `id` is `None`, set the idle rate of all input reports to `dur`. If /// This is only called for feature or input reports. Output reports
/// an indefinite duration is requested, `dur` will be set to `Duration::MAX`. /// are routed through [`HidClass::output()`].
fn set_idle(&self, id: Option<ReportId>, dur: Duration) { fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
let _ = (id, dur); let _ = (id, data);
OutResponse::Rejected
} }
/// Get the idle rate for `id`. /// Get the idle rate for `id`.
@ -339,27 +311,32 @@ pub trait RequestHandler {
let _ = id; let _ = id;
None None
} }
/// Set the idle rate for `id` to `dur`.
///
/// If `id` is `None`, set the idle rate of all input reports to `dur`. If
/// an indefinite duration is requested, `dur` will be set to `Duration::MAX`.
fn set_idle(&self, id: Option<ReportId>, dur: Duration) {
let _ = (id, dur);
}
} }
pub struct Control<'d, const OUT_N: usize, const FEATURE_N: usize> { pub struct Control<'d, const OUT_N: usize> {
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
out_signal: &'d Signal<(usize, [u8; OUT_N])>, out_signal: &'d Signal<(usize, [u8; OUT_N])>,
feature_signal: &'d Signal<(usize, [u8; FEATURE_N])>,
request_handler: Option<&'d dyn RequestHandler>, request_handler: Option<&'d dyn RequestHandler>,
hid_descriptor: [u8; 9], hid_descriptor: [u8; 9],
} }
impl<'a, const OUT_N: usize, const FEATURE_N: usize> Control<'a, OUT_N, FEATURE_N> { impl<'a, const OUT_N: usize> Control<'a, OUT_N> {
fn new( fn new(
report_descriptor: &'static [u8], report_descriptor: &'static [u8],
out_signal: &'a Signal<(usize, [u8; OUT_N])>, out_signal: &'a Signal<(usize, [u8; OUT_N])>,
feature_signal: &'a Signal<(usize, [u8; FEATURE_N])>,
request_handler: Option<&'a dyn RequestHandler>, request_handler: Option<&'a dyn RequestHandler>,
) -> Self { ) -> Self {
Control { Control {
report_descriptor, report_descriptor,
out_signal, out_signal,
feature_signal,
request_handler, request_handler,
hid_descriptor: [ hid_descriptor: [
// Length of buf inclusive of size prefix // Length of buf inclusive of size prefix
@ -426,9 +403,7 @@ impl<'a, const OUT_N: usize, const FEATURE_N: usize> Control<'a, OUT_N, FEATURE_
} }
} }
impl<'d, const OUT_N: usize, const FEATURE_N: usize> ControlHandler impl<'d, const OUT_N: usize> ControlHandler for Control<'d, OUT_N> {
for Control<'d, OUT_N, FEATURE_N>
{
fn reset(&mut self) {} fn reset(&mut self) {}
fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse { fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse {
@ -450,7 +425,6 @@ impl<'d, const OUT_N: usize, const FEATURE_N: usize> ControlHandler
OutResponse::Accepted OutResponse::Accepted
} }
HID_REQ_SET_REPORT => match ReportId::try_from(req.value) { HID_REQ_SET_REPORT => match ReportId::try_from(req.value) {
Ok(ReportId::In(_)) => OutResponse::Rejected,
Ok(ReportId::Out(_id)) => { Ok(ReportId::Out(_id)) => {
let mut buf = [0; OUT_N]; let mut buf = [0; OUT_N];
buf[0..data.len()].copy_from_slice(data); buf[0..data.len()].copy_from_slice(data);
@ -460,14 +434,12 @@ impl<'d, const OUT_N: usize, const FEATURE_N: usize> ControlHandler
self.out_signal.signal((data.len(), buf)); self.out_signal.signal((data.len(), buf));
OutResponse::Accepted OutResponse::Accepted
} }
Ok(ReportId::Feature(_id)) => { Ok(id @ ReportId::Feature(_)) | Ok(id @ ReportId::In(_)) => {
let mut buf = [0; FEATURE_N]; if let Some(handler) = self.request_handler.as_ref() {
buf[0..data.len()].copy_from_slice(data); handler.set_report(id, data)
if self.feature_signal.signaled() { } else {
warn!("Feature report dropped before being read!"); OutResponse::Rejected
} }
self.feature_signal.signal((data.len(), buf));
OutResponse::Accepted
} }
Err(_) => OutResponse::Rejected, Err(_) => OutResponse::Rejected,
}, },

View File

@ -14,6 +14,7 @@ use embassy_nrf::interrupt;
use embassy_nrf::pac; use embassy_nrf::pac;
use embassy_nrf::usb::Driver; use embassy_nrf::usb::Driver;
use embassy_nrf::Peripherals; use embassy_nrf::Peripherals;
use embassy_usb::control::OutResponse;
use embassy_usb::{Config, UsbDeviceBuilder}; use embassy_usb::{Config, UsbDeviceBuilder};
use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State};
use futures::future::join; use futures::future::join;
@ -51,7 +52,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
let mut control_buf = [0; 16]; let mut control_buf = [0; 16];
let request_handler = MyRequestHandler {}; let request_handler = MyRequestHandler {};
let mut state = State::<5, 0, 0>::new(); let mut state = State::<5, 0>::new();
let mut builder = UsbDeviceBuilder::new( let mut builder = UsbDeviceBuilder::new(
driver, driver,
@ -63,8 +64,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
); );
// Create classes on the builder. // Create classes on the builder.
// let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); let mut hid = HidClass::new_ep_in(
let mut hid = HidClass::new(
&mut builder, &mut builder,
&mut state, &mut state,
MouseReport::desc(), MouseReport::desc(),
@ -120,6 +120,11 @@ impl RequestHandler for MyRequestHandler {
None None
} }
fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
info!("Set report for {:?}: {=[u8]}", id, data);
OutResponse::Accepted
}
fn set_idle(&self, id: Option<ReportId>, dur: Duration) { fn set_idle(&self, id: Option<ReportId>, dur: Duration) {
info!("Set idle rate for {:?} to {:?}", id, dur); info!("Set idle rate for {:?} to {:?}", id, dur);
} }