usbd_human_interface_device/
interface.rs

1//! Human Interface Device Interfaces
2use 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    // N must be < u16::MAX
115    // not currently enforceable in stable
116    #[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            //When initialized, all devices default to report protocol - Hid spec 7.2.6 Set_Protocol Request
339            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        //Try to write report to the report buffer for the config endpoint
377        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        //Also try to write report to the in endpoint
387        let endpoint_result = self.in_endpoint.write(data);
388
389        match (control_result, endpoint_result) {
390            //OK if either succeeded
391            (_, Ok(n)) | (Ok(n), _) => Ok(n),
392            //non-WouldBlock errors take preference
393            (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        //If there is an out endpoint, try to read from it first
398        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                //If there wasn't data available from the in endpoint
407                //try the config endpoint report buffer
408                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        //Hid descriptor
463        writer.write(DescriptorType::Hid.into(), &self.hid_descriptor_body())?;
464
465        //Endpoint descriptors
466        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            //"If the lower byte of value is zero, then the idle rate applies to all
539            //input reports generated by the device" - HID spec 7.2.4
540            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                //round up for 1-3ms
647                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    /// Call every 1ms
716    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}