usbd_human_interface_device/device/
multiaxis.rs

1//!HID multiaxis
2use crate::usb_class::prelude::*;
3use core::default::Default;
4use fugit::ExtU32;
5use packed_struct::prelude::*;
6use usb_device::bus::UsbBus;
7use usb_device::class_prelude::UsbBusAllocator;
8
9#[rustfmt::skip]
10pub const MULTIAXIS_DESCRIPTOR: &[u8] = &[
11    0x05, 0x01, // Usage Page (Generic Desktop)         5,   1
12    0x09, 0x08, // Usage (multi-axis Controller)        9,   8
13    0xa1, 0x01, // Collection (Application)             161, 1
14    0x09, 0x01, //   Usage Page (Pointer)               9,   1
15    0xa1, 0x00, //   Collection (Physical)              161, 0
16    0x09, 0x30, //     Usage (X)                        9,   48
17    0x09, 0x31, //     Usage (Y)                        9,   49
18    0x09, 0x32, //     Usage (Z)                        9,   50
19    0x09, 0x33, //     Usage (Rx)                       9,   51
20    0x09, 0x34, //     Usage (Ry)                       9,   52
21    0x09, 0x35, //     Usage (Rz)                       9,   53
22    0x15, 0x81, //     Logical Minimum (-127)           21,  129
23    0x25, 0x7f, //     Logical Maximum (127)            37,  127
24    0x75, 0x08, //     Report Size (8)                  117, 8
25    0x95, 0x06, //     Report count (6)                 149, 6,
26    0x81, 0x02, //     Input (Data, Variable, Absolute) 129, 2,
27    0xc0,       //   End Collection                     192,
28    0x05, 0x09, //   Usage Page (Button)                5,   9,
29    0x19, 0x01, //   Usage Minimum (0)                  25,  1,
30    0x29, 0x08, //   Usage Maximum (8)                  41,  8,
31    0x15, 0x00, //   Logical Minimum (0)                21,  0
32    0x25, 0x01, //   Logical Maximum (1)                37,  1,
33    0x75, 0x01, //   Report Size (1)                    117, 1,
34    0x95, 0x08, //   Report Count (8)                   149, 8
35    0x81, 0x02, //   Input (Data, Variable, Absolute)   129, 2,
36    0xc0,       // End Collection                       192
37];
38
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
41#[packed_struct(endian = "lsb", size_bytes = "7")]
42pub struct MultiaxisReport {
43    #[packed_field]
44    pub x: i8,
45    #[packed_field]
46    pub y: i8,
47    #[packed_field]
48    pub z: i8,
49    #[packed_field]
50    pub rx: i8,
51    #[packed_field]
52    pub ry: i8,
53    #[packed_field]
54    pub rz: i8,
55    #[packed_field]
56    pub buttons: u8,
57}
58
59pub struct Multiaxis<'a, B: UsbBus> {
60    interface: Interface<'a, B, InBytes8, OutNone, ReportSingle>,
61}
62
63impl<B: UsbBus> Multiaxis<'_, B> {
64    pub fn write_report(&mut self, report: &MultiaxisReport) -> Result<(), UsbHidError> {
65        let data = report.pack().map_err(|_| {
66            error!("Error packing MultiaxisReport");
67            UsbHidError::SerializationError
68        })?;
69        self.interface
70            .write_report(&data)
71            .map(|_| ())
72            .map_err(UsbHidError::from)
73    }
74}
75
76impl<'a, B: UsbBus> DeviceClass<'a> for Multiaxis<'a, B> {
77    type I = Interface<'a, B, InBytes8, OutNone, ReportSingle>;
78
79    fn interface(&mut self) -> &mut Self::I {
80        &mut self.interface
81    }
82
83    fn reset(&mut self) {}
84
85    fn tick(&mut self) -> Result<(), UsbHidError> {
86        Ok(())
87    }
88}
89
90pub struct MultiaxisConfig<'a> {
91    interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>,
92}
93
94impl Default for MultiaxisConfig<'_> {
95    fn default() -> Self {
96        Self::new(
97            unwrap!(unwrap!(InterfaceBuilder::new(MULTIAXIS_DESCRIPTOR))
98                .boot_device(InterfaceProtocol::None)
99                .description("Multi-axis Controller")
100                .in_endpoint(10.millis()))
101            .without_out_endpoint()
102            .build(),
103        )
104    }
105}
106
107impl<'a> MultiaxisConfig<'a> {
108    #[must_use]
109    pub fn new(interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>) -> Self {
110        Self { interface }
111    }
112}
113
114impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for MultiaxisConfig<'a> {
115    type Allocated = Multiaxis<'a, B>;
116
117    fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
118        Self::Allocated {
119            interface: Interface::new(usb_alloc, self.interface),
120        }
121    }
122}