1use crate::descriptor::{
3 DescriptorType, HidProtocol, InterfaceProtocol, InterfaceSubClass, COUNTRY_CODE_NOT_SUPPORTED,
4 SPEC_VERSION_1_11, USB_CLASS_HID,
5};
6use crate::device::DeviceClass;
7use crate::private::Sealed;
8use crate::usb_class::{BuilderResult, UsbHidBuilderError};
9use crate::UsbHidError;
10use core::marker::PhantomData;
11use frunk::{HCons, HNil};
12use fugit::{ExtU32, MillisDurationU32};
13use heapless::Vec;
14use option_block::{Block128, Block16, Block32, Block64, Block8};
15use packed_struct::prelude::*;
16use packed_struct::PackedStruct;
17use usb_device::bus::{StringIndex, UsbBus, UsbBusAllocator};
18#[allow(clippy::wildcard_imports)]
19use usb_device::class_prelude::*;
20use usb_device::class_prelude::{DescriptorWriter, InterfaceNumber};
21use usb_device::descriptor::lang_id::LangID;
22use usb_device::UsbError;
23
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[derive(Debug, PackedStruct)]
26#[packed_struct(endian = "lsb", size_bytes = 7)]
27struct HidDescriptorBody {
28 bcd_hid: u16,
29 country_code: u8,
30 num_descriptors: u8,
31 #[packed_field(ty = "enum", size_bytes = "1")]
32 descriptor_type: DescriptorType,
33 descriptor_length: u16,
34}
35
36pub trait UsbAllocatable<'a, B: UsbBus> {
37 type Allocated;
38 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated;
39}
40
41impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for HNil {
42 type Allocated = Self;
43
44 fn allocate(self, _: &'a UsbBusAllocator<B>) -> Self::Allocated {
45 self
46 }
47}
48
49impl<'a, B, C, Tail> UsbAllocatable<'a, B> for HCons<C, Tail>
50where
51 B: UsbBus + 'a,
52 C: UsbAllocatable<'a, B>,
53 Tail: UsbAllocatable<'a, B>,
54{
55 type Allocated = HCons<C::Allocated, Tail::Allocated>;
56
57 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
58 HCons {
59 head: self.head.allocate(usb_alloc),
60 tail: self.tail.allocate(usb_alloc),
61 }
62 }
63}
64
65pub trait InterfaceClass<'a> {
66 fn hid_descriptor_body(&self) -> [u8; 7];
67 fn report_descriptor(&self) -> ReportDescriptor<'_>;
68 fn id(&self) -> InterfaceNumber;
69 fn write_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()>;
70 fn get_string(&self, index: StringIndex, _lang_id: LangID) -> Option<&'a str>;
71 fn reset(&mut self);
72 fn set_report(&mut self, data: &[u8]) -> usb_device::Result<()>;
73 fn get_report(&self, data: &mut [u8]) -> usb_device::Result<usize>;
74 fn get_report_ack(&mut self) -> usb_device::Result<()>;
75 fn set_idle(&mut self, report_id: u8, value: u8);
76 fn get_idle(&self, report_id: u8) -> u8;
77 fn set_protocol(&mut self, protocol: HidProtocol);
78 fn get_protocol(&self) -> HidProtocol;
79}
80
81pub trait ReportBuffer: Default {
82 const CAPACITY: u16;
83 fn clear(&mut self);
84 fn is_empty(&self) -> bool;
85 fn len(&self) -> usize;
86 #[allow(clippy::result_unit_err)]
87 fn extend_from_slice(&mut self, other: &[u8]) -> Result<(), ()>;
88 fn as_ref(&self) -> &[u8];
89}
90
91impl ReportBuffer for () {
92 const CAPACITY: u16 = 0;
93
94 fn clear(&mut self) {}
95
96 fn is_empty(&self) -> bool {
97 true
98 }
99
100 fn len(&self) -> usize {
101 0
102 }
103
104 fn extend_from_slice(&mut self, _other: &[u8]) -> Result<(), ()> {
105 Err(())
106 }
107
108 fn as_ref(&self) -> &[u8] {
109 &[]
110 }
111}
112
113impl<const N: usize> ReportBuffer for Vec<u8, N> {
114 #[allow(clippy::cast_possible_truncation)]
117 const CAPACITY: u16 = N as u16;
118
119 fn clear(&mut self) {
120 self.clear();
121 }
122
123 fn is_empty(&self) -> bool {
124 self.is_empty()
125 }
126
127 fn len(&self) -> usize {
128 <[u8]>::len(self)
129 }
130
131 fn extend_from_slice(&mut self, other: &[u8]) -> Result<(), ()> {
132 self.extend_from_slice(other)
133 }
134
135 fn as_ref(&self) -> &[u8] {
136 self
137 }
138}
139
140pub trait InSize: Sealed {
141 type Buffer: ReportBuffer;
142}
143pub enum InNone {}
144impl Sealed for InNone {}
145impl InSize for InNone {
146 type Buffer = ();
147}
148
149macro_rules! vec_in_bytes {
150 ($name: ident, $capacity: literal) => {
151 pub enum $name {}
152 impl Sealed for $name {}
153 impl InSize for $name {
154 type Buffer = Vec<u8, $capacity>;
155 }
156 };
157}
158
159vec_in_bytes!(InBytes8, 8);
160vec_in_bytes!(InBytes16, 16);
161vec_in_bytes!(InBytes32, 32);
162vec_in_bytes!(InBytes64, 64);
163
164pub trait OutSize: Sealed {
165 type Buffer: ReportBuffer;
166}
167pub enum OutNone {}
168impl Sealed for OutNone {}
169impl OutSize for OutNone {
170 type Buffer = ();
171}
172
173macro_rules! vec_out_bytes {
174 ($name: ident, $capacity: literal) => {
175 pub enum $name {}
176 impl Sealed for $name {}
177 impl OutSize for $name {
178 type Buffer = Vec<u8, $capacity>;
179 }
180 };
181}
182
183vec_out_bytes!(OutBytes8, 8);
184vec_out_bytes!(OutBytes16, 16);
185vec_out_bytes!(OutBytes32, 32);
186vec_out_bytes!(OutBytes64, 64);
187
188pub trait IdleStorage: Default {
189 const CAPACITY: u32;
190 fn insert(&mut self, index: usize, val: u8) -> Option<u8>;
191 fn get(&self, index: usize) -> Option<u8>;
192}
193
194pub trait ReportCount: Sealed {
195 type IdleStorage: IdleStorage;
196}
197
198impl IdleStorage for () {
199 const CAPACITY: u32 = 0;
200
201 fn insert(&mut self, _index: usize, _val: u8) -> Option<u8> {
202 None
203 }
204
205 fn get(&self, _index: usize) -> Option<u8> {
206 None
207 }
208}
209
210pub enum ReportSingle {}
211impl Sealed for ReportSingle {}
212impl ReportCount for ReportSingle {
213 type IdleStorage = ();
214}
215
216macro_rules! option_block_idle_storage {
217 ($name: ident, $storage: ident) => {
218 impl IdleStorage for $storage<u8> {
219 const CAPACITY: u32 = $storage::<u8>::CAPACITY;
220
221 fn insert(&mut self, index: usize, val: u8) -> Option<u8> {
222 self.insert(index, val)
223 }
224
225 fn get(&self, index: usize) -> Option<u8> {
226 self.get(index).cloned()
227 }
228 }
229
230 pub enum $name {}
231 impl Sealed for $name {}
232 impl ReportCount for $name {
233 type IdleStorage = $storage<u8>;
234 }
235 };
236}
237
238option_block_idle_storage!(Reports8, Block8);
239option_block_idle_storage!(Reports16, Block16);
240option_block_idle_storage!(Reports32, Block32);
241option_block_idle_storage!(Reports64, Block64);
242option_block_idle_storage!(Reports128, Block128);
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq)]
245pub enum ReportDescriptor<'a> {
246 StaticDescriptor(&'static [u8]),
247 DynamicDescriptor(&'a [u8]),
248}
249
250#[cfg_attr(feature = "defmt", derive(defmt::Format))]
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub struct InterfaceConfig<'a, I, O, R>
253where
254 I: InSize,
255 O: OutSize,
256 R: ReportCount,
257{
258 marker: PhantomData<(I, O, R)>,
259 report_descriptor: ReportDescriptor<'a>,
260 report_descriptor_length: u16,
261 description: Option<&'a str>,
262 protocol: InterfaceProtocol,
263 idle_default: u8,
264 out_endpoint: Option<EndpointConfig>,
265 in_endpoint: EndpointConfig,
266}
267
268pub struct Interface<'a, B, I, O, R>
269where
270 B: UsbBus,
271 I: InSize,
272 O: OutSize,
273 R: ReportCount,
274{
275 id: InterfaceNumber,
276 config: InterfaceConfig<'a, I, O, R>,
277 out_endpoint: Option<EndpointOut<'a, B>>,
278 in_endpoint: EndpointIn<'a, B>,
279 description_index: Option<StringIndex>,
280 protocol: HidProtocol,
281 report_idle: R::IdleStorage,
282 global_idle: u8,
283 control_in_report_buffer: I::Buffer,
284 control_out_report_buffer: O::Buffer,
285}
286
287impl<'a, B: UsbBus + 'a, I, O, R> UsbAllocatable<'a, B> for InterfaceConfig<'a, I, O, R>
288where
289 B: UsbBus,
290 I: InSize,
291 O: OutSize,
292 R: ReportCount,
293{
294 type Allocated = Interface<'a, B, I, O, R>;
295
296 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
297 Interface::new(usb_alloc, self)
298 }
299}
300
301impl<'a, B, I, O, R> DeviceClass<'a> for Interface<'a, B, I, O, R>
302where
303 B: UsbBus,
304 I: InSize,
305 O: OutSize,
306 R: ReportCount,
307{
308 type I = Self;
309
310 fn interface(&mut self) -> &mut Self {
311 self
312 }
313
314 fn reset(&mut self) {
315 <Self as InterfaceClass<'a>>::reset(self);
316 }
317
318 fn tick(&mut self) -> Result<(), crate::UsbHidError> {
319 Ok(())
320 }
321}
322
323impl<'a, B: UsbBus, I, O, R> Interface<'a, B, I, O, R>
324where
325 B: UsbBus,
326 I: InSize,
327 O: OutSize,
328 R: ReportCount,
329{
330 pub fn new(usb_alloc: &'a UsbBusAllocator<B>, config: InterfaceConfig<'a, I, O, R>) -> Self {
331 Interface {
332 id: usb_alloc.interface(),
333 in_endpoint: usb_alloc.interrupt(I::Buffer::CAPACITY, config.in_endpoint.poll_interval),
334 out_endpoint: config
335 .out_endpoint
336 .map(|c| usb_alloc.interrupt(O::Buffer::CAPACITY, c.poll_interval)),
337 description_index: config.description.map(|_| usb_alloc.string()),
338 protocol: HidProtocol::Report,
340 report_idle: R::IdleStorage::default(),
341 global_idle: config.idle_default,
342 control_in_report_buffer: I::Buffer::default(),
343 control_out_report_buffer: O::Buffer::default(),
344 config,
345 }
346 }
347
348 fn clear_report_idle(&mut self) {
349 self.report_idle = R::IdleStorage::default();
350 }
351 fn get_report_idle(&self, report_id: u8) -> Option<u8> {
352 if u32::from(report_id) < R::IdleStorage::CAPACITY {
353 self.report_idle.get(report_id.into())
354 } else {
355 None
356 }
357 }
358 #[must_use]
359 pub fn protocol(&self) -> HidProtocol {
360 self.protocol
361 }
362 #[must_use]
363 pub fn global_idle(&self) -> MillisDurationU32 {
364 (u32::from(self.global_idle) * 4).millis()
365 }
366 #[must_use]
367 pub fn report_idle(&self, report_id: u8) -> Option<MillisDurationU32> {
368 if report_id == 0 {
369 None
370 } else {
371 self.get_report_idle(report_id)
372 .map(|i| (u32::from(i) * 4).millis())
373 }
374 }
375 pub fn write_report(&mut self, data: &[u8]) -> usb_device::Result<usize> {
376 let control_result = if self.control_in_report_buffer.is_empty() {
378 match self.control_in_report_buffer.extend_from_slice(data) {
379 Ok(()) => Ok(data.len()),
380 Err(()) => Err(UsbError::BufferOverflow),
381 }
382 } else {
383 Err(UsbError::WouldBlock)
384 };
385
386 let endpoint_result = self.in_endpoint.write(data);
388
389 match (control_result, endpoint_result) {
390 (_, Ok(n)) | (Ok(n), _) => Ok(n),
392 (Err(e), Err(UsbError::WouldBlock)) | (_, Err(e)) => Err(e),
394 }
395 }
396 pub fn read_report(&mut self, data: &mut [u8]) -> usb_device::Result<usize> {
397 let ep_result = if let Some(ep) = &self.out_endpoint {
399 ep.read(data)
400 } else {
401 Err(UsbError::WouldBlock)
402 };
403
404 match ep_result {
405 Err(UsbError::WouldBlock) => {
406 let out_len = self.control_out_report_buffer.len();
409 if self.control_out_report_buffer.is_empty() {
410 Err(UsbError::WouldBlock)
411 } else if data.len() < out_len {
412 Err(UsbError::BufferOverflow)
413 } else {
414 data[..out_len].copy_from_slice(self.control_out_report_buffer.as_ref());
415 self.control_out_report_buffer.clear();
416 Ok(out_len)
417 }
418 }
419 _ => ep_result,
420 }
421 }
422}
423impl<'a, B: UsbBus, I, O, R> InterfaceClass<'a> for Interface<'a, B, I, O, R>
424where
425 B: UsbBus,
426 I: InSize,
427 O: OutSize,
428 R: ReportCount,
429{
430 fn hid_descriptor_body(&self) -> [u8; 7] {
431 match (HidDescriptorBody {
432 bcd_hid: SPEC_VERSION_1_11,
433 country_code: COUNTRY_CODE_NOT_SUPPORTED,
434 num_descriptors: 1,
435 descriptor_type: DescriptorType::Report,
436 descriptor_length: self.config.report_descriptor_length,
437 }
438 .pack())
439 {
440 Ok(d) => d,
441 Err(_) => panic!("Failed to pack HidDescriptor"),
442 }
443 }
444
445 fn report_descriptor(&self) -> ReportDescriptor<'_> {
446 self.config.report_descriptor
447 }
448
449 fn id(&self) -> InterfaceNumber {
450 self.id
451 }
452 fn write_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()> {
453 writer.interface_alt(
454 self.id,
455 usb_device::device::DEFAULT_ALTERNATE_SETTING,
456 USB_CLASS_HID,
457 InterfaceSubClass::from(self.config.protocol).into(),
458 self.config.protocol.into(),
459 self.description_index,
460 )?;
461
462 writer.write(DescriptorType::Hid.into(), &self.hid_descriptor_body())?;
464
465 writer.endpoint(&self.in_endpoint)?;
467 if let Some(e) = &self.out_endpoint {
468 writer.endpoint(e)?;
469 }
470
471 Ok(())
472 }
473 fn get_string(&self, index: StringIndex, _lang_id: LangID) -> Option<&'a str> {
474 self.description_index
475 .filter(|&i| i == index)
476 .and(self.config.description)
477 }
478 fn reset(&mut self) {
479 self.protocol = HidProtocol::Report;
480 self.global_idle = self.config.idle_default;
481 self.clear_report_idle();
482 self.control_in_report_buffer = I::Buffer::default();
483 self.control_out_report_buffer = O::Buffer::default();
484 }
485 fn set_report(&mut self, data: &[u8]) -> usb_device::Result<()> {
486 if self.control_out_report_buffer.is_empty() {
487 if self
488 .control_out_report_buffer
489 .extend_from_slice(data)
490 .is_ok()
491 {
492 trace!(
493 "Set report, {:X} bytes",
494 &self.control_out_report_buffer.len()
495 );
496 Ok(())
497 } else {
498 error!(
499 "Failed to set report, too large for buffer. Report size {:X}, expected <={:X}",
500 data.len(),
501 O::Buffer::CAPACITY
502 );
503 Err(UsbError::BufferOverflow)
504 }
505 } else {
506 trace!("Failed to set report, buffer not empty");
507 Err(UsbError::WouldBlock)
508 }
509 }
510
511 fn get_report(&self, data: &mut [u8]) -> usb_device::Result<usize> {
512 if self.control_in_report_buffer.is_empty() {
513 trace!("GetReport would block, empty buffer");
514 Err(UsbError::WouldBlock)
515 } else if data.len() < self.control_in_report_buffer.len() {
516 error!("GetReport failed, buffer too short");
517 Err(UsbError::BufferOverflow)
518 } else {
519 data[..self.control_in_report_buffer.len()]
520 .copy_from_slice(self.control_in_report_buffer.as_ref());
521 Ok(self.control_in_report_buffer.len())
522 }
523 }
524
525 fn get_report_ack(&mut self) -> usb_device::Result<()> {
526 if self.control_in_report_buffer.is_empty() {
527 error!("GetReport ACK failed, empty buffer");
528 Err(UsbError::WouldBlock)
529 } else {
530 self.control_in_report_buffer.clear();
531 Ok(())
532 }
533 }
534
535 fn set_idle(&mut self, report_id: u8, value: u8) {
536 if report_id == 0 {
537 self.global_idle = value;
538 self.clear_report_idle();
541 info!("Set global idle to {:X}", value);
542 return;
543 }
544
545 let idx = report_id - 1;
546 if u32::from(idx) < R::IdleStorage::CAPACITY {
547 self.report_idle.insert(usize::from(idx), value);
548 info!("Set report idle for ID{:X} to {:X}", report_id, value);
549 } else {
550 warn!(
551 "Failed to set idle for report id {:X} - max id {:X}",
552 report_id,
553 R::IdleStorage::CAPACITY
554 );
555 }
556 }
557 fn get_idle(&self, report_id: u8) -> u8 {
558 if report_id == 0 {
559 self.global_idle
560 } else {
561 let idx = report_id - 1;
562 self.get_report_idle(idx).unwrap_or(self.global_idle)
563 }
564 }
565 fn set_protocol(&mut self, protocol: HidProtocol) {
566 self.protocol = protocol;
567 info!("Set protocol to {:?}", protocol);
568 }
569
570 fn get_protocol(&self) -> HidProtocol {
571 self.protocol
572 }
573}
574
575#[cfg_attr(feature = "defmt", derive(defmt::Format))]
576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
577struct EndpointConfig {
578 pub poll_interval: u8,
579}
580
581#[must_use = "this `UsbHidInterfaceBuilder` must be assigned or consumed by `::build_interface()`"]
582#[derive(Copy, Clone, Debug)]
583pub struct InterfaceBuilder<'a, I, O, R>
584where
585 I: InSize,
586 O: OutSize,
587 R: ReportCount,
588{
589 config: InterfaceConfig<'a, I, O, R>,
590}
591
592impl<'a, I, O, R> InterfaceBuilder<'a, I, O, R>
593where
594 I: InSize,
595 O: OutSize,
596 R: ReportCount,
597{
598 pub fn new(report_descriptor: &'a [u8]) -> BuilderResult<Self> {
599 if report_descriptor.len() > 128 {
600 return Err(UsbHidBuilderError::SliceLengthOverflow);
601 }
602
603 Ok(InterfaceBuilder {
604 config: InterfaceConfig {
605 marker: PhantomData,
606 report_descriptor: ReportDescriptor::DynamicDescriptor(report_descriptor),
607 report_descriptor_length: u16::try_from(report_descriptor.len())
608 .map_err(|_| UsbHidBuilderError::SliceLengthOverflow)?,
609 description: None,
610 protocol: InterfaceProtocol::None,
611 idle_default: 0,
612 out_endpoint: None,
613 in_endpoint: EndpointConfig { poll_interval: 20 },
614 },
615 })
616 }
617
618 pub fn with_static_descriptor(report_descriptor: &'static [u8]) -> BuilderResult<Self> {
619 Ok(InterfaceBuilder {
620 config: InterfaceConfig {
621 marker: PhantomData,
622 report_descriptor: ReportDescriptor::StaticDescriptor(report_descriptor),
623 report_descriptor_length: u16::try_from(report_descriptor.len())
624 .map_err(|_| UsbHidBuilderError::SliceLengthOverflow)?,
625 description: None,
626 protocol: InterfaceProtocol::None,
627 idle_default: 0,
628 out_endpoint: None,
629 in_endpoint: EndpointConfig { poll_interval: 20 },
630 },
631 })
632 }
633
634 pub fn boot_device(mut self, protocol: InterfaceProtocol) -> Self {
635 self.config.protocol = protocol;
636 self
637 }
638
639 pub fn idle_default(mut self, duration: MillisDurationU32) -> BuilderResult<Self> {
640 if duration.ticks() == 0 {
641 self.config.idle_default = 0;
642 } else {
643 let scaled_duration = duration.to_millis() / 4;
644
645 if scaled_duration == 0 {
646 self.config.idle_default = 1;
648 } else {
649 self.config.idle_default =
650 u8::try_from(scaled_duration).map_err(|_| UsbHidBuilderError::ValueOverflow)?;
651 }
652 }
653 Ok(self)
654 }
655
656 pub fn description(mut self, s: &'a str) -> Self {
657 self.config.description = Some(s);
658 self
659 }
660
661 pub fn with_out_endpoint(mut self, poll_interval: MillisDurationU32) -> BuilderResult<Self> {
662 self.config.out_endpoint = Some(EndpointConfig {
663 poll_interval: u8::try_from(poll_interval.to_millis())
664 .map_err(|_| UsbHidBuilderError::ValueOverflow)?,
665 });
666 Ok(self)
667 }
668
669 pub fn without_out_endpoint(mut self) -> Self {
670 self.config.out_endpoint = None;
671 self
672 }
673
674 pub fn in_endpoint(mut self, poll_interval: MillisDurationU32) -> BuilderResult<Self> {
675 self.config.in_endpoint = EndpointConfig {
676 poll_interval: u8::try_from(poll_interval.to_millis())
677 .map_err(|_| UsbHidBuilderError::ValueOverflow)?,
678 };
679 Ok(self)
680 }
681
682 #[must_use]
683 pub fn build(self) -> InterfaceConfig<'a, I, O, R> {
684 self.config
685 }
686}
687
688struct IdleManager<R> {
689 last_report: Option<R>,
690 since_last_report: MillisDurationU32,
691}
692
693impl<R> Default for IdleManager<R> {
694 fn default() -> Self {
695 Self {
696 last_report: Option::None,
697 since_last_report: 0.millis(),
698 }
699 }
700}
701
702impl<R> IdleManager<R>
703where
704 R: Eq + Copy,
705{
706 pub fn report_written(&mut self, report: R) {
707 self.last_report = Some(report);
708 self.since_last_report = 0.millis();
709 }
710
711 pub fn is_duplicate(&self, report: &R) -> bool {
712 self.last_report.as_ref() == Some(report)
713 }
714
715 pub fn tick(&mut self, timeout: MillisDurationU32) -> bool {
717 if timeout.ticks() == 0 {
718 self.since_last_report = 0.millis();
719 return false;
720 }
721
722 if self.since_last_report >= timeout {
723 self.since_last_report = 0.millis();
724 true
725 } else {
726 self.since_last_report += 1.millis();
727 false
728 }
729 }
730
731 pub fn last_report(&self) -> Option<R> {
732 self.last_report
733 }
734}
735
736pub struct ManagedIdleInterface<'a, B: UsbBus, Report, I, O>
737where
738 B: UsbBus,
739 I: InSize,
740 O: OutSize,
741{
742 interface: Interface<'a, B, I, O, ReportSingle>,
743 idle_manager: IdleManager<Report>,
744}
745
746#[allow(clippy::inline_always)]
747impl<'a, B: UsbBus, Report, I, O> ManagedIdleInterface<'a, B, Report, I, O>
748where
749 B: UsbBus,
750 I: InSize,
751 O: OutSize,
752{
753 fn new(interface: Interface<'a, B, I, O, ReportSingle>) -> Self {
754 Self {
755 interface,
756 idle_manager: IdleManager::default(),
757 }
758 }
759}
760
761#[allow(clippy::inline_always)]
762impl<B: UsbBus, Report, I, O, const LEN: usize> ManagedIdleInterface<'_, B, Report, I, O>
763where
764 Report: Copy + Eq + PackedStruct<ByteArray = [u8; LEN]>,
765 B: UsbBus,
766 I: InSize,
767 O: OutSize,
768{
769 pub fn write_report(&mut self, report: &Report) -> Result<(), UsbHidError> {
770 if self.idle_manager.is_duplicate(report) {
771 Err(UsbHidError::Duplicate)
772 } else {
773 let data = report.pack().map_err(|_| {
774 error!("Error packing report");
775 UsbHidError::SerializationError
776 })?;
777
778 self.interface
779 .write_report(&data)
780 .map_err(UsbHidError::from)
781 .map(|_| {
782 self.idle_manager.report_written(*report);
783 })
784 }
785 }
786
787 pub fn read_report(&mut self, data: &mut [u8]) -> usb_device::Result<usize> {
788 self.interface.read_report(data)
789 }
790}
791
792impl<'a, B: UsbBus, Report, I, O, const LEN: usize> DeviceClass<'a>
793 for ManagedIdleInterface<'a, B, Report, I, O>
794where
795 Report: Copy + Eq + PackedStruct<ByteArray = [u8; LEN]>,
796 B: UsbBus,
797 I: InSize,
798 O: OutSize,
799{
800 type I = Interface<'a, B, I, O, ReportSingle>;
801
802 fn interface(&mut self) -> &mut Self::I {
803 &mut self.interface
804 }
805
806 fn reset(&mut self) {
807 self.idle_manager = IdleManager::default();
808 }
809
810 fn tick(&mut self) -> Result<(), UsbHidError> {
811 if !(self.idle_manager.tick(self.interface.global_idle())) {
812 Ok(())
813 } else if let Some(r) = self.idle_manager.last_report() {
814 let data = r.pack().map_err(|_| {
815 error!("Error packing report");
816 UsbHidError::SerializationError
817 })?;
818 match self.interface.write_report(&data) {
819 Ok(n) => {
820 self.idle_manager.report_written(r);
821 Ok(n)
822 }
823 Err(UsbError::WouldBlock) => Err(UsbHidError::WouldBlock),
824 Err(e) => Err(UsbHidError::UsbError(e)),
825 }
826 .map(|_| ())
827 } else {
828 Ok(())
829 }
830 }
831}
832
833pub struct ManagedIdleInterfaceConfig<'a, Report, I, O>
834where
835 I: InSize,
836 O: OutSize,
837{
838 report: PhantomData<Report>,
839 interface_config: InterfaceConfig<'a, I, O, ReportSingle>,
840}
841
842impl<'a, Report, I, O> ManagedIdleInterfaceConfig<'a, Report, I, O>
843where
844 I: InSize,
845 O: OutSize,
846{
847 #[must_use]
848 pub fn new(interface_config: InterfaceConfig<'a, I, O, ReportSingle>) -> Self {
849 Self {
850 interface_config,
851 report: PhantomData,
852 }
853 }
854}
855
856impl<'a, B, Report, I, O> UsbAllocatable<'a, B> for ManagedIdleInterfaceConfig<'a, Report, I, O>
857where
858 B: UsbBus + 'a,
859 I: InSize,
860 O: OutSize,
861{
862 type Allocated = ManagedIdleInterface<'a, B, Report, I, O>;
863
864 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
865 ManagedIdleInterface::new(self.interface_config.allocate(usb_alloc))
866 }
867}