aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-04-01 10:57:37 -0400
committerDario Nieuwenhuis <[email protected]>2022-04-06 05:38:11 +0200
commitc309531874052bc96ef9ce39dd8698c120cee824 (patch)
tree365424e5b37ec66a200a49fd0cd157dd57f278bb
parentdaf2379fa4d4ab8772982847613a09a750ac7ba8 (diff)
Remove output() and split() methods from HidClass when there is no out endpoint, and route set_report requests for output reports to RequestHandler::set_report in that case.
-rw-r--r--embassy-usb-hid/src/lib.rs125
-rw-r--r--examples/nrf/src/bin/usb_hid.rs3
2 files changed, 62 insertions, 66 deletions
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs
index 4a7e60320..8bc9efdb0 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb-hid/src/lib.rs
@@ -74,12 +74,12 @@ impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> {
74 } 74 }
75} 75}
76 76
77pub struct HidClass<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> { 77pub struct HidClass<'d, D: Driver<'d>, T, const IN_N: usize> {
78 input: ReportWriter<'d, D, IN_N>, 78 input: ReportWriter<'d, D, IN_N>,
79 output: ReportReader<'d, D, OUT_N>, 79 output: T,
80} 80}
81 81
82impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> HidClass<'d, D, IN_N, OUT_N> { 82impl<'d, D: Driver<'d>, const IN_N: usize> HidClass<'d, D, (), IN_N> {
83 /// Creates a new HidClass. 83 /// Creates a new HidClass.
84 /// 84 ///
85 /// 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
@@ -87,60 +87,64 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> HidClass<'d, D, I
87 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for 87 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
88 /// high performance uses, and a value of 255 is good for best-effort usecases. 88 /// high performance uses, and a value of 255 is good for best-effort usecases.
89 /// 89 ///
90 /// This allocates two endpoints (IN and OUT). 90 /// This allocates an IN endpoint only.
91 /// See new_ep_in (IN endpoint only) and new_ep_out (OUT endpoint only) to only create a single
92 /// endpoint.
93 pub fn new( 91 pub fn new(
94 builder: &mut UsbDeviceBuilder<'d, D>, 92 builder: &mut UsbDeviceBuilder<'d, D>,
95 state: &'d mut State<'d, IN_N, OUT_N>, 93 state: &'d mut State<'d, IN_N, 0>,
96 report_descriptor: &'static [u8], 94 report_descriptor: &'static [u8],
97 request_handler: Option<&'d dyn RequestHandler>, 95 request_handler: Option<&'d dyn RequestHandler>,
98 poll_ms: u8, 96 poll_ms: u8,
97 max_packet_size: u16,
99 ) -> Self { 98 ) -> Self {
100 let ep_out = Some(builder.alloc_interrupt_endpoint_out(64, poll_ms)); 99 let ep_in = builder.alloc_interrupt_endpoint_in(max_packet_size, poll_ms);
101 let ep_in = builder.alloc_interrupt_endpoint_in(64, poll_ms); 100 let control = state
102 Self::new_inner( 101 .control
103 builder, 102 .write(Control::new(report_descriptor, None, request_handler));
104 state, 103
105 report_descriptor, 104 control.build(builder, None, &ep_in);
106 request_handler, 105
107 ep_out, 106 Self {
108 ep_in, 107 input: ReportWriter { ep_in },
109 ) 108 output: (),
109 }
110 } 110 }
111}
111 112
112 /// Creates a new HidClass with the provided UsbBus & HID report descriptor. 113impl<'d, D: Driver<'d>, T, const IN_N: usize> HidClass<'d, D, T, IN_N> {
113 /// See new() for more details. 114 /// Gets the [`ReportWriter`] for input reports.
114 pub fn new_ep_in( 115 ///
115 builder: &mut UsbDeviceBuilder<'d, D>, 116 /// **Note:** If the `HidClass` was created with [`new_ep_out()`](Self::new_ep_out)
116 state: &'d mut State<'d, IN_N, OUT_N>, 117 /// this writer will be useless as no endpoint is availabe to send reports.
117 report_descriptor: &'static [u8], 118 pub fn input(&mut self) -> &mut ReportWriter<'d, D, IN_N> {
118 request_handler: Option<&'d dyn RequestHandler>, 119 &mut self.input
119 poll_ms: u8,
120 ) -> Self {
121 let ep_out = None;
122 let ep_in = builder.alloc_interrupt_endpoint_in(64, poll_ms);
123 Self::new_inner(
124 builder,
125 state,
126 report_descriptor,
127 request_handler,
128 ep_out,
129 ep_in,
130 )
131 } 120 }
121}
132 122
133 fn new_inner( 123impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize>
124 HidClass<'d, D, ReportReader<'d, D, OUT_N>, IN_N>
125{
126 /// Creates a new HidClass.
127 ///
128 /// poll_ms configures how frequently the host should poll for reading/writing
129 /// HID reports. A lower value means better throughput & latency, at the expense
130 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
131 /// high performance uses, and a value of 255 is good for best-effort usecases.
132 ///
133 /// This allocates two endpoints (IN and OUT).
134 pub fn with_output_ep(
134 builder: &mut UsbDeviceBuilder<'d, D>, 135 builder: &mut UsbDeviceBuilder<'d, D>,
135 state: &'d mut State<'d, IN_N, OUT_N>, 136 state: &'d mut State<'d, IN_N, OUT_N>,
136 report_descriptor: &'static [u8], 137 report_descriptor: &'static [u8],
137 request_handler: Option<&'d dyn RequestHandler>, 138 request_handler: Option<&'d dyn RequestHandler>,
138 ep_out: Option<D::EndpointOut>, 139 poll_ms: u8,
139 ep_in: D::EndpointIn, 140 max_packet_size: u16,
140 ) -> Self { 141 ) -> Self {
142 let ep_out = Some(builder.alloc_interrupt_endpoint_out(max_packet_size, poll_ms));
143 let ep_in = builder.alloc_interrupt_endpoint_in(max_packet_size, poll_ms);
144
141 let control = state.control.write(Control::new( 145 let control = state.control.write(Control::new(
142 report_descriptor, 146 report_descriptor,
143 &state.out_signal, 147 Some(&state.out_signal),
144 request_handler, 148 request_handler,
145 )); 149 ));
146 150
@@ -155,14 +159,6 @@ impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> HidClass<'d, D, I
155 } 159 }
156 } 160 }
157 161
158 /// Gets the [`ReportWriter`] for input reports.
159 ///
160 /// **Note:** If the `HidClass` was created with [`new_ep_out()`](Self::new_ep_out)
161 /// this writer will be useless as no endpoint is availabe to send reports.
162 pub fn input(&mut self) -> &mut ReportWriter<'d, D, IN_N> {
163 &mut self.input
164 }
165
166 /// Gets the [`ReportReader`] for output reports. 162 /// Gets the [`ReportReader`] for output reports.
167 pub fn output(&mut self) -> &mut ReportReader<'d, D, OUT_N> { 163 pub fn output(&mut self) -> &mut ReportReader<'d, D, OUT_N> {
168 &mut self.output 164 &mut self.output
@@ -269,8 +265,9 @@ pub trait RequestHandler {
269 265
270 /// Sets the value of report `id` to `data`. 266 /// Sets the value of report `id` to `data`.
271 /// 267 ///
272 /// This is only called for feature or input reports. Output reports 268 /// If an output endpoint has been allocated, output reports
273 /// are routed through [`HidClass::output()`]. 269 /// are routed through [`HidClass::output()`]. Otherwise they
270 /// are sent here, along with input and feature reports.
274 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { 271 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
275 let _ = (id, data); 272 let _ = (id, data);
276 OutResponse::Rejected 273 OutResponse::Rejected
@@ -295,9 +292,9 @@ pub trait RequestHandler {
295 } 292 }
296} 293}
297 294
298pub struct Control<'d, const OUT_N: usize> { 295struct Control<'d, const OUT_N: usize> {
299 report_descriptor: &'static [u8], 296 report_descriptor: &'static [u8],
300 out_signal: &'d Signal<(usize, [u8; OUT_N])>, 297 out_signal: Option<&'d Signal<(usize, [u8; OUT_N])>>,
301 request_handler: Option<&'d dyn RequestHandler>, 298 request_handler: Option<&'d dyn RequestHandler>,
302 hid_descriptor: [u8; 9], 299 hid_descriptor: [u8; 9],
303} 300}
@@ -305,7 +302,7 @@ pub struct Control<'d, const OUT_N: usize> {
305impl<'a, const OUT_N: usize> Control<'a, OUT_N> { 302impl<'a, const OUT_N: usize> Control<'a, OUT_N> {
306 fn new( 303 fn new(
307 report_descriptor: &'static [u8], 304 report_descriptor: &'static [u8],
308 out_signal: &'a Signal<(usize, [u8; OUT_N])>, 305 out_signal: Option<&'a Signal<(usize, [u8; OUT_N])>>,
309 request_handler: Option<&'a dyn RequestHandler>, 306 request_handler: Option<&'a dyn RequestHandler>,
310 ) -> Self { 307 ) -> Self {
311 Control { 308 Control {
@@ -396,24 +393,22 @@ impl<'d, const OUT_N: usize> ControlHandler for Control<'d, OUT_N> {
396 } 393 }
397 OutResponse::Accepted 394 OutResponse::Accepted
398 } 395 }
399 HID_REQ_SET_REPORT => match ReportId::try_from(req.value) { 396 HID_REQ_SET_REPORT => match (
400 Ok(ReportId::Out(_id)) => { 397 ReportId::try_from(req.value),
398 self.out_signal,
399 self.request_handler.as_ref(),
400 ) {
401 (Ok(ReportId::Out(_)), Some(signal), _) => {
401 let mut buf = [0; OUT_N]; 402 let mut buf = [0; OUT_N];
402 buf[0..data.len()].copy_from_slice(data); 403 buf[0..data.len()].copy_from_slice(data);
403 if self.out_signal.signaled() { 404 if signal.signaled() {
404 warn!("Output report dropped before being read!"); 405 warn!("Output report dropped before being read!");
405 } 406 }
406 self.out_signal.signal((data.len(), buf)); 407 signal.signal((data.len(), buf));
407 OutResponse::Accepted 408 OutResponse::Accepted
408 } 409 }
409 Ok(id @ ReportId::Feature(_)) | Ok(id @ ReportId::In(_)) => { 410 (Ok(id), _, Some(handler)) => handler.set_report(id, data),
410 if let Some(handler) = self.request_handler.as_ref() { 411 _ => OutResponse::Rejected,
411 handler.set_report(id, data)
412 } else {
413 OutResponse::Rejected
414 }
415 }
416 Err(_) => OutResponse::Rejected,
417 }, 412 },
418 HID_REQ_SET_PROTOCOL => { 413 HID_REQ_SET_PROTOCOL => {
419 if req.value == 1 { 414 if req.value == 1 {
diff --git a/examples/nrf/src/bin/usb_hid.rs b/examples/nrf/src/bin/usb_hid.rs
index 11c2d71ad..5253f225d 100644
--- a/examples/nrf/src/bin/usb_hid.rs
+++ b/examples/nrf/src/bin/usb_hid.rs
@@ -64,12 +64,13 @@ async fn main(_spawner: Spawner, p: Peripherals) {
64 ); 64 );
65 65
66 // Create classes on the builder. 66 // Create classes on the builder.
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(),
71 Some(&request_handler), 71 Some(&request_handler),
72 60, 72 60,
73 8,
73 ); 74 );
74 75
75 // Build the builder. 76 // Build the builder.