usbd_human_interface_device/device/
joystick.rs

1//!HID joystick
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 JOYSTICK_DESCRIPTOR: &[u8] = &[
11    0x05, 0x01, // Usage Page (Generic Desktop)         5,   1
12    0x09, 0x04, // Usage (Joystick)                     9,   4
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    0x15, 0x81, //     Logical Minimum (-127)           21,  129
19    0x25, 0x7f, //     Logical Maximum (127)            37,  127
20    0x75, 0x08, //     Report Size (8)                  117, 8
21    0x95, 0x02, //     Report count (2)                 149, 2,
22    0x81, 0x02, //     Input (Data, Variable, Absolute) 129, 2,
23    0xc0,       //   End Collection                     192,
24    0x05, 0x09, //   Usage Page (Button)                5,   9,
25    0x19, 0x01, //   Usage Minimum (0)                  25,  1,
26    0x29, 0x08, //   Usage Maximum (8)                  41,  8,
27    0x15, 0x00, //   Logical Minimum (0)                21,  0
28    0x25, 0x01, //   Logical Maximum (1)                37,  1,
29    0x75, 0x01, //   Report Size (1)                    117, 1,
30    0x95, 0x08, //   Report Count (8)                   149, 8
31    0x81, 0x02, //   Input (Data, Variable, Absolute)   129, 2,
32    0xc0,       // End Collection                       192
33];
34
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
37#[packed_struct(endian = "lsb", size_bytes = "3")]
38pub struct JoystickReport {
39    #[packed_field]
40    pub x: i8,
41    #[packed_field]
42    pub y: i8,
43    #[packed_field]
44    pub buttons: u8,
45}
46
47pub struct Joystick<'a, B: UsbBus> {
48    interface: Interface<'a, B, InBytes8, OutNone, ReportSingle>,
49}
50
51impl<B: UsbBus> Joystick<'_, B> {
52    pub fn write_report(&mut self, report: &JoystickReport) -> Result<(), UsbHidError> {
53        let data = report.pack().map_err(|_| {
54            error!("Error packing JoystickReport");
55            UsbHidError::SerializationError
56        })?;
57        self.interface
58            .write_report(&data)
59            .map(|_| ())
60            .map_err(UsbHidError::from)
61    }
62}
63
64impl<'a, B: UsbBus> DeviceClass<'a> for Joystick<'a, B> {
65    type I = Interface<'a, B, InBytes8, OutNone, ReportSingle>;
66
67    fn interface(&mut self) -> &mut Self::I {
68        &mut self.interface
69    }
70
71    fn reset(&mut self) {}
72
73    fn tick(&mut self) -> Result<(), UsbHidError> {
74        Ok(())
75    }
76}
77
78pub struct JoystickConfig<'a> {
79    interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>,
80}
81
82impl Default for JoystickConfig<'_> {
83    fn default() -> Self {
84        Self::new(
85            unwrap!(unwrap!(InterfaceBuilder::new(JOYSTICK_DESCRIPTOR))
86                .boot_device(InterfaceProtocol::None)
87                .description("Joystick")
88                .in_endpoint(10.millis()))
89            .without_out_endpoint()
90            .build(),
91        )
92    }
93}
94
95impl<'a> JoystickConfig<'a> {
96    #[must_use]
97    pub fn new(interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>) -> Self {
98        Self { interface }
99    }
100}
101
102impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for JoystickConfig<'a> {
103    type Allocated = Joystick<'a, B>;
104
105    fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
106        Self::Allocated {
107            interface: Interface::new(usb_alloc, self.interface),
108        }
109    }
110}