Skip to main content

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// Allow gen_hid_descriptor macro to access usbd_hid types from within usbd_hid itself,
13// while retaining the ability to run the macro in user crates as well.
14extern crate self as usbd_hid;
15
16#[cfg(test)]
17#[allow(unused_imports)]
18mod tests {
19    use crate::descriptor::{generator_prelude::*, CtapReport};
20    use crate::descriptor::{KeyboardReport, MouseReport, SystemControlReport};
21
22    fn serialize<T: AsInputReport>(buf: &mut [u8], report: T) -> &[u8] {
23        let size = report.serialize(buf).unwrap();
24        &buf[..size]
25    }
26
27    // This should generate this descriptor:
28    // 0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
29    // 0x09, 0x01,        // Usage (0x01)
30    // 0xA1, 0x01,        // Collection (Application)
31    // 0x15, 0x00,        //   Logical Minimum (0)
32    // 0x26, 0xFF, 0x00,  //   Logical Maximum (255)
33    // 0x75, 0x08,        //   Report Size (8)
34    // 0x95, 0x01,        //   Report Count (1)
35    // 0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
36    // 0x27, 0xFF, 0xFF, 0x00, 0x00,  //   Logical Maximum (65534)
37    // 0x75, 0x10,        //   Report Size (16)
38    // 0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
39    // 0xC1,              // End Collection
40    #[gen_hid_descriptor(
41        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
42            f1=input;
43            f2=output;
44        }
45    )]
46    #[allow(dead_code)]
47    struct CustomUnaryUnsignedFrame {
48        f1: u8,
49        f2: u16,
50    }
51
52    #[test]
53    fn test_custom_unsigned() {
54        let expected = &[
55            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 21u8, 0u8, 38u8, 255u8, 0u8, 117u8, 8u8, 149u8,
56            1u8, 129u8, 2u8, 39u8, 255u8, 255u8, 0u8, 0u8, 117u8, 16u8, 145u8, 2u8, 192u8,
57        ];
58        assert_eq!(CustomUnaryUnsignedFrame::desc(), expected);
59    }
60
61    #[test]
62    fn test_custom_unsigned_serialize() {
63        let expected = &[1];
64        let report = CustomUnaryUnsignedFrame { f1: 1, f2: 2 };
65        let mut buf = [0; 64];
66        let result = serialize(&mut buf, report);
67        assert_eq!(result, expected);
68    }
69
70    // This should generate this descriptor:
71    // 0x06, 0x00, 0xFF,                // Usage Page (Vendor Defined 0xFF00)
72    // 0x09, 0x01,                      // Usage (0x01)
73    // 0xA1, 0x01,                      // Collection (Application)
74    // 0x17, 0x81, 0xFF, 0xFF, 0xFF,    //   Logical Minimum (-128)
75    // 0x25, 0x7F,                      //   Logical Maximum (127)
76    // 0x75, 0x08,                      //   Report Size (8)
77    // 0x95, 0x01,                      //   Report Count (1)
78    // 0x81, 0x02,                      //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
79    // 0x17, 0x01, 0x80, 0xFF, 0xFF,    //   Logical Minimum (-32768)
80    // 0x26, 0xFF, 0x7F,                //   Logical Maximum (32767)
81    // 0x75, 0x10,                      //   Report Size (16)
82    // 0x91, 0x02,                      //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
83    // 0xC0,                            // End Collection
84    #[gen_hid_descriptor(
85        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
86            f1=input;
87            f2=output;
88        }
89    )]
90    #[allow(dead_code)]
91    struct CustomUnarySignedFrame {
92        f1: i8,
93        f2: i16,
94    }
95
96    #[test]
97    fn test_custom_signed() {
98        let expected = &[
99            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 23u8, 129u8, 255u8, 255u8, 255u8, 37u8, 127u8,
100            117u8, 8u8, 149u8, 1u8, 129u8, 2u8, 23u8, 1u8, 128u8, 255u8, 255u8, 38u8, 255u8, 127u8,
101            117u8, 16u8, 145u8, 2u8, 192u8,
102        ];
103        assert_eq!(CustomUnarySignedFrame::desc()[0..32], expected[0..32]);
104    }
105
106    #[test]
107    fn test_custom_signed_serialize() {
108        let expected = &[1];
109        let report = CustomUnarySignedFrame { f1: 1, f2: 2 };
110        let mut buf = [0; 64];
111        let result = serialize(&mut buf, report);
112        assert_eq!(result, expected);
113    }
114
115    #[gen_hid_descriptor(
116        (report_id = 0x01,) = {
117            f1=input
118        },
119        (report_id = 0x02,) = {
120            f2=input
121        },
122    )]
123    #[allow(dead_code)]
124    struct CustomMultiReport {
125        f1: u8,
126        f2: u8,
127    }
128
129    #[test]
130    fn test_custom_reports() {
131        let expected: &[u8] = &[
132            133, 1, 21, 0, 38, 255, 0, 117, 8, 149, 1, 129, 2, 133, 2, 129, 2,
133        ];
134        assert_eq!(CustomMultiReport::desc(), expected);
135    }
136
137    // This should generate the following descriptor:
138    // 0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
139    // 0x09, 0x01,        // Usage (0x01)
140    // 0xA1, 0x01,        // Collection (Application)
141    // 0x15, 0x00,        //   Logical Minimum (0)
142    // 0x26, 0xFF, 0x00,  //   Logical Maximum (255)
143    // 0x75, 0x08,        //   Report Size (8)
144    // 0x95, 0x20,        //   Report Count (32)
145    // 0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
146    // 0xC0,              // End Collection
147    #[gen_hid_descriptor(
148        (collection = 0x01, usage = 0x01, usage_page = 0xff00) = {
149            buff=input;
150        }
151    )]
152    #[allow(dead_code)]
153    struct CustomArray {
154        buff: [u8; 32],
155    }
156
157    #[test]
158    fn test_array() {
159        let expected: &[u8] = &[
160            6, 0, 255, 9, 1, 161, 1, 21, 0, 38, 255, 0, 117, 8, 149, 32, 129, 2, 192,
161        ];
162        assert_eq!(CustomArray::desc(), expected);
163    }
164
165    #[test]
166    fn test_array_serialize() {
167        let expected = [
168            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
169            4, 4, 4,
170        ];
171        let report = CustomArray { buff: [4; 32] };
172        let mut buf = [0; 64];
173        let result = serialize(&mut buf, report);
174        assert_eq!(result, expected);
175    }
176
177    #[gen_hid_descriptor(
178        (collection = APPLICATION, usage_page = VENDOR_DEFINED_START, usage = 0x01) = {
179            (usage_min = BUTTON_1, usage_max = BUTTON_3) = {
180                #[item_settings(data,variable,relative)] f1=input;
181            };
182        }
183    )]
184    #[allow(dead_code)]
185    struct CustomConst {
186        f1: u8,
187    }
188
189    #[test]
190    fn test_custom_const() {
191        let expected = &[
192            6u8, 0u8, 255u8, 9u8, 1u8, 161u8, 1u8, 25u8, 1u8, 41u8, 3u8, 21u8, 0u8, 38u8, 255u8,
193            0u8, 117u8, 8u8, 149u8, 1u8, 129u8, 6u8, 192u8,
194        ];
195        assert_eq!(CustomConst::desc(), expected);
196    }
197
198    #[test]
199    fn test_custom_const_serialize() {
200        let expected = &[1];
201        let report = CustomConst { f1: 1 };
202        let mut buf = [0; 64];
203        let result = serialize(&mut buf, report);
204        assert_eq!(result, expected);
205    }
206
207    // This should generate the following descriptor:
208    // 0x85, 0x01,        // Report ID (1)
209    // 0x15, 0x00,        // Logical Minimum (0)
210    // 0x25, 0x01,        // Logical Maximum (1)
211    // 0x75, 0x01,        // Report Size (1)
212    // 0x95, 0x03,        // Report Count (3)
213    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
214    // 0x95, 0x05,        // Report Count (5)
215    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
216    // 0x95, 0x09,        // Report Count (9)
217    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
218    // 0x95, 0x07,        // Report Count (7)
219    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
220    // 0x95, 0x14,        // Report Count (20)
221    // 0x81, 0x02,        // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
222    // 0x95, 0x04,        // Report Count (4)
223    // 0x81, 0x03,        // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
224    #[gen_hid_descriptor(
225        (report_id = 0x01,) = {
226            #[packed_bits = 3] f1=input;
227            #[packed_bits = 9] f2=input;
228            #[packed_bits = 20] f3=input;
229        }
230    )]
231    #[allow(dead_code)]
232    struct CustomPackedBits {
233        f1: u8,
234        f2: u16,
235        f3: [u8; 3],
236    }
237
238    #[test]
239    fn test_custom_packed_bits() {
240        let expected = &[
241            133u8, 1u8, 21u8, 0u8, 37u8, 1u8, 117u8, 1u8, 149u8, 3u8, 129u8, 2u8, 149u8, 5u8,
242            129u8, 3u8, 149u8, 9u8, 129u8, 2u8, 149u8, 7u8, 129u8, 3u8, 149u8, 20u8, 129u8, 2u8,
243            149u8, 4u8, 129u8, 3u8,
244        ];
245        assert_eq!(CustomPackedBits::desc(), expected);
246    }
247
248    #[test]
249    fn test_mouse_descriptor() {
250        let expected = &[
251            5u8, 1u8, 9u8, 2u8, 161u8, 1u8, 9u8, 1u8, 161u8, 0u8, 5u8, 9u8, 25u8, 1u8, 41u8, 8u8,
252            21u8, 0u8, 37u8, 1u8, 117u8, 1u8, 149u8, 8u8, 129u8, 2u8, 5u8, 1u8, 9u8, 48u8, 23u8,
253            129u8, 255u8, 255u8, 255u8, 37u8, 127u8, 117u8, 8u8, 149u8, 1u8, 129u8, 6u8, 9u8, 49u8,
254            129u8, 6u8, 9u8, 56u8, 129u8, 6u8, 5u8, 12u8, 10u8, 56u8, 2u8, 129u8, 6u8, 192u8,
255            192u8,
256        ];
257        assert_eq!(MouseReport::desc()[0..32], expected[0..32]);
258    }
259
260    #[test]
261    fn test_mouse_serialize() {
262        let expected = &[1, 2, 3, 4, 5];
263        let report = MouseReport {
264            buttons: 1,
265            x: 2,
266            y: 3,
267            wheel: 4,
268            pan: 5,
269        };
270        let mut buf = [0; 64];
271        let result = serialize(&mut buf, report);
272        assert_eq!(result, expected);
273    }
274
275    #[test]
276    fn test_keyboard_descriptor() {
277        let expected = &[
278            0x05, 0x01, // Usage Page (Generic Desktop)
279            0x09, 0x06, // Usage (Keyboard)
280            0xa1, 0x01, // Collection (Application)
281            0x05, 0x07, // Usage Page (Key Codes)
282            0x19, 0xe0, // Usage Minimum (224)
283            0x29, 0xe7, // Usage Maximum (231)
284            0x15, 0x00, // Logical Minimum (0)
285            0x25, 0x01, // Logical Maximum (1)
286            0x75, 0x01, // Report Size (1)
287            0x95, 0x08, // Report count (8)
288            0x81, 0x02, // Input (Data, Variable, Absolute)
289            0x19, 0x00, // Usage Minimum (0)
290            0x29, 0xFF, // Usage Maximum (255)
291            0x26, 0xFF, 0x00, // Logical Maximum (255)
292            0x75, 0x08, // Report Size (8)
293            0x95, 0x01, // Report Count (1)
294            0x81, 0x03, // Input (Const, Variable, Absolute)
295            0x05, 0x08, // Usage Page (LEDs)
296            0x19, 0x01, // Usage Minimum (1)
297            0x29, 0x05, // Usage Maximum (5)
298            0x25, 0x01, // Logical Maximum (1)
299            0x75, 0x01, // Report Size (1)
300            0x95, 0x05, // Report Count (5)
301            0x91, 0x02, // Output (Data, Variable, Absolute)
302            0x95, 0x03, // Report Count (3)
303            0x91, 0x03, // Output (Constant, Variable, Absolute)
304            0x05, 0x07, // Usage Page (Key Codes)
305            0x19, 0x00, // Usage Minimum (0)
306            0x29, 0xDD, // Usage Maximum (221)
307            0x26, 0xFF, 0x00, // Logical Maximum (255)
308            0x75, 0x08, // Report Size (8)
309            0x95, 0x06, // Report Count (6)
310            0x81, 0x00, // Input (Data, Array, Absolute)
311            0xc0, // End Collection
312        ];
313        assert_eq!(KeyboardReport::desc(), expected);
314    }
315
316    #[test]
317    fn test_keyboard_serialize() {
318        let expected = &[1, 2, 4, 5, 6, 7, 8, 9];
319        let report = KeyboardReport {
320            modifier: 1,
321            reserved: 2,
322            leds: 3,
323            keycodes: [4, 5, 6, 7, 8, 9],
324        };
325        let mut buf = [0; 64];
326        let result = serialize(&mut buf, report);
327        assert_eq!(result, expected);
328    }
329
330    #[test]
331    fn test_system_control_descriptor() {
332        let expected = &[
333            0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
334            0x09, 0x80, // Usage (Sys Control)
335            0xA1, 0x01, // Collection (Application)
336            0x19, 0x81, //   Usage Minimum (Sys Power Down)
337            0x29, 0xB7, //   Usage Maximum (Sys Display LCD Autoscale)
338            0x15, 0x01, //   Logical Minimum (1)
339            0x26, 0xFF, 0x00, //   Logical Maximum (255)
340            0x75, 0x08, //   Report Size (8)
341            0x95, 0x01, //   Report Count (1)
342            0x81,
343            0x00, //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
344            0xC0, // End Collection
345        ];
346        assert_eq!(SystemControlReport::desc(), expected);
347    }
348
349    #[test]
350    fn test_system_control_serialize() {
351        let expected = &[4];
352        let report = SystemControlReport { usage_id: 4 };
353        let mut buf = [0; 64];
354        let result = serialize(&mut buf, report);
355        assert_eq!(result, expected);
356    }
357
358    #[test]
359    fn test_ctap_serialize() {
360        let expected = &[
361            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
362            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
363            1, 1, 1, 1, 1, 1,
364        ];
365        let report = CtapReport {
366            data_in: [1; 64],
367            data_out: [2; 64],
368        };
369        let mut buf = [0; 64];
370        let result = serialize(&mut buf, report);
371        assert_eq!(result, expected);
372    }
373}