diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-04-16 01:55:21 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-04-16 01:55:21 +0000 |
| commit | 1c9adec3c59da48f8084c29b4ece083100a703e3 (patch) | |
| tree | 848a28f4a2dfcad860073360c36f0e4ad7a52088 | |
| parent | 3a90a8eb4a5ef61aef034025ac882255c94260dc (diff) | |
| parent | f35bde684acb736fd4d5b709833b8c2a47146fa8 (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.rs | 289 | ||||
| -rw-r--r-- | embassy-usb/src/control.rs | 4 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_keyboard.rs | 27 | ||||
| -rw-r--r-- | examples/nrf/src/bin/usb_hid_mouse.rs | 22 |
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; | |||
| 41 | const HID_REQ_GET_PROTOCOL: u8 = 0x03; | 41 | const HID_REQ_GET_PROTOCOL: u8 = 0x03; |
| 42 | const HID_REQ_SET_PROTOCOL: u8 = 0x0b; | 42 | const HID_REQ_SET_PROTOCOL: u8 = 0x0b; |
| 43 | 43 | ||
| 44 | pub 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))] |
| 46 | pub enum ReportId { | 64 | pub enum ReportId { |
| @@ -60,12 +78,12 @@ impl ReportId { | |||
| 60 | } | 78 | } |
| 61 | } | 79 | } |
| 62 | 80 | ||
| 63 | pub struct State<'a, const IN_N: usize, const OUT_N: usize> { | 81 | pub 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 | ||
| 68 | impl<'a, const IN_N: usize, const OUT_N: usize> State<'a, IN_N, OUT_N> { | 86 | impl<'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 | ||
| 77 | pub struct HidClass<'d, D: Driver<'d>, T, const IN_N: usize> { | 95 | pub 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 | ||
| 82 | impl<'d, D: Driver<'d>, const IN_N: usize> HidClass<'d, D, (), IN_N> { | 100 | fn 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 | ||
| 114 | impl<'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 | ||
| 124 | impl<'d, D: Driver<'d>, const IN_N: usize, const OUT_N: usize> | 155 | impl<'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 | ||
| 173 | pub struct ReportWriter<'d, D: Driver<'d>, const N: usize> { | 212 | pub struct HidWriter<'d, D: Driver<'d>, const N: usize> { |
| 174 | ep_in: D::EndpointIn, | 213 | ep_in: D::EndpointIn, |
| 175 | } | 214 | } |
| 176 | 215 | ||
| 177 | pub struct ReportReader<'d, D: Driver<'d>, const N: usize> { | 216 | pub 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 | ||
| 200 | impl<'d, D: Driver<'d>, const N: usize> ReportWriter<'d, D, N> { | 239 | impl<'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 | ||
| 239 | impl<'d, D: Driver<'d>, const N: usize> ReportReader<'d, D, N> { | 298 | impl<'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 | ||
| 357 | struct Control<'d> { | 413 | struct 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 | ||
| 364 | impl<'a> Control<'a> { | 420 | impl<'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 | ||
| 437 | impl<'d> ControlHandler for Control<'d> { | 452 | impl<'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; | |||
| 18 | use embassy_nrf::Peripherals; | 18 | use embassy_nrf::Peripherals; |
| 19 | use embassy_usb::control::OutResponse; | 19 | use embassy_usb::control::OutResponse; |
| 20 | use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; | 20 | use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; |
| 21 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; | 21 | use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State}; |
| 22 | use futures::future::join; | 22 | use futures::future::join; |
| 23 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 23 | use 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; | |||
| 13 | use embassy_nrf::Peripherals; | 13 | use embassy_nrf::Peripherals; |
| 14 | use embassy_usb::control::OutResponse; | 14 | use embassy_usb::control::OutResponse; |
| 15 | use embassy_usb::{Config, UsbDeviceBuilder}; | 15 | use embassy_usb::{Config, UsbDeviceBuilder}; |
| 16 | use embassy_usb_hid::{HidClass, ReportId, RequestHandler, State}; | 16 | use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State}; |
| 17 | use futures::future::join; | 17 | use futures::future::join; |
| 18 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 18 | use 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 | } |
