aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-usb-hid/src/lib.rs98
-rw-r--r--examples/nrf/src/bin/usb_hid.rs11
2 files changed, 43 insertions, 66 deletions
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs
index 14aadbc8c..0c449fa26 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb-hid/src/lib.rs
@@ -60,39 +60,26 @@ impl ReportId {
60 } 60 }
61} 61}
62 62
63pub struct State<'a, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> { 63pub struct State<'a, const IN_N: usize, const OUT_N: usize> {
64 control: MaybeUninit<Control<'a, OUT_N, FEATURE_N>>, 64 control: MaybeUninit<Control<'a, OUT_N>>,
65 out_signal: Signal<(usize, [u8; OUT_N])>, 65 out_signal: Signal<(usize, [u8; OUT_N])>,
66 feature_signal: Signal<(usize, [u8; FEATURE_N])>,
67} 66}
68 67
69impl<'a, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> 68impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> {
70 State<'a, IN_N, OUT_N, FEATURE_N>
71{
72 pub fn new() -> Self { 69 pub fn new() -> Self {
73 State { 70 State {
74 control: MaybeUninit::uninit(), 71 control: MaybeUninit::uninit(),
75 out_signal: Signal::new(), 72 out_signal: Signal::new(),
76 feature_signal: Signal::new(),
77 } 73 }
78 } 74 }
79} 75}
80 76
81pub struct HidClass< 77pub struct HidClass<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> {
82 'd,
83 D: Driver<'d>,
84 const IN_N: usize,
85 const OUT_N: usize,
86 const FEATURE_N: usize,
87> {
88 input: ReportWriter<'d, D, IN_N>, 78 input: ReportWriter<'d, D, IN_N>,
89 output: ReportReader<'d, D, OUT_N>, 79 output: ReportReader<'d, D, OUT_N>,
90 feature: ReportReader<'d, D, FEATURE_N>,
91} 80}
92 81
93impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N: usize> 82impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> HidClass<'d, D, IN_N, OUT_N> {
94 HidClass<'d, D, IN_N, OUT_N, FEATURE_N>
95{
96 /// Creates a new HidClass. 83 /// Creates a new HidClass.
97 /// 84 ///
98 /// poll_ms configures how frequently the host should poll for reading/writing 85 /// 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:
105 /// endpoint. 92 /// endpoint.
106 pub fn new( 93 pub fn new(
107 builder: &mut UsbDeviceBuilder<'d, D>, 94 builder: &mut UsbDeviceBuilder<'d, D>,
108 state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, 95 state: &'d mut State<'d, IN_N, OUT_N>,
109 report_descriptor: &'static [u8], 96 report_descriptor: &'static [u8],
110 request_handler: Option<&'d dyn RequestHandler>, 97 request_handler: Option<&'d dyn RequestHandler>,
111 poll_ms: u8, 98 poll_ms: u8,
@@ -126,7 +113,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
126 /// See new() for more details. 113 /// See new() for more details.
127 pub fn new_ep_in( 114 pub fn new_ep_in(
128 builder: &mut UsbDeviceBuilder<'d, D>, 115 builder: &mut UsbDeviceBuilder<'d, D>,
129 state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, 116 state: &'d mut State<'d, IN_N, OUT_N>,
130 report_descriptor: &'static [u8], 117 report_descriptor: &'static [u8],
131 request_handler: Option<&'d dyn RequestHandler>, 118 request_handler: Option<&'d dyn RequestHandler>,
132 poll_ms: u8, 119 poll_ms: u8,
@@ -147,7 +134,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
147 /// See new() for more details. 134 /// See new() for more details.
148 pub fn new_ep_out( 135 pub fn new_ep_out(
149 builder: &mut UsbDeviceBuilder<'d, D>, 136 builder: &mut UsbDeviceBuilder<'d, D>,
150 state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, 137 state: &'d mut State<'d, IN_N, OUT_N>,
151 report_descriptor: &'static [u8], 138 report_descriptor: &'static [u8],
152 request_handler: Option<&'d dyn RequestHandler>, 139 request_handler: Option<&'d dyn RequestHandler>,
153 poll_ms: u8, 140 poll_ms: u8,
@@ -166,7 +153,7 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
166 153
167 fn new_inner( 154 fn new_inner(
168 builder: &mut UsbDeviceBuilder<'d, D>, 155 builder: &mut UsbDeviceBuilder<'d, D>,
169 state: &'d mut State<'d, IN_N, OUT_N, FEATURE_N>, 156 state: &'d mut State<'d, IN_N, OUT_N>,
170 report_descriptor: &'static [u8], 157 report_descriptor: &'static [u8],
171 request_handler: Option<&'d dyn RequestHandler>, 158 request_handler: Option<&'d dyn RequestHandler>,
172 ep_out: Option<D::EndpointOut>, 159 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:
175 let control = state.control.write(Control::new( 162 let control = state.control.write(Control::new(
176 report_descriptor, 163 report_descriptor,
177 &state.out_signal, 164 &state.out_signal,
178 &state.feature_signal,
179 request_handler, 165 request_handler,
180 )); 166 ));
181 167
@@ -187,10 +173,6 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
187 ep_out, 173 ep_out,
188 receiver: &state.out_signal, 174 receiver: &state.out_signal,
189 }, 175 },
190 feature: ReportReader {
191 ep_out: None,
192 receiver: &state.feature_signal,
193 },
194 } 176 }
195 } 177 }
196 178
@@ -207,20 +189,9 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize, const FEATURE_N:
207 &mut self.output 189 &mut self.output
208 } 190 }
209 191
210 /// Gets the [`ReportReader`] for feature reports. 192 /// Splits this `HidClass` into seperate readers/writers for input and output reports.
211 pub fn feature(&mut self) -> &mut ReportReader<'d, D, FEATURE_N> { 193 pub fn split(self) -> (ReportWriter<'d, D, IN_N>, ReportReader<'d, D, OUT_N>) {
212 &mut self.feature 194 (self.input, self.output)
213 }
214
215 /// Splits this `HidClass` into seperate readers/writers for each report type.
216 pub fn split(
217 self,
218 ) -> (
219 ReportWriter<'d, D, IN_N>,
220 ReportReader<'d, D, OUT_N>,
221 ReportReader<'d, D, FEATURE_N>,
222 ) {
223 (self.input, self.output, self.feature)
224 } 195 }
225} 196}
226 197
@@ -314,7 +285,7 @@ impl<'d, D: Driver<'d>, const N: usize> ReportReader<'d, D, N> {
314} 285}
315 286
316pub trait RequestHandler { 287pub trait RequestHandler {
317 /// Read the value of report `id` into `buf` returning the size. 288 /// Reads the value of report `id` into `buf` returning the size.
318 /// 289 ///
319 /// Returns `None` if `id` is invalid or no data is available. 290 /// Returns `None` if `id` is invalid or no data is available.
320 fn get_report(&self, id: ReportId, buf: &mut [u8]) -> Option<usize> { 291 fn get_report(&self, id: ReportId, buf: &mut [u8]) -> Option<usize> {
@@ -322,12 +293,13 @@ pub trait RequestHandler {
322 None 293 None
323 } 294 }
324 295
325 /// Set the idle rate for `id` to `dur`. 296 /// Sets the value of report `id` to `data`.
326 /// 297 ///
327 /// If `id` is `None`, set the idle rate of all input reports to `dur`. If 298 /// This is only called for feature or input reports. Output reports
328 /// an indefinite duration is requested, `dur` will be set to `Duration::MAX`. 299 /// are routed through [`HidClass::output()`].
329 fn set_idle(&self, id: Option<ReportId>, dur: Duration) { 300 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
330 let _ = (id, dur); 301 let _ = (id, data);
302 OutResponse::Rejected
331 } 303 }
332 304
333 /// Get the idle rate for `id`. 305 /// Get the idle rate for `id`.
@@ -339,27 +311,32 @@ pub trait RequestHandler {
339 let _ = id; 311 let _ = id;
340 None 312 None
341 } 313 }
314
315 /// Set the idle rate for `id` to `dur`.
316 ///
317 /// If `id` is `None`, set the idle rate of all input reports to `dur`. If
318 /// an indefinite duration is requested, `dur` will be set to `Duration::MAX`.
319 fn set_idle(&self, id: Option<ReportId>, dur: Duration) {
320 let _ = (id, dur);
321 }
342} 322}
343 323
344pub struct Control<'d, const OUT_N: usize, const FEATURE_N: usize> { 324pub struct Control<'d, const OUT_N: usize> {
345 report_descriptor: &'static [u8], 325 report_descriptor: &'static [u8],
346 out_signal: &'d Signal<(usize, [u8; OUT_N])>, 326 out_signal: &'d Signal<(usize, [u8; OUT_N])>,
347 feature_signal: &'d Signal<(usize, [u8; FEATURE_N])>,
348 request_handler: Option<&'d dyn RequestHandler>, 327 request_handler: Option<&'d dyn RequestHandler>,
349 hid_descriptor: [u8; 9], 328 hid_descriptor: [u8; 9],
350} 329}
351 330
352impl<'a, const OUT_N: usize, const FEATURE_N: usize> Control<'a, OUT_N, FEATURE_N> { 331impl<'a, const OUT_N: usize> Control<'a, OUT_N> {
353 fn new( 332 fn new(
354 report_descriptor: &'static [u8], 333 report_descriptor: &'static [u8],
355 out_signal: &'a Signal<(usize, [u8; OUT_N])>, 334 out_signal: &'a Signal<(usize, [u8; OUT_N])>,
356 feature_signal: &'a Signal<(usize, [u8; FEATURE_N])>,
357 request_handler: Option<&'a dyn RequestHandler>, 335 request_handler: Option<&'a dyn RequestHandler>,
358 ) -> Self { 336 ) -> Self {
359 Control { 337 Control {
360 report_descriptor, 338 report_descriptor,
361 out_signal, 339 out_signal,
362 feature_signal,
363 request_handler, 340 request_handler,
364 hid_descriptor: [ 341 hid_descriptor: [
365 // Length of buf inclusive of size prefix 342 // 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_
426 } 403 }
427} 404}
428 405
429impl<'d, const OUT_N: usize, const FEATURE_N: usize> ControlHandler 406impl<'d, const OUT_N: usize> ControlHandler for Control<'d, OUT_N> {
430 for Control<'d, OUT_N, FEATURE_N>
431{
432 fn reset(&mut self) {} 407 fn reset(&mut self) {}
433 408
434 fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse { 409 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
450 OutResponse::Accepted 425 OutResponse::Accepted
451 } 426 }
452 HID_REQ_SET_REPORT => match ReportId::try_from(req.value) { 427 HID_REQ_SET_REPORT => match ReportId::try_from(req.value) {
453 Ok(ReportId::In(_)) => OutResponse::Rejected,
454 Ok(ReportId::Out(_id)) => { 428 Ok(ReportId::Out(_id)) => {
455 let mut buf = [0; OUT_N]; 429 let mut buf = [0; OUT_N];
456 buf[0..data.len()].copy_from_slice(data); 430 buf[0..data.len()].copy_from_slice(data);
@@ -460,14 +434,12 @@ impl<'d, const OUT_N: usize, const FEATURE_N: usize> ControlHandler
460 self.out_signal.signal((data.len(), buf)); 434 self.out_signal.signal((data.len(), buf));
461 OutResponse::Accepted 435 OutResponse::Accepted
462 } 436 }
463 Ok(ReportId::Feature(_id)) => { 437 Ok(id @ ReportId::Feature(_)) | Ok(id @ ReportId::In(_)) => {
464 let mut buf = [0; FEATURE_N]; 438 if let Some(handler) = self.request_handler.as_ref() {
465 buf[0..data.len()].copy_from_slice(data); 439 handler.set_report(id, data)
466 if self.feature_signal.signaled() { 440 } else {
467 warn!("Feature report dropped before being read!"); 441 OutResponse::Rejected
468 } 442 }
469 self.feature_signal.signal((data.len(), buf));
470 OutResponse::Accepted
471 } 443 }
472 Err(_) => OutResponse::Rejected, 444 Err(_) => OutResponse::Rejected,
473 }, 445 },
diff --git a/examples/nrf/src/bin/usb_hid.rs b/examples/nrf/src/bin/usb_hid.rs
index 1fd056d00..11c2d71ad 100644
--- a/examples/nrf/src/bin/usb_hid.rs
+++ b/examples/nrf/src/bin/usb_hid.rs
@@ -14,6 +14,7 @@ use embassy_nrf::interrupt;
14use embassy_nrf::pac; 14use embassy_nrf::pac;
15use embassy_nrf::usb::Driver; 15use embassy_nrf::usb::Driver;
16use embassy_nrf::Peripherals; 16use embassy_nrf::Peripherals;
17use embassy_usb::control::OutResponse;
17use embassy_usb::{Config, UsbDeviceBuilder}; 18use embassy_usb::{Config, UsbDeviceBuilder};
18use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 19use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State};
19use futures::future::join; 20use futures::future::join;
@@ -51,7 +52,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
51 let mut control_buf = [0; 16]; 52 let mut control_buf = [0; 16];
52 let request_handler = MyRequestHandler {}; 53 let request_handler = MyRequestHandler {};
53 54
54 let mut state = State::<5, 0, 0>::new(); 55 let mut state = State::<5, 0>::new();
55 56
56 let mut builder = UsbDeviceBuilder::new( 57 let mut builder = UsbDeviceBuilder::new(
57 driver, 58 driver,
@@ -63,8 +64,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
63 ); 64 );
64 65
65 // Create classes on the builder. 66 // Create classes on the builder.
66 // let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); 67 let mut hid = HidClass::new_ep_in(
67 let mut hid = HidClass::new(
68 &mut builder, 68 &mut builder,
69 &mut state, 69 &mut state,
70 MouseReport::desc(), 70 MouseReport::desc(),
@@ -120,6 +120,11 @@ impl RequestHandler for MyRequestHandler {
120 None 120 None
121 } 121 }
122 122
123 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
124 info!("Set report for {:?}: {=[u8]}", id, data);
125 OutResponse::Accepted
126 }
127
123 fn set_idle(&self, id: Option<ReportId>, dur: Duration) { 128 fn set_idle(&self, id: Option<ReportId>, dur: Duration) {
124 info!("Set idle rate for {:?} to {:?}", id, dur); 129 info!("Set idle rate for {:?} to {:?}", id, dur);
125 } 130 }