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}