aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-16 01:55:21 +0000
committerGitHub <[email protected]>2022-04-16 01:55:21 +0000
commit1c9adec3c59da48f8084c29b4ece083100a703e3 (patch)
tree848a28f4a2dfcad860073360c36f0e4ad7a52088
parent3a90a8eb4a5ef61aef034025ac882255c94260dc (diff)
parentf35bde684acb736fd4d5b709833b8c2a47146fa8 (diff)
Merge #721
721: USB HID: simplify API r=Dirbaio a=Dirbaio Following the discussion from #720 and [matrix](https://matrix.to/#/!YoLPkieCYHGzdjUhOK:matrix.org/$PcPr8E_JbodEPuUUKI2PzIC9sx7nF3y0kV2T5O4UWj8?via=matrix.org&via=converser.eu&via=braun-odw.eu), this is a second take on simplifying the HID API. Split into a separate PR so it can be reviewed separately. See individual commit messages for details. cc `@alexmoon` Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rw-r--r--embassy-usb-hid/src/lib.rs289
-rw-r--r--embassy-usb/src/control.rs4
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs27
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs22
4 files changed, 178 insertions, 164 deletions
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb-hid/src/lib.rs
index e870becf5..abcd6b5d9 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb-hid/src/lib.rs
@@ -41,6 +41,24 @@ const HID_REQ_SET_REPORT: u8 = 0x09;
41const HID_REQ_GET_PROTOCOL: u8 = 0x03; 41const HID_REQ_GET_PROTOCOL: u8 = 0x03;
42const HID_REQ_SET_PROTOCOL: u8 = 0x0b; 42const HID_REQ_SET_PROTOCOL: u8 = 0x0b;
43 43
44pub struct Config<'d> {
45 /// HID report descriptor.
46 pub report_descriptor: &'d [u8],
47
48 /// Handler for control requests.
49 pub request_handler: Option<&'d dyn RequestHandler>,
50
51 /// Configures how frequently the host should poll for reading/writing HID reports.
52 ///
53 /// A lower value means better throughput & latency, at the expense
54 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
55 /// high performance uses, and a value of 255 is good for best-effort usecases.
56 pub poll_ms: u8,
57
58 /// Max packet size for both the IN and OUT endpoints.
59 pub max_packet_size: u16,
60}
61
44#[derive(Debug, Clone, Copy, PartialEq, Eq)] 62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))] 63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub enum ReportId { 64pub enum ReportId {
@@ -60,12 +78,12 @@ impl ReportId {
60 } 78 }
61} 79}
62 80
63pub struct State<'a, const IN_N: usize, const OUT_N: usize> { 81pub struct State<'d> {
64 control: MaybeUninit<Control<'a>>, 82 control: MaybeUninit<Control<'d>>,
65 out_report_offset: AtomicUsize, 83 out_report_offset: AtomicUsize,
66} 84}
67 85
68impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> { 86impl<'d> State<'d> {
69 pub fn new() -> Self { 87 pub fn new() -> Self {
70 State { 88 State {
71 control: MaybeUninit::uninit(), 89 control: MaybeUninit::uninit(),
@@ -74,107 +92,128 @@ impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> {
74 } 92 }
75} 93}
76 94
77pub struct HidClass<'d, D: Driver<'d>, T, const IN_N: usize> { 95pub struct HidReaderWriter<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> {
78 input: ReportWriter<'d, D, IN_N>, 96 reader: HidReader<'d, D, READ_N>,
79 output: T, 97 writer: HidWriter<'d, D, WRITE_N>,
80} 98}
81 99
82impl<'d, D: Driver<'d>, const IN_N: usize> HidClass<'d, D, (), IN_N> { 100fn build<'d, D: Driver<'d>>(
83 /// Creates a new HidClass. 101 builder: &mut UsbDeviceBuilder<'d, D>,
84 /// 102 state: &'d mut State<'d>,
85 /// poll_ms configures how frequently the host should poll for reading/writing 103 config: Config<'d>,
86 /// HID reports. A lower value means better throughput & latency, at the expense 104 with_out_endpoint: bool,
87 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for 105) -> (Option<D::EndpointOut>, D::EndpointIn, &'d AtomicUsize) {
88 /// high performance uses, and a value of 255 is good for best-effort usecases. 106 let control = state.control.write(Control::new(
89 /// 107 config.report_descriptor,
90 /// This allocates an IN endpoint only. 108 config.request_handler,
91 pub fn new<const OUT_N: usize>( 109 &state.out_report_offset,
92 builder: &mut UsbDeviceBuilder<'d, D>, 110 ));
93 state: &'d mut State<'d, IN_N, OUT_N>, 111
94 report_descriptor: &'static [u8], 112 let len = config.report_descriptor.len();
95 request_handler: Option<&'d dyn RequestHandler>, 113 let if_num = builder.alloc_interface_with_handler(control);
96 poll_ms: u8, 114 let ep_in = builder.alloc_interrupt_endpoint_in(config.max_packet_size, config.poll_ms);
97 max_packet_size: u16, 115 let ep_out = if with_out_endpoint {
98 ) -> Self { 116 Some(builder.alloc_interrupt_endpoint_out(config.max_packet_size, config.poll_ms))
99 let ep_in = builder.alloc_interrupt_endpoint_in(max_packet_size, poll_ms); 117 } else {
100 let control = state.control.write(Control::new( 118 None
101 report_descriptor, 119 };
102 request_handler, 120
103 &state.out_report_offset, 121 builder.config_descriptor.interface(
104 )); 122 if_num,
105 control.build(builder, None, &ep_in); 123 USB_CLASS_HID,
106 124 USB_SUBCLASS_NONE,
107 Self { 125 USB_PROTOCOL_NONE,
108 input: ReportWriter { ep_in }, 126 );
109 output: (), 127
110 } 128 // HID descriptor
129 builder.config_descriptor.write(
130 HID_DESC_DESCTYPE_HID,
131 &[
132 // HID Class spec version
133 HID_DESC_SPEC_1_10[0],
134 HID_DESC_SPEC_1_10[1],
135 // Country code not supported
136 HID_DESC_COUNTRY_UNSPEC,
137 // Number of following descriptors
138 1,
139 // We have a HID report descriptor the host should read
140 HID_DESC_DESCTYPE_HID_REPORT,
141 // HID report descriptor size,
142 (len & 0xFF) as u8,
143 (len >> 8 & 0xFF) as u8,
144 ],
145 );
146
147 builder.config_descriptor.endpoint(ep_in.info());
148 if let Some(ep_out) = &ep_out {
149 builder.config_descriptor.endpoint(ep_out.info());
111 } 150 }
112}
113 151
114impl<'d, D: Driver<'d>, T, const IN_N: usize> HidClass<'d, D, T, IN_N> { 152 (ep_out, ep_in, &state.out_report_offset)
115 /// Gets the [`ReportWriter`] for input reports.
116 ///
117 /// **Note:** If the `HidClass` was created with [`new_ep_out()`](Self::new_ep_out)
118 /// this writer will be useless as no endpoint is availabe to send reports.
119 pub fn input(&mut self) -> &mut ReportWriter<'d, D, IN_N> {
120 &mut self.input
121 }
122} 153}
123 154
124impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> 155impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize>
125 HidClass<'d, D, ReportReader<'d, D, OUT_N>, IN_N> 156 HidReaderWriter<'d, D, READ_N, WRITE_N>
126{ 157{
127 /// Creates a new HidClass. 158 /// Creates a new HidReaderWriter.
128 /// 159 ///
129 /// poll_ms configures how frequently the host should poll for reading/writing 160 /// This will allocate one IN and one OUT endpoints. If you only need writing (sending)
130 /// HID reports. A lower value means better throughput & latency, at the expense 161 /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
131 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
132 /// high performance uses, and a value of 255 is good for best-effort usecases.
133 /// 162 ///
134 /// This allocates two endpoints (IN and OUT). 163 pub fn new(
135 pub fn with_output_ep(
136 builder: &mut UsbDeviceBuilder<'d, D>, 164 builder: &mut UsbDeviceBuilder<'d, D>,
137 state: &'d mut State<'d, IN_N, OUT_N>, 165 state: &'d mut State<'d>,
138 report_descriptor: &'static [u8], 166 config: Config<'d>,
139 request_handler: Option<&'d dyn RequestHandler>,
140 poll_ms: u8,
141 max_packet_size: u16,
142 ) -> Self { 167 ) -> Self {
143 let ep_out = builder.alloc_interrupt_endpoint_out(max_packet_size, poll_ms); 168 let (ep_out, ep_in, offset) = build(builder, state, config, true);
144 let ep_in = builder.alloc_interrupt_endpoint_in(max_packet_size, poll_ms);
145
146 let control = state.control.write(Control::new(
147 report_descriptor,
148 request_handler,
149 &state.out_report_offset,
150 ));
151 control.build(builder, Some(&ep_out), &ep_in);
152 169
153 Self { 170 Self {
154 input: ReportWriter { ep_in }, 171 reader: HidReader {
155 output: ReportReader { 172 ep_out: ep_out.unwrap(),
156 ep_out, 173 offset,
157 offset: &state.out_report_offset,
158 }, 174 },
175 writer: HidWriter { ep_in },
159 } 176 }
160 } 177 }
161 178
162 /// Gets the [`ReportReader`] for output reports. 179 /// Splits into seperate readers/writers for input and output reports.
163 pub fn output(&mut self) -> &mut ReportReader<'d, D, OUT_N> { 180 pub fn split(self) -> (HidReader<'d, D, READ_N>, HidWriter<'d, D, WRITE_N>) {
164 &mut self.output 181 (self.reader, self.writer)
182 }
183
184 /// Waits for both IN and OUT endpoints to be enabled.
185 pub async fn ready(&mut self) -> () {
186 self.reader.ready().await;
187 self.writer.ready().await;
165 } 188 }
166 189
167 /// Splits this `HidClass` into seperate readers/writers for input and output reports. 190 /// Writes an input report by serializing the given report structure.
168 pub fn split(self) -> (ReportWriter<'d, D, IN_N>, ReportReader<'d, D, OUT_N>) { 191 #[cfg(feature = "usbd-hid")]
169 (self.input, self.output) 192 pub async fn write_serialize<IR: AsInputReport>(
193 &mut self,
194 r: &IR,
195 ) -> Result<(), EndpointError> {
196 self.writer.write_serialize(r).await
197 }
198
199 /// Writes `report` to its interrupt endpoint.
200 pub async fn write(&mut self, report: &[u8]) -> Result<(), EndpointError> {
201 self.writer.write(report).await
202 }
203
204 /// Reads an output report from the Interrupt Out pipe.
205 ///
206 /// See [`HidReader::read`].
207 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, ReadError> {
208 self.reader.read(buf).await
170 } 209 }
171} 210}
172 211
173pub struct ReportWriter<'d, D: Driver<'d>, const N: usize> { 212pub struct HidWriter<'d, D: Driver<'d>, const N: usize> {
174 ep_in: D::EndpointIn, 213 ep_in: D::EndpointIn,
175} 214}
176 215
177pub struct ReportReader<'d, D: Driver<'d>, const N: usize> { 216pub struct HidReader<'d, D: Driver<'d>, const N: usize> {
178 ep_out: D::EndpointOut, 217 ep_out: D::EndpointOut,
179 offset: &'d AtomicUsize, 218 offset: &'d AtomicUsize,
180} 219}
@@ -197,17 +236,39 @@ impl From<embassy_usb::driver::EndpointError> for ReadError {
197 } 236 }
198} 237}
199 238
200impl<'d, D: Driver<'d>, const N: usize> ReportWriter<'d, D, N> { 239impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
240 /// Creates a new HidWriter.
241 ///
242 /// This will allocate one IN endpoint only, so the host won't be able to send
243 /// reports to us. If you need that, consider using [`HidReaderWriter::new`] instead.
244 ///
245 /// poll_ms configures how frequently the host should poll for reading/writing
246 /// HID reports. A lower value means better throughput & latency, at the expense
247 /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for
248 /// high performance uses, and a value of 255 is good for best-effort usecases.
249 pub fn new(
250 builder: &mut UsbDeviceBuilder<'d, D>,
251 state: &'d mut State<'d>,
252 config: Config<'d>,
253 ) -> Self {
254 let (ep_out, ep_in, _offset) = build(builder, state, config, false);
255
256 assert!(ep_out.is_none());
257
258 Self { ep_in }
259 }
260
201 /// Waits for the interrupt in endpoint to be enabled. 261 /// Waits for the interrupt in endpoint to be enabled.
202 pub async fn ready(&mut self) -> () { 262 pub async fn ready(&mut self) -> () {
203 self.ep_in.wait_enabled().await 263 self.ep_in.wait_enabled().await
204 } 264 }
205 265
206 /// Tries to write an input report by serializing the given report structure. 266 /// Writes an input report by serializing the given report structure.
207 ///
208 /// Panics if no endpoint is available.
209 #[cfg(feature = "usbd-hid")] 267 #[cfg(feature = "usbd-hid")]
210 pub async fn serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> { 268 pub async fn write_serialize<IR: AsInputReport>(
269 &mut self,
270 r: &IR,
271 ) -> Result<(), EndpointError> {
211 let mut buf: [u8; N] = [0; N]; 272 let mut buf: [u8; N] = [0; N];
212 let size = match serialize(&mut buf, r) { 273 let size = match serialize(&mut buf, r) {
213 Ok(size) => size, 274 Ok(size) => size,
@@ -217,8 +278,6 @@ impl<'d, D: Driver<'d>, const N: usize> ReportWriter<'d, D, N> {
217 } 278 }
218 279
219 /// Writes `report` to its interrupt endpoint. 280 /// Writes `report` to its interrupt endpoint.
220 ///
221 /// Panics if no endpoint is available.
222 pub async fn write(&mut self, report: &[u8]) -> Result<(), EndpointError> { 281 pub async fn write(&mut self, report: &[u8]) -> Result<(), EndpointError> {
223 assert!(report.len() <= N); 282 assert!(report.len() <= N);
224 283
@@ -236,16 +295,13 @@ impl<'d, D: Driver<'d>, const N: usize> ReportWriter<'d, D, N> {
236 } 295 }
237} 296}
238 297
239impl<'d, D: Driver<'d>, const N: usize> ReportReader<'d, D, N> { 298impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
240 /// Waits for the interrupt out endpoint to be enabled. 299 /// Waits for the interrupt out endpoint to be enabled.
241 pub async fn ready(&mut self) -> () { 300 pub async fn ready(&mut self) -> () {
242 self.ep_out.wait_enabled().await 301 self.ep_out.wait_enabled().await
243 } 302 }
244 303
245 /// Starts a task to deliver output reports from the Interrupt Out pipe to 304 /// Delivers output reports from the Interrupt Out pipe to `handler`.
246 /// `handler`.
247 ///
248 /// Terminates when the interface becomes disabled.
249 /// 305 ///
250 /// If `use_report_ids` is true, the first byte of the report will be used as 306 /// If `use_report_ids` is true, the first byte of the report will be used as
251 /// the `ReportId` value. Otherwise the `ReportId` value will be 0. 307 /// the `ReportId` value. Otherwise the `ReportId` value will be 0.
@@ -355,17 +411,17 @@ pub trait RequestHandler {
355} 411}
356 412
357struct Control<'d> { 413struct Control<'d> {
358 report_descriptor: &'static [u8], 414 report_descriptor: &'d [u8],
359 request_handler: Option<&'d dyn RequestHandler>, 415 request_handler: Option<&'d dyn RequestHandler>,
360 out_report_offset: &'d AtomicUsize, 416 out_report_offset: &'d AtomicUsize,
361 hid_descriptor: [u8; 9], 417 hid_descriptor: [u8; 9],
362} 418}
363 419
364impl<'a> Control<'a> { 420impl<'d> Control<'d> {
365 fn new( 421 fn new(
366 report_descriptor: &'static [u8], 422 report_descriptor: &'d [u8],
367 request_handler: Option<&'a dyn RequestHandler>, 423 request_handler: Option<&'d dyn RequestHandler>,
368 out_report_offset: &'a AtomicUsize, 424 out_report_offset: &'d AtomicUsize,
369 ) -> Self { 425 ) -> Self {
370 Control { 426 Control {
371 report_descriptor, 427 report_descriptor,
@@ -391,47 +447,6 @@ impl<'a> Control<'a> {
391 ], 447 ],
392 } 448 }
393 } 449 }
394
395 fn build<'d, D: Driver<'d>>(
396 &'d mut self,
397 builder: &mut UsbDeviceBuilder<'d, D>,
398 ep_out: Option<&D::EndpointOut>,
399 ep_in: &D::EndpointIn,
400 ) {
401 let len = self.report_descriptor.len();
402 let if_num = builder.alloc_interface_with_handler(self);
403
404 builder.config_descriptor.interface(
405 if_num,
406 USB_CLASS_HID,
407 USB_SUBCLASS_NONE,
408 USB_PROTOCOL_NONE,
409 );
410
411 // HID descriptor
412 builder.config_descriptor.write(
413 HID_DESC_DESCTYPE_HID,
414 &[
415 // HID Class spec version
416 HID_DESC_SPEC_1_10[0],
417 HID_DESC_SPEC_1_10[1],
418 // Country code not supported
419 HID_DESC_COUNTRY_UNSPEC,
420 // Number of following descriptors
421 1,
422 // We have a HID report descriptor the host should read
423 HID_DESC_DESCTYPE_HID_REPORT,
424 // HID report descriptor size,
425 (len & 0xFF) as u8,
426 (len >> 8 & 0xFF) as u8,
427 ],
428 );
429
430 builder.config_descriptor.endpoint(ep_in.info());
431 if let Some(ep) = ep_out {
432 builder.config_descriptor.endpoint(ep.info());
433 }
434 }
435} 450}
436 451
437impl<'d> ControlHandler for Control<'d> { 452impl<'d> ControlHandler for Control<'d> {
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index a613f1145..9300d8c4c 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -271,9 +271,9 @@ impl<C: driver::ControlPipe> ControlPipe<C> {
271 271
272 let res = &buf[0..total]; 272 let res = &buf[0..total];
273 #[cfg(feature = "defmt")] 273 #[cfg(feature = "defmt")]
274 trace!(" control out data: {:02x}", buf); 274 trace!(" control out data: {:02x}", res);
275 #[cfg(not(feature = "defmt"))] 275 #[cfg(not(feature = "defmt"))]
276 trace!(" control out data: {:02x?}", buf); 276 trace!(" control out data: {:02x?}", res);
277 277
278 Ok((res, StatusStage {})) 278 Ok((res, StatusStage {}))
279 } 279 }
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 5f03f5126..a2d78b08e 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -18,7 +18,7 @@ use embassy_nrf::usb::Driver;
18use embassy_nrf::Peripherals; 18use embassy_nrf::Peripherals;
19use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
20use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; 20use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder};
21use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 21use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
22use futures::future::join; 22use futures::future::join;
23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 23use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
24 24
@@ -75,7 +75,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
75 let request_handler = MyRequestHandler {}; 75 let request_handler = MyRequestHandler {};
76 let device_state_handler = MyDeviceStateHandler::new(); 76 let device_state_handler = MyDeviceStateHandler::new();
77 77
78 let mut state = State::<8, 1>::new(); 78 let mut state = State::new();
79 79
80 let mut builder = UsbDeviceBuilder::new( 80 let mut builder = UsbDeviceBuilder::new(
81 driver, 81 driver,
@@ -88,14 +88,13 @@ async fn main(_spawner: Spawner, p: Peripherals) {
88 ); 88 );
89 89
90 // Create classes on the builder. 90 // Create classes on the builder.
91 let hid = HidClass::with_output_ep( 91 let config = embassy_usb_hid::Config {
92 &mut builder, 92 report_descriptor: KeyboardReport::desc(),
93 &mut state, 93 request_handler: Some(&request_handler),
94 KeyboardReport::desc(), 94 poll_ms: 60,
95 Some(&request_handler), 95 max_packet_size: 64,
96 60, 96 };
97 64, 97 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
98 );
99 98
100 // Build the builder. 99 // Build the builder.
101 let mut usb = builder.build(); 100 let mut usb = builder.build();
@@ -135,7 +134,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
135 134
136 let mut button = Input::new(p.P0_11.degrade(), Pull::Up); 135 let mut button = Input::new(p.P0_11.degrade(), Pull::Up);
137 136
138 let (mut hid_in, hid_out) = hid.split(); 137 let (reader, mut writer) = hid.split();
139 138
140 // Do stuff with the class! 139 // Do stuff with the class!
141 let in_fut = async { 140 let in_fut = async {
@@ -153,7 +152,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
153 modifier: 0, 152 modifier: 0,
154 reserved: 0, 153 reserved: 0,
155 }; 154 };
156 match hid_in.serialize(&report).await { 155 match writer.write_serialize(&report).await {
157 Ok(()) => {} 156 Ok(()) => {}
158 Err(e) => warn!("Failed to send report: {:?}", e), 157 Err(e) => warn!("Failed to send report: {:?}", e),
159 }; 158 };
@@ -167,7 +166,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
167 modifier: 0, 166 modifier: 0,
168 reserved: 0, 167 reserved: 0,
169 }; 168 };
170 match hid_in.serialize(&report).await { 169 match writer.write_serialize(&report).await {
171 Ok(()) => {} 170 Ok(()) => {}
172 Err(e) => warn!("Failed to send report: {:?}", e), 171 Err(e) => warn!("Failed to send report: {:?}", e),
173 }; 172 };
@@ -175,7 +174,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
175 }; 174 };
176 175
177 let out_fut = async { 176 let out_fut = async {
178 hid_out.run(false, &request_handler).await; 177 reader.run(false, &request_handler).await;
179 }; 178 };
180 179
181 let power_irq = interrupt::take!(POWER_CLOCK); 180 let power_irq = interrupt::take!(POWER_CLOCK);
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index fe27e76fb..1e98dd1ae 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -13,7 +13,7 @@ use embassy_nrf::usb::Driver;
13use embassy_nrf::Peripherals; 13use embassy_nrf::Peripherals;
14use embassy_usb::control::OutResponse; 14use embassy_usb::control::OutResponse;
15use embassy_usb::{Config, UsbDeviceBuilder}; 15use embassy_usb::{Config, UsbDeviceBuilder};
16use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; 16use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
17use futures::future::join; 17use futures::future::join;
18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
19 19
@@ -52,7 +52,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
52 let mut control_buf = [0; 16]; 52 let mut control_buf = [0; 16];
53 let request_handler = MyRequestHandler {}; 53 let request_handler = MyRequestHandler {};
54 54
55 let mut control = State::<5, 0>::new(); 55 let mut state = State::new();
56 56
57 let mut builder = UsbDeviceBuilder::new( 57 let mut builder = UsbDeviceBuilder::new(
58 driver, 58 driver,
@@ -65,14 +65,14 @@ async fn main(_spawner: Spawner, p: Peripherals) {
65 ); 65 );
66 66
67 // Create classes on the builder. 67 // Create classes on the builder.
68 let mut hid = HidClass::new( 68 let config = embassy_usb_hid::Config {
69 &mut builder, 69 report_descriptor: MouseReport::desc(),
70 &mut control, 70 request_handler: Some(&request_handler),
71 MouseReport::desc(), 71 poll_ms: 60,
72 Some(&request_handler), 72 max_packet_size: 8,
73 60, 73 };
74 8, 74
75 ); 75 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
76 76
77 // Build the builder. 77 // Build the builder.
78 let mut usb = builder.build(); 78 let mut usb = builder.build();
@@ -94,7 +94,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
94 wheel: 0, 94 wheel: 0,
95 pan: 0, 95 pan: 0,
96 }; 96 };
97 match hid.input().serialize(&report).await { 97 match writer.write_serialize(&report).await {
98 Ok(()) => {} 98 Ok(()) => {}
99 Err(e) => warn!("Failed to send report: {:?}", e), 99 Err(e) => warn!("Failed to send report: {:?}", e),
100 } 100 }