usbd_hid/
lib.rs

1//! HID report descriptor generation & USB HID class implementation
2//!
3//! This crate implements components necessary to build a USB HID device. This
4//! includes generation of the report descriptor, serialization of input reports,
5//! and communicating with a host that implements USB HID.
6#![no_std]
7
8pub use usb_device::{Result, UsbError};
9pub mod descriptor;
10pub mod hid_class;
11
12#[cfg(test)]
13#[allow(unused_imports)]
14mod tests {
15    use crate::descriptor::generator_prelude::*;
16    use crate::descriptor::{KeyboardReport, MouseReport, SystemControlReport};
17
18    // This should generate this descriptor:
19    // 0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
20    // 0x09, 0x01,        // Usage (0x01)
21    // 0xA1, 0x01,        // Collection (Application)
22    // 0x15, 0x00,        //   Logical Minimum (0)
23    // 0x26, 0xFF, 0x00,  //   Logical Maximum (255)
24    // 0x75, 0x08,        //   Report Size (8)
25    // 0x95, 0x01,        //   Report Count (1)
26    // 0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
27    // 0x27, 0xFF, 0xFF, 0x00, 0x00,  //   Logical Maximum (65534)
28    // 0x75, 0x10,        //   Report Size (16)
29    // 0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
30    // 0xC1,              // End Collection
31    #[gen_hid_descriptor(
32        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
33            f1=input;
34            f2=output;
35        }
36    )]
37    #[allow(dead_code)]
38    struct CustomUnaryUnsignedFrame {
39        f1: u8,
40        f2: u16,
41    }
42
43    #[test]
44    fn test_custom_unsigned() {
45        let expected = &[
46            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 21u8, 0u8, 38u8, 255u8, 0u8, 117u8, 8u8, 149u8,
47            1u8, 129u8, 2u8, 39u8, 255u8, 255u8, 0u8, 0u8, 117u8, 16u8, 145u8, 2u8, 192u8,
48        ];
49        assert_eq!(CustomUnaryUnsignedFrame::desc(), expected);
50    }
51
52    // This should generate this descriptor:
53    // 0x06, 0x00, 0xFF,                // Usage Page (Vendor Defined 0xFF00)
54    // 0x09, 0x01,                      // Usage (0x01)
55    // 0xA1, 0x01,                      // Collection (Application)
56    // 0x17, 0x81, 0xFF, 0xFF, 0xFF,    //   Logical Minimum (-128)
57    // 0x25, 0x7F,                      //   Logical Maximum (127)
58    // 0x75, 0x08,                      //   Report Size (8)
59    // 0x95, 0x01,                      //   Report Count (1)
60    // 0x81, 0x02,                      //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
61    // 0x17, 0x01, 0x80, 0xFF, 0xFF,    //   Logical Minimum (-32768)
62    // 0x26, 0xFF, 0x7F,                //   Logical Maximum (32767)
63    // 0x75, 0x10,                      //   Report Size (16)
64    // 0x91, 0x02,                      //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
65    // 0xC0,                            // End Collection
66    #[gen_hid_descriptor(
67        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
68            f1=input;
69            f2=output;
70        }
71    )]
72    #[allow(dead_code)]
73    struct CustomUnarySignedFrame {
74        f1: i8,
75        f2: i16,
76    }
77
78    #[test]
79    fn test_custom_signed() {
80        let expected = &[
81            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 23u8, 129u8, 255u8, 255u8, 255u8, 37u8, 127u8,
82            117u8, 8u8, 149u8, 1u8, 129u8, 2u8, 23u8, 1u8, 128u8, 255u8, 255u8, 38u8, 255u8, 127u8,
83            117u8, 16u8, 145u8, 2u8, 192u8,
84        ];
85        assert_eq!(CustomUnarySignedFrame::desc()[0..32], expected[0..32]);
86    }
87
88    #[gen_hid_descriptor(
89        (report_id = 0x01,) = {
90            f1=input
91        },
92        (report_id = 0x02,) = {
93            f2=input
94        },
95    )]
96    #[allow(dead_code)]
97    struct CustomMultiReport {
98        f1: u8,
99        f2: u8,
100    }
101
102    #[test]
103    fn test_custom_reports() {
104        let expected: &[u8] = &[
105            133, 1, 21, 0, 38, 255, 0, 117, 8, 149, 1, 129, 2, 133, 2, 129, 2,
106        ];
107        assert_eq!(CustomMultiReport::desc(), expected);
108    }
109
110    // This should generate the following descriptor:
111    // 0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
112    // 0x09, 0x01,        // Usage (0x01)
113    // 0xA1, 0x01,        // Collection (Application)
114    // 0x15, 0x00,        //   Logical Minimum (0)
115    // 0x26, 0xFF, 0x00,  //   Logical Maximum (255)
116    // 0x75, 0x08,        //   Report Size (8)
117    // 0x95, 0x20,        //   Report Count (32)
118    // 0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
119    // 0xC0,              // End Collection
120    #[gen_hid_descriptor(
121        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
122            buff=input;
123        }
124    )]
125    #[allow(dead_code)]
126    struct CustomArray {
127        buff: [u8; 32],
128    }
129
130    #[test]
131    fn test_array() {
132        let expected: &[u8] = &[
133            6, 0, 255, 9, 1, 161, 1, 21, 0, 38, 255, 0, 117, 8, 149, 32, 129, 2, 192,
134        ];
135        assert_eq!(CustomArray::desc(), expected);
136    }
137
138    #[gen_hid_descriptor(
139        (collection = APPLICATION, usage_page = VENDOR_DEFINED_START, usage = 0x01) = {
140            (usage_min = BUTTON_1, usage_max = BUTTON_3) = {
141                #[item_settings data,variable,relative] f1=input;
142            };
143        }
144    )]
145    #[allow(dead_code)]
146    struct CustomConst {
147        f1: u8,
148    }
149
150    #[test]
151    fn test_custom_const() {
152        let expected = &[
153            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 25u8, 1u8, 41u8, 3u8, 21u8, 0u8, 38u8, 255u8,
154            0u8, 117u8, 8u8, 149u8, 1u8, 129u8, 6u8, 192u8,
155        ];
156        assert_eq!(CustomConst::desc(), expected);
157    }
158
159    // This should generate the following descriptor:
160    // 0x85, 0x01,        // Report ID (1)
161    // 0x15, 0x00,        // Logical Minimum (0)
162    // 0x25, 0x01,        // Logical Maximum (1)
163    // 0x75, 0x01,        // Report Size (1)
164    // 0x95, 0x03,        // Report Count (3)
165    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
166    // 0x95, 0x05,        // Report Count (5)
167    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
168    // 0x95, 0x09,        // Report Count (9)
169    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
170    // 0x95, 0x07,        // Report Count (7)
171    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
172    // 0x95, 0x14,        // Report Count (20)
173    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
174    // 0x95, 0x04,        // Report Count (4)
175    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
176    #[gen_hid_descriptor(
177        (report_id = 0x01,) = {
178            #[packed_bits 3] f1=input;
179            #[packed_bits 9] f2=input;
180            #[packed_bits 20] f3=input;
181        }
182    )]
183    #[allow(dead_code)]
184    struct CustomPackedBits {
185        f1: u8,
186        f2: u16,
187        f3: [u8; 3],
188    }
189
190    #[test]
191    fn test_custom_packed_bits() {
192        let expected = &[
193            133u8, 1u8, 21u8, 0u8, 37u8, 1u8, 117u8, 1u8, 149u8, 3u8, 129u8, 2u8, 149u8, 5u8,
194            129u8, 3u8, 149u8, 9u8, 129u8, 2u8, 149u8, 7u8, 129u8, 3u8, 149u8, 20u8, 129u8, 2u8,
195            149u8, 4u8, 129u8, 3u8,
196        ];
197        assert_eq!(CustomPackedBits::desc(), expected);
198    }
199
200    #[test]
201    fn test_mouse_descriptor() {
202        let expected = &[
203            5u8, 1u8, 9u8, 2u8, 161u8, 1u8, 9u8, 1u8, 161u8, 0u8, 5u8, 9u8, 25u8, 1u8, 41u8, 8u8,
204            21u8, 0u8, 37u8, 1u8, 117u8, 1u8, 149u8, 8u8, 129u8, 2u8, 5u8, 1u8, 9u8, 48u8, 23u8,
205            129u8, 255u8, 255u8, 255u8, 37u8, 127u8, 117u8, 8u8, 149u8, 1u8, 129u8, 6u8, 9u8, 49u8,
206            129u8, 6u8, 9u8, 56u8, 129u8, 6u8, 5u8, 12u8, 10u8, 56u8, 2u8, 129u8, 6u8, 192u8,
207            192u8,
208        ];
209        assert_eq!(MouseReport::desc()[0..32], expected[0..32]);
210    }
211
212    #[test]
213    fn test_keyboard_descriptor() {
214        let expected = &[
215            0x05, 0x01, // Usage Page (Generic Desktop)
216            0x09, 0x06, // Usage (Keyboard)
217            0xa1, 0x01, // Collection (Application)
218            0x05, 0x07, // Usage Page (Key Codes)
219            0x19, 0xe0, // Usage Minimum (224)
220            0x29, 0xe7, // Usage Maximum (231)
221            0x15, 0x00, // Logical Minimum (0)
222            0x25, 0x01, // Logical Maximum (1)
223            0x75, 0x01, // Report Size (1)
224            0x95, 0x08, // Report count (8)
225            0x81, 0x02, // Input (Data, Variable, Absolute)
226            0x19, 0x00, // Usage Minimum (0)
227            0x29, 0xFF, // Usage Maximum (255)
228            0x26, 0xFF, 0x00, // Logical Maximum (255)
229            0x75, 0x08, // Report Size (8)
230            0x95, 0x01, // Report Count (1)
231            0x81, 0x03, // Input (Const, Variable, Absolute)
232            0x05, 0x08, // Usage Page (LEDs)
233            0x19, 0x01, // Usage Minimum (1)
234            0x29, 0x05, // Usage Maximum (5)
235            0x25, 0x01, // Logical Maximum (1)
236            0x75, 0x01, // Report Size (1)
237            0x95, 0x05, // Report Count (5)
238            0x91, 0x02, // Output (Data, Variable, Absolute)
239            0x95, 0x03, // Report Count (3)
240            0x91, 0x03, // Output (Constant, Variable, Absolute)
241            0x05, 0x07, // Usage Page (Key Codes)
242            0x19, 0x00, // Usage Minimum (0)
243            0x29, 0xDD, // Usage Maximum (221)
244            0x26, 0xFF, 0x00, // Logical Maximum (255)
245            0x75, 0x08, // Report Size (8)
246            0x95, 0x06, // Report Count (6)
247            0x81, 0x00, // Input (Data, Array, Absolute)
248            0xc0, // End Collection
249        ];
250        assert_eq!(KeyboardReport::desc(), expected);
251    }
252
253    #[test]
254    fn test_system_control_descriptor() {
255        let expected = &[
256            0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
257            0x09, 0x80, // Usage (Sys Control)
258            0xA1, 0x01, // Collection (Application)
259            0x19, 0x81, //   Usage Minimum (Sys Power Down)
260            0x29, 0xB7, //   Usage Maximum (Sys Display LCD Autoscale)
261            0x15, 0x01, //   Logical Minimum (1)
262            0x26, 0xFF, 0x00, //   Logical Maximum (255)
263            0x75, 0x08, //   Report Size (8)
264            0x95, 0x01, //   Report Count (1)
265            0x81,
266            0x00, //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
267            0xC0, // End Collection
268        ];
269        assert_eq!(SystemControlReport::desc(), expected);
270    }
271}