1use crate::descriptor::{DescriptorType, HidProtocol, HidRequest};
4use crate::device::{DeviceClass, DeviceHList};
5use crate::interface::{InterfaceClass, ReportDescriptor, UsbAllocatable};
6use crate::UsbHidError;
7use core::cell::RefCell;
8use core::default::Default;
9use core::marker::PhantomData;
10use frunk::hlist::{HList, Selector};
11use frunk::{HCons, HNil, ToMut};
12#[allow(clippy::wildcard_imports)]
13use usb_device::class_prelude::*;
14use usb_device::control::{Recipient, Request};
15use usb_device::descriptor::lang_id::LangID;
16use usb_device::{control::RequestType, Result};
17
18pub mod prelude {
19 pub use crate::descriptor::{HidProtocol, InterfaceProtocol};
30 pub use crate::device::DeviceClass;
31 pub use crate::interface::{
32 InBytes16, InBytes32, InBytes64, InBytes8, InNone, Interface, InterfaceBuilder,
33 InterfaceConfig, OutBytes16, OutBytes32, OutBytes64, OutBytes8, OutNone, ReportSingle,
34 Reports128, Reports16, Reports32, Reports64, Reports8, UsbAllocatable,
35 };
36 pub use crate::interface::{ManagedIdleInterface, ManagedIdleInterfaceConfig};
37 pub use crate::usb_class::{UsbHidClass, UsbHidClassBuilder};
38 pub use crate::UsbHidError;
39}
40
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum UsbHidBuilderError {
45 ValueOverflow,
47 SliceLengthOverflow,
49}
50
51#[must_use = "this `UsbHidClassBuilder` must be assigned or consumed by `::build()`"]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54#[derive(Debug, Clone, Copy, Eq, PartialEq)]
55pub struct UsbHidClassBuilder<'a, B, Devices> {
56 devices: Devices,
57 marker: PhantomData<&'a B>,
58}
59
60impl<B> UsbHidClassBuilder<'_, B, HNil> {
61 pub fn new() -> Self {
62 Self {
63 devices: HNil,
64 marker: PhantomData,
65 }
66 }
67}
68
69impl<B> Default for UsbHidClassBuilder<'_, B, HNil> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<'a, B: UsbBus, Tail: HList> UsbHidClassBuilder<'a, B, Tail> {
76 pub fn add_device<Config, Device>(
77 self,
78 config: Config,
79 ) -> UsbHidClassBuilder<'a, B, HCons<Config, Tail>>
80 where
81 Config: UsbAllocatable<'a, B, Allocated = Device>,
82 Device: DeviceClass<'a>,
83 {
84 UsbHidClassBuilder {
85 devices: self.devices.prepend(config),
86 marker: PhantomData,
87 }
88 }
89}
90
91impl<'a, B, Config, Tail> UsbHidClassBuilder<'a, B, HCons<Config, Tail>>
92where
93 B: UsbBus,
94 Tail: UsbAllocatable<'a, B>,
95 Config: UsbAllocatable<'a, B>,
96{
97 pub fn build(
98 self,
99 usb_alloc: &'a UsbBusAllocator<B>,
100 ) -> UsbHidClass<'a, B, HCons<Config::Allocated, Tail::Allocated>> {
101 UsbHidClass {
102 devices: RefCell::new(self.devices.allocate(usb_alloc)),
103 _marker: PhantomData,
104 }
105 }
106}
107
108pub type BuilderResult<B> = core::result::Result<B, UsbHidBuilderError>;
109
110pub struct UsbHidClass<'a, B, Devices> {
112 devices: RefCell<Devices>,
116 _marker: PhantomData<&'a B>,
117}
118
119impl<'a, B, Devices: DeviceHList<'a>> UsbHidClass<'a, B, Devices> {
120 pub fn device<T, Index>(&mut self) -> &mut T
122 where
123 Devices: Selector<T, Index>,
124 {
125 self.devices.get_mut().get_mut()
126 }
127
128 pub fn devices(&'a mut self) -> <Devices as ToMut<'a>>::Output {
130 self.devices.get_mut().to_mut()
131 }
132
133 pub fn tick(&mut self) -> core::result::Result<(), UsbHidError> {
135 self.devices.get_mut().tick()
136 }
137}
138
139impl<'a, B: UsbBus + 'a, Devices> UsbHidClass<'a, B, Devices> {
140 fn get_descriptor(transfer: ControlIn<B>, interface: &mut dyn InterfaceClass<'a>) {
141 let request: &Request = transfer.request();
142 match DescriptorType::try_from((request.value >> 8) as u8) {
143 Ok(DescriptorType::Report) => {
144 let result = match interface.report_descriptor() {
145 ReportDescriptor::DynamicDescriptor(desc) => transfer.accept_with(desc),
146 ReportDescriptor::StaticDescriptor(desc) => transfer.accept_with_static(desc),
147 };
148
149 match result {
150 Err(e) => error!("Failed to send report descriptor - {:?}", e),
151 Ok(()) => {
152 trace!("Sent report descriptor");
153 }
154 }
155 }
156 Ok(DescriptorType::Hid) => {
157 let transfer_result = transfer.accept(|buffer| {
158 if buffer.len() < 9 {
159 return Err(UsbError::BufferOverflow);
160 }
161
162 buffer[0] = 9;
163 buffer[1] = u8::from(DescriptorType::Hid);
164 (buffer[2..9]).copy_from_slice(&interface.hid_descriptor_body());
165 Ok(9)
166 });
167 match transfer_result {
168 Err(e) => {
169 error!("Failed to send Hid descriptor - {:?}", e);
170 }
171 Ok(()) => {
172 trace!("Sent hid descriptor");
173 }
174 }
175 }
176 _ => {
177 warn!(
178 "Unsupported descriptor type, request type:{:?}, request:{}, value:{}",
179 request.request_type, request.request, request.value
180 );
181 }
182 }
183 }
184}
185
186impl<'a, B, Devices> UsbClass<B> for UsbHidClass<'a, B, Devices>
187where
188 B: UsbBus + 'a,
189 Devices: DeviceHList<'a>,
190{
191 fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
192 self.devices.borrow_mut().write_descriptors(writer)?;
193 info!("wrote class config descriptor");
194 Ok(())
195 }
196
197 fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> {
198 self.devices.borrow_mut().get_string(index, lang_id)
199 }
200
201 fn reset(&mut self) {
202 info!("Reset");
203 self.devices.get_mut().reset();
204 }
205
206 fn control_out(&mut self, transfer: ControlOut<B>) {
207 let request: &Request = transfer.request();
208
209 if !(request.request_type == RequestType::Class
211 && request.recipient == Recipient::Interface)
212 {
213 return;
214 }
215
216 let Some(interface) = u8::try_from(request.index)
217 .ok()
218 .and_then(|id| self.devices.get_mut().get(id))
219 else {
220 return;
221 };
222
223 trace!(
224 "ctrl_out: request type: {:?}, request: {}, value: {}",
225 request.request_type,
226 request.request,
227 request.value
228 );
229
230 match HidRequest::try_from(request.request) {
231 Ok(HidRequest::SetReport) => {
232 interface.set_report(transfer.data()).ok();
233 transfer.accept().ok();
234 }
235 Ok(HidRequest::SetIdle) => {
236 if request.length != 0 {
237 warn!(
238 "Expected SetIdle to have length 0, received {}",
239 request.length
240 );
241 }
242
243 interface.set_idle((request.value & 0xFF) as u8, (request.value >> 8) as u8);
244 transfer.accept().ok();
245 }
246 Ok(HidRequest::SetProtocol) => {
247 if request.length != 0 {
248 warn!(
249 "Expected SetProtocol to have length 0, received {}",
250 request.length
251 );
252 }
253 if let Ok(protocol) = HidProtocol::try_from((request.value & 0xFF) as u8) {
254 interface.set_protocol(protocol);
255 transfer.accept().ok();
256 } else {
257 error!(
258 "Unable to set protocol, unsupported value:{}",
259 request.value
260 );
261 }
262 }
263 _ => {
264 warn!(
265 "Unsupported control_out request type: {:?}, request: {}, value: {}",
266 request.request_type, request.request, request.value
267 );
268 }
269 }
270 }
271
272 fn control_in(&mut self, transfer: ControlIn<B>) {
273 let request: &Request = transfer.request();
274 if !(request.recipient == Recipient::Interface) {
276 return;
277 }
278
279 let Ok(interface_id) = u8::try_from(request.index) else {
280 return;
281 };
282
283 trace!(
284 "ctrl_in: request type: {:?}, request: {}, value: {}",
285 request.request_type,
286 request.request,
287 request.value
288 );
289
290 match request.request_type {
291 RequestType::Standard => {
292 if let Some(interface) = self.devices.get_mut().get(interface_id) {
293 if request.request == Request::GET_DESCRIPTOR {
294 info!("Get descriptor");
295 Self::get_descriptor(transfer, interface);
296 }
297 }
298 }
299
300 RequestType::Class => {
301 let Some(interface) = self.devices.get_mut().get(interface_id) else {
302 return;
303 };
304
305 match HidRequest::try_from(request.request) {
306 Ok(HidRequest::GetReport) => {
307 let requested_n = transfer.request().length.into();
308 if let Err(e) = transfer.accept(|buffer| {
309 interface.get_report(buffer).inspect(|&n| {
310 if n != requested_n {
311 warn!(
312 "GetReport requested {} bytes, got {} bytes",
313 requested_n, n
314 );
315 }
316 })
317 }) {
318 error!("Failed to send report - {:?}", e);
319 } else {
320 trace!("Sent report");
321 unwrap!(interface.get_report_ack());
322 }
323 }
324 Ok(HidRequest::GetIdle) => {
325 if request.length != 1 {
326 warn!(
327 "Expected GetIdle to have length 1, received {}",
328 request.length
329 );
330 }
331
332 let report_id = (request.value & 0xFF) as u8;
333 let idle = interface.get_idle(report_id);
334 if let Err(e) = transfer.accept(|buffer| {
335 if buffer.is_empty() {
336 return Err(UsbError::BufferOverflow);
337 }
338 buffer[0] = idle;
339 Ok(1)
340 }) {
341 error!("Failed to send idle data - {:?}", e);
342 } else {
343 info!("Get Idle for ID{}: {}", report_id, idle);
344 }
345 }
346 Ok(HidRequest::GetProtocol) => {
347 if request.length != 1 {
348 warn!(
349 "Expected GetProtocol to have length 1, received {}",
350 request.length
351 );
352 }
353
354 let protocol = interface.get_protocol();
355 if let Err(e) = transfer.accept(|buffer| {
356 if buffer.is_empty() {
357 return Err(UsbError::BufferOverflow);
358 }
359 buffer[0] = protocol.into();
360 Ok(1)
361 }) {
362 error!("Failed to send protocol data - {:?}", e);
363 } else {
364 info!("Get protocol: {:?}", protocol);
365 }
366 }
367 _ => {
368 warn!(
369 "Unsupported control_in request type: {:?}, request: {}, value: {}",
370 request.request_type, request.request, request.value
371 );
372 }
373 }
374 }
375 _ => {}
376 }
377 }
378}
379
380#[cfg(test)]
381mod test {
382 #![allow(clippy::unwrap_used)]
383 #![allow(clippy::expect_used)]
384
385 use std::cell::RefCell;
386 use std::sync::Mutex;
387 use std::vec::Vec;
388
389 use crate::descriptor::USB_CLASS_HID;
390 use crate::interface::{InBytes64, InterfaceBuilder, OutBytes64, ReportSingle, Reports8};
391 use env_logger::Env;
392 use fugit::MillisDurationU32;
393 use log::SetLoggerError;
394 use packed_struct::prelude::*;
395 use usb_device::bus::PollResult;
396 use usb_device::prelude::*;
397 use usb_device::UsbDirection;
398
399 use super::*;
400
401 fn init_logging() {
402 let _: core::result::Result<(), SetLoggerError> =
403 env_logger::Builder::from_env(Env::default().default_filter_or("trace"))
404 .is_test(true)
405 .try_init();
406 }
407
408 #[derive(Default)]
409 struct UsbTestManager {
410 in_buf: Mutex<RefCell<Vec<u8>>>,
411 setup_buf: Mutex<RefCell<Vec<u8>>>,
412 }
413
414 impl UsbTestManager {
415 fn host_write_setup(&self, data: &[u8]) -> Result<()> {
416 let buf = self.setup_buf.lock().unwrap();
417 if buf.borrow().is_empty() {
418 buf.borrow_mut().extend_from_slice(data);
419 Ok(())
420 } else {
421 Err(UsbError::WouldBlock)
422 }
423 }
424
425 fn host_read_in(&self) -> Vec<u8> {
426 self.in_buf.lock().unwrap().take()
427 }
428
429 fn has_setup_data(&self) -> bool {
430 !self.setup_buf.lock().unwrap().borrow().is_empty()
431 }
432
433 fn device_read_setup(&self, data: &mut [u8]) -> Result<usize> {
434 let buf = self.setup_buf.lock().unwrap();
435 if buf.borrow().is_empty() {
436 Err(UsbError::WouldBlock)
437 } else {
438 let tmp = buf.take();
439 data[..tmp.len()].copy_from_slice(&tmp);
440 Ok(tmp.len())
441 }
442 }
443
444 fn device_write(&self, data: &[u8]) -> Result<usize> {
445 let buf = self.in_buf.lock().unwrap();
446 if buf.borrow().is_empty() {
447 buf.borrow_mut().extend_from_slice(data);
448 Ok(data.len())
449 } else {
450 Err(UsbError::WouldBlock)
451 }
452 }
453 }
454
455 struct TestUsbBus<'a> {
456 next_ep_index: usize,
457 manager: &'a UsbTestManager,
458 }
459
460 impl<'a> TestUsbBus<'a> {
461 fn new(manager: &'a UsbTestManager) -> Self {
462 TestUsbBus {
463 next_ep_index: 0,
464 manager,
465 }
466 }
467 }
468
469 impl UsbBus for TestUsbBus<'_> {
470 fn alloc_ep(
471 &mut self,
472 ep_dir: UsbDirection,
473 _ep_addr: Option<EndpointAddress>,
474 _ep_type: EndpointType,
475 _max_packet_size: u16,
476 _interval: u8,
477 ) -> Result<EndpointAddress> {
478 let ep = EndpointAddress::from_parts(self.next_ep_index, ep_dir);
479 self.next_ep_index += 1;
480 Ok(ep)
481 }
482
483 fn enable(&mut self) {}
484 fn reset(&self) {
485 todo!()
486 }
487 fn set_device_address(&self, _addr: u8) {
488 todo!()
489 }
490 fn write(&self, _ep_addr: EndpointAddress, buf: &[u8]) -> Result<usize> {
491 self.manager.device_write(buf)
492 }
493 fn read(&self, _ep_addr: EndpointAddress, buf: &mut [u8]) -> Result<usize> {
494 self.manager.device_read_setup(buf)
495 }
496 fn set_stalled(&self, _ep_addr: EndpointAddress, _stalled: bool) {}
497 fn is_stalled(&self, _ep_addr: EndpointAddress) -> bool {
498 todo!()
499 }
500 fn suspend(&self) {
501 todo!()
502 }
503 fn resume(&self) {
504 todo!()
505 }
506 fn poll(&self) -> PollResult {
507 PollResult::Data {
508 ep_out: 0,
509 ep_in_complete: 1,
510 ep_setup: u16::from(self.manager.has_setup_data()),
511 }
512 }
513 }
514
515 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
516 #[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct)]
517 #[packed_struct(endian = "lsb", bit_numbering = "msb0", size_bytes = "8")]
518 struct UsbRequest {
519 #[packed_field(bits = "0")]
520 direction: bool,
521 #[packed_field(bits = "1:2")]
522 request_type: u8,
523 #[packed_field(bits = "4:7")]
524 recipient: u8,
525 request: u8,
526 value: u16,
527 index: u16,
528 length: u16,
529 }
530
531 #[test]
532 fn descriptor_ordering_satisfies_boot_spec() {
533 init_logging();
534
535 let manager = UsbTestManager::default();
536
537 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
538
539 let mut hid = UsbHidClassBuilder::new()
540 .add_device(
541 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
542 .unwrap()
543 .build(),
544 )
545 .build(&usb_alloc);
546
547 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
548 .device_class(USB_CLASS_HID)
549 .build();
550
551 manager
553 .host_write_setup(
554 &UsbRequest {
555 direction: UsbDirection::In != UsbDirection::Out,
556 request_type: RequestType::Standard as u8,
557 recipient: Recipient::Device as u8,
558 request: Request::GET_DESCRIPTOR,
559 value: u16::from(usb_device::descriptor::descriptor_type::CONFIGURATION) << 8,
560 index: 0,
561 length: 0xFFFF,
562 }
563 .pack()
564 .unwrap(),
565 )
566 .unwrap();
567
568 assert!(usb_dev.poll(&mut [&mut hid]));
569
570 let mut data = Vec::new();
572
573 loop {
574 let read = manager.host_read_in();
575 if read.is_empty() {
576 break;
577 }
578 data.extend_from_slice(&read);
579 assert!(usb_dev.poll(&mut [&mut hid]));
580 }
581
582 let mut it = data.iter();
592
593 let len = *it.next().unwrap();
594 assert_eq!(
595 *(it.next().unwrap()),
596 0x02,
597 "Expected Configuration descriptor"
598 );
599 for _ in 0..(len - 2) {
600 it.next().unwrap();
601 }
602
603 let len = it.next().unwrap();
604 assert_eq!(*it.next().unwrap(), 0x04, "Expected Interface descriptor");
605 for _ in 0..(len - 2) {
606 it.next().unwrap();
607 }
608
609 let len = it.next().unwrap();
610 assert_eq!(*(it.next().unwrap()), 0x21, "Expected Hid descriptor");
611 for _ in 0..(len - 2) {
612 it.next().unwrap();
613 }
614
615 while let Some(&len) = it.next() {
616 assert_eq!(*(it.next().unwrap()), 0x05, "Expected Endpoint descriptor");
617
618 for _ in 0..(len - 2) {
619 it.next().unwrap();
620 }
621 }
622
623 assert!(it.next().is_none());
625 }
626
627 #[test]
628 fn get_protocol_default_to_report() {
629 init_logging();
630
631 let manager = UsbTestManager::default();
632 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
633
634 let mut hid = UsbHidClassBuilder::new()
635 .add_device(
636 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
637 .unwrap()
638 .build(),
639 )
640 .build(&usb_alloc);
641
642 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
643 .device_class(USB_CLASS_HID)
644 .build();
645
646 manager
648 .host_write_setup(
649 &UsbRequest {
650 direction: UsbDirection::In != UsbDirection::Out,
651 request_type: RequestType::Class as u8,
652 recipient: Recipient::Interface as u8,
653 request: HidRequest::GetProtocol.into(),
654 value: 0x0,
655 index: 0x0,
656 length: 0x1,
657 }
658 .pack()
659 .unwrap(),
660 )
661 .unwrap();
662
663 assert!(usb_dev.poll(&mut [&mut hid]));
664
665 let data = manager.host_read_in();
667 assert_eq!(
668 data,
669 [HidProtocol::Report.into()],
670 "Expected protocol to be Report by default"
671 );
672 }
673
674 #[test]
675 fn set_protocol() {
676 init_logging();
677
678 let manager = UsbTestManager::default();
679
680 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
681
682 let mut hid = UsbHidClassBuilder::new()
683 .add_device(
684 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
685 .unwrap()
686 .build(),
687 )
688 .build(&usb_alloc);
689
690 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
691 .device_class(USB_CLASS_HID)
692 .build();
693
694 manager
696 .host_write_setup(
697 &UsbRequest {
698 direction: UsbDirection::In != UsbDirection::In,
699 request_type: RequestType::Class as u8,
700 recipient: Recipient::Interface as u8,
701 request: HidRequest::SetProtocol.into(),
702 value: HidProtocol::Boot as u16,
703 index: 0x0,
704 length: 0x0,
705 }
706 .pack()
707 .unwrap(),
708 )
709 .unwrap();
710
711 assert!(usb_dev.poll(&mut [&mut hid]));
712
713 manager
715 .host_write_setup(
716 &UsbRequest {
717 direction: UsbDirection::In != UsbDirection::Out,
718 request_type: RequestType::Class as u8,
719 recipient: Recipient::Interface as u8,
720 request: HidRequest::GetProtocol.into(),
721 value: 0x0,
722 index: 0x0,
723 length: 0x1,
724 }
725 .pack()
726 .unwrap(),
727 )
728 .unwrap();
729
730 assert!(usb_dev.poll(&mut [&mut hid]));
731
732 let data = &manager.host_read_in();
734 assert_eq!(
735 data,
736 &[HidProtocol::Boot.into()],
737 "Expected protocol to be Boot"
738 );
739 }
740
741 #[test]
742 fn get_protocol_default_post_reset() {
743 init_logging();
744
745 let manager = UsbTestManager::default();
746
747 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
748
749 let mut hid = UsbHidClassBuilder::new()
750 .add_device(
751 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
752 .unwrap()
753 .build(),
754 )
755 .build(&usb_alloc);
756
757 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
758 .device_class(USB_CLASS_HID)
759 .build();
760
761 manager
763 .host_write_setup(
764 &UsbRequest {
765 direction: UsbDirection::In != UsbDirection::In,
766 request_type: RequestType::Class as u8,
767 recipient: Recipient::Interface as u8,
768 request: HidRequest::SetProtocol.into(),
769 value: HidProtocol::Boot as u16,
770 index: 0x0,
771 length: 0x0,
772 }
773 .pack()
774 .unwrap(),
775 )
776 .unwrap();
777
778 assert!(usb_dev.poll(&mut [&mut hid]));
779
780 hid.reset();
782
783 manager
785 .host_write_setup(
786 &UsbRequest {
787 direction: UsbDirection::In != UsbDirection::Out,
788 request_type: RequestType::Class as u8,
789 recipient: Recipient::Interface as u8,
790 request: HidRequest::GetProtocol.into(),
791 value: 0x0,
792 index: 0x0,
793 length: 0x1,
794 }
795 .pack()
796 .unwrap(),
797 )
798 .unwrap();
799
800 assert!(usb_dev.poll(&mut [&mut hid]));
801
802 let data = &manager.host_read_in();
804 assert_eq!(
805 data,
806 &[HidProtocol::Report.into()],
807 "Expected protocol to be Report post reset"
808 );
809 }
810
811 #[test]
812 fn get_global_idle_default() {
813 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
814
815 init_logging();
816
817 let manager = UsbTestManager::default();
818
819 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
820
821 let mut hid = UsbHidClassBuilder::new()
822 .add_device(
823 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
824 .unwrap()
825 .idle_default(IDLE_DEFAULT)
826 .unwrap()
827 .build(),
828 )
829 .build(&usb_alloc);
830
831 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
832 .device_class(USB_CLASS_HID)
833 .build();
834
835 manager
837 .host_write_setup(
838 &UsbRequest {
839 direction: UsbDirection::In != UsbDirection::Out,
840 request_type: RequestType::Class as u8,
841 recipient: Recipient::Interface as u8,
842 request: HidRequest::GetIdle.into(),
843 value: 0x0,
844 index: 0x0,
845 length: 0x1,
846 }
847 .pack()
848 .unwrap(),
849 )
850 .unwrap();
851
852 assert!(usb_dev.poll(&mut [&mut hid]));
853
854 let data = manager.host_read_in();
856 assert_eq!(
857 data,
858 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
859 "Unexpected idle value"
860 );
861 }
862
863 #[test]
864 fn set_global_idle() {
865 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
866 const IDLE_NEW: MillisDurationU32 = MillisDurationU32::millis(88);
867
868 init_logging();
869
870 let manager = UsbTestManager::default();
871
872 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
873
874 let mut hid = UsbHidClassBuilder::new()
875 .add_device(
876 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
877 .unwrap()
878 .idle_default(IDLE_DEFAULT)
879 .unwrap()
880 .build(),
881 )
882 .build(&usb_alloc);
883
884 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
885 .device_class(USB_CLASS_HID)
886 .build();
887
888 manager
890 .host_write_setup(
891 &UsbRequest {
892 direction: UsbDirection::In != UsbDirection::In,
893 request_type: RequestType::Class as u8,
894 recipient: Recipient::Interface as u8,
895 request: HidRequest::SetIdle.into(),
896 value: (u16::try_from(IDLE_NEW.to_millis()).unwrap() / 4) << 8,
897 index: 0x0,
898 length: 0x0,
899 }
900 .pack()
901 .unwrap(),
902 )
903 .unwrap();
904
905 assert!(usb_dev.poll(&mut [&mut hid]));
906
907 manager
909 .host_write_setup(
910 &UsbRequest {
911 direction: UsbDirection::In != UsbDirection::Out,
912 request_type: RequestType::Class as u8,
913 recipient: Recipient::Interface as u8,
914 request: HidRequest::GetIdle.into(),
915 value: 0x0,
916 index: 0x0,
917 length: 0x1,
918 }
919 .pack()
920 .unwrap(),
921 )
922 .unwrap();
923
924 assert!(usb_dev.poll(&mut [&mut hid]));
925
926 let data = manager.host_read_in();
928 assert_eq!(
929 data,
930 [u8::try_from(IDLE_NEW.ticks()).unwrap() / 4],
931 "Unexpected idle value"
932 );
933 }
934
935 #[test]
936 fn get_global_idle_default_post_reset() {
937 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
938 const IDLE_NEW: MillisDurationU32 = MillisDurationU32::millis(88);
939
940 init_logging();
941
942 let manager = UsbTestManager::default();
943
944 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
945
946 let mut hid = UsbHidClassBuilder::new()
947 .add_device(
948 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
949 .unwrap()
950 .idle_default(IDLE_DEFAULT)
951 .unwrap()
952 .build(),
953 )
954 .build(&usb_alloc);
955
956 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
957 .device_class(USB_CLASS_HID)
958 .build();
959
960 manager
962 .host_write_setup(
963 &UsbRequest {
964 direction: UsbDirection::In != UsbDirection::In,
965 request_type: RequestType::Class as u8,
966 recipient: Recipient::Interface as u8,
967 request: HidRequest::SetIdle.into(),
968 value: (u16::try_from(IDLE_NEW.to_millis()).unwrap() / 4) << 8,
969 index: 0x0,
970 length: 0x0,
971 }
972 .pack()
973 .unwrap(),
974 )
975 .unwrap();
976
977 assert!(usb_dev.poll(&mut [&mut hid]));
978
979 hid.reset();
980
981 manager
983 .host_write_setup(
984 &UsbRequest {
985 direction: UsbDirection::In != UsbDirection::Out,
986 request_type: RequestType::Class as u8,
987 recipient: Recipient::Interface as u8,
988 request: HidRequest::GetIdle.into(),
989 value: 0x0,
990 index: 0x0,
991 length: 0x1,
992 }
993 .pack()
994 .unwrap(),
995 )
996 .unwrap();
997
998 assert!(usb_dev.poll(&mut [&mut hid]));
999
1000 let data = manager.host_read_in();
1002 assert_eq!(
1003 data,
1004 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1005 "Unexpected idle value"
1006 );
1007 }
1008
1009 #[test]
1010 fn get_report_idle_default() {
1011 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
1012 const REPORT_ID: u8 = 0xAB;
1013
1014 init_logging();
1015
1016 let manager = UsbTestManager::default();
1017
1018 let usb_bus = TestUsbBus::new(&manager);
1019
1020 let usb_alloc = UsbBusAllocator::new(usb_bus);
1021
1022 let mut hid = UsbHidClassBuilder::new()
1023 .add_device(
1024 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
1025 .unwrap()
1026 .idle_default(IDLE_DEFAULT)
1027 .unwrap()
1028 .build(),
1029 )
1030 .build(&usb_alloc);
1031
1032 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
1033 .device_class(USB_CLASS_HID)
1034 .build();
1035
1036 manager
1038 .host_write_setup(
1039 &UsbRequest {
1040 direction: UsbDirection::In != UsbDirection::Out,
1041 request_type: RequestType::Class as u8,
1042 recipient: Recipient::Interface as u8,
1043 request: HidRequest::GetIdle.into(),
1044 value: u16::from(REPORT_ID),
1045 index: 0x0,
1046 length: 0x1,
1047 }
1048 .pack()
1049 .unwrap(),
1050 )
1051 .unwrap();
1052
1053 assert!(usb_dev.poll(&mut [&mut hid]));
1054
1055 let data = manager.host_read_in();
1057 assert_eq!(
1058 data,
1059 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1060 "Unexpected idle value"
1061 );
1062 }
1063
1064 #[test]
1065 fn set_report_idle() {
1066 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
1067 const IDLE_NEW: MillisDurationU32 = MillisDurationU32::millis(88);
1068 const REPORT_ID: u8 = 0x4;
1069
1070 init_logging();
1071
1072 let manager = UsbTestManager::default();
1073
1074 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
1075
1076 let mut hid = UsbHidClassBuilder::new()
1077 .add_device(
1078 InterfaceBuilder::<InBytes64, OutBytes64, Reports8>::new(&[])
1079 .unwrap()
1080 .idle_default(IDLE_DEFAULT)
1081 .unwrap()
1082 .build(),
1083 )
1084 .build(&usb_alloc);
1085
1086 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
1087 .device_class(USB_CLASS_HID)
1088 .build();
1089
1090 manager
1092 .host_write_setup(
1093 &UsbRequest {
1094 direction: UsbDirection::In != UsbDirection::In,
1095 request_type: RequestType::Class as u8,
1096 recipient: Recipient::Interface as u8,
1097 request: HidRequest::SetIdle.into(),
1098 value: ((u16::try_from(IDLE_NEW.to_millis()).unwrap() / 4) << 8)
1099 | u16::from(REPORT_ID),
1100 index: 0x0,
1101 length: 0x0,
1102 }
1103 .pack()
1104 .unwrap(),
1105 )
1106 .unwrap();
1107
1108 assert!(usb_dev.poll(&mut [&mut hid]));
1109
1110 manager
1112 .host_write_setup(
1113 &UsbRequest {
1114 direction: UsbDirection::In != UsbDirection::Out,
1115 request_type: RequestType::Class as u8,
1116 recipient: Recipient::Interface as u8,
1117 request: HidRequest::GetIdle.into(),
1118 value: u16::from(REPORT_ID),
1119 index: 0x0,
1120 length: 0x1,
1121 }
1122 .pack()
1123 .unwrap(),
1124 )
1125 .unwrap();
1126
1127 assert!(usb_dev.poll(&mut [&mut hid]));
1128
1129 let data = manager.host_read_in();
1131 assert_eq!(
1132 data,
1133 [u8::try_from(IDLE_NEW.ticks()).unwrap() / 4],
1134 "Unexpected report idle value"
1135 );
1136
1137 manager
1139 .host_write_setup(
1140 &UsbRequest {
1141 direction: UsbDirection::In != UsbDirection::Out,
1142 request_type: RequestType::Class as u8,
1143 recipient: Recipient::Interface as u8,
1144 request: HidRequest::GetIdle.into(),
1145 value: 0x0,
1146 index: 0x0,
1147 length: 0x1,
1148 }
1149 .pack()
1150 .unwrap(),
1151 )
1152 .unwrap();
1153
1154 assert!(usb_dev.poll(&mut [&mut hid]));
1155
1156 let data = manager.host_read_in();
1158 assert_eq!(
1159 data,
1160 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1161 "Unexpected global idle value"
1162 );
1163 }
1164
1165 #[test]
1166 fn set_report_idle_no_reports() {
1167 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
1168 const IDLE_NEW: MillisDurationU32 = MillisDurationU32::millis(88);
1169 const REPORT_ID: u16 = 0x4;
1170
1171 init_logging();
1172
1173 let manager = UsbTestManager::default();
1174
1175 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
1176
1177 let mut hid = UsbHidClassBuilder::new()
1178 .add_device(
1179 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
1180 .unwrap()
1181 .idle_default(IDLE_DEFAULT)
1182 .unwrap()
1183 .build(),
1184 )
1185 .build(&usb_alloc);
1186
1187 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
1188 .device_class(USB_CLASS_HID)
1189 .build();
1190
1191 manager
1193 .host_write_setup(
1194 &UsbRequest {
1195 direction: UsbDirection::In != UsbDirection::In,
1196 request_type: RequestType::Class as u8,
1197 recipient: Recipient::Interface as u8,
1198 request: HidRequest::SetIdle as u8,
1199 value: ((u16::try_from(IDLE_NEW.to_millis()).unwrap() / 4) << 8) | REPORT_ID,
1200 index: 0x0,
1201 length: 0x0,
1202 }
1203 .pack()
1204 .unwrap(),
1205 )
1206 .unwrap();
1207
1208 assert!(usb_dev.poll(&mut [&mut hid]));
1209
1210 manager
1212 .host_write_setup(
1213 &UsbRequest {
1214 direction: UsbDirection::In != UsbDirection::Out,
1215 request_type: RequestType::Class as u8,
1216 recipient: Recipient::Interface as u8,
1217 request: HidRequest::GetIdle as u8,
1218 value: REPORT_ID,
1219 index: 0x0,
1220 length: 0x1,
1221 }
1222 .pack()
1223 .unwrap(),
1224 )
1225 .unwrap();
1226
1227 assert!(usb_dev.poll(&mut [&mut hid]));
1228
1229 let data = manager.host_read_in();
1231 assert_eq!(
1232 data,
1233 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1234 "Unexpected report idle value"
1235 );
1236
1237 manager
1239 .host_write_setup(
1240 &UsbRequest {
1241 direction: UsbDirection::In != UsbDirection::Out,
1242 request_type: RequestType::Class as u8,
1243 recipient: Recipient::Interface as u8,
1244 request: HidRequest::GetIdle as u8,
1245 value: 0x0,
1246 index: 0x0,
1247 length: 0x1,
1248 }
1249 .pack()
1250 .unwrap(),
1251 )
1252 .unwrap();
1253
1254 assert!(usb_dev.poll(&mut [&mut hid]));
1255
1256 let data = manager.host_read_in();
1258 assert_eq!(
1259 data,
1260 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1261 "Unexpected global idle value"
1262 );
1263 }
1264
1265 #[test]
1266 fn get_report_idle_default_post_reset() {
1267 const REPORT_ID: u8 = 0x4;
1268 const IDLE_DEFAULT: MillisDurationU32 = MillisDurationU32::millis(40);
1269 const IDLE_NEW: MillisDurationU32 = MillisDurationU32::millis(88);
1270
1271 init_logging();
1272
1273 let manager = UsbTestManager::default();
1274
1275 let usb_alloc = UsbBusAllocator::new(TestUsbBus::new(&manager));
1276
1277 let mut hid = UsbHidClassBuilder::new()
1278 .add_device(
1279 InterfaceBuilder::<InBytes64, OutBytes64, ReportSingle>::new(&[])
1280 .unwrap()
1281 .idle_default(IDLE_DEFAULT)
1282 .unwrap()
1283 .build(),
1284 )
1285 .build(&usb_alloc);
1286
1287 let mut usb_dev = UsbDeviceBuilder::new(&usb_alloc, UsbVidPid(0x1209, 0x0001))
1288 .device_class(USB_CLASS_HID)
1289 .build();
1290
1291 manager
1293 .host_write_setup(
1294 &UsbRequest {
1295 direction: UsbDirection::In != UsbDirection::In,
1296 request_type: RequestType::Class as u8,
1297 recipient: Recipient::Interface as u8,
1298 request: HidRequest::SetIdle.into(),
1299 value: ((u16::try_from(IDLE_NEW.to_millis()).unwrap() / 4) << 8)
1300 | u16::from(REPORT_ID),
1301 index: 0x0,
1302 length: 0x0,
1303 }
1304 .pack()
1305 .unwrap(),
1306 )
1307 .unwrap();
1308
1309 assert!(usb_dev.poll(&mut [&mut hid]));
1310
1311 hid.reset();
1312
1313 manager
1315 .host_write_setup(
1316 &UsbRequest {
1317 direction: UsbDirection::In != UsbDirection::Out,
1318 request_type: RequestType::Class as u8,
1319 recipient: Recipient::Interface as u8,
1320 request: HidRequest::GetIdle.into(),
1321 value: u16::from(REPORT_ID),
1322 index: 0x0,
1323 length: 0x1,
1324 }
1325 .pack()
1326 .unwrap(),
1327 )
1328 .unwrap();
1329
1330 assert!(usb_dev.poll(&mut [&mut hid]));
1331
1332 let data = manager.host_read_in();
1334 assert_eq!(
1335 data,
1336 [u8::try_from(IDLE_DEFAULT.ticks()).unwrap() / 4],
1337 "Unexpected report idle value"
1338 );
1339 }
1340}