1 /*
2 * Copyright (c) 2024, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbd_core.h"
7 #include "usbd_hid.h"
8
9 /*!< endpoint address */
10 #define HID_INT_EP 0x81
11 #define HID_INT_EP_SIZE 4
12 #define HID_INT_EP_INTERVAL 1
13
14 #define USBD_VID 0xffff
15 #define USBD_PID 0xffff
16 #define USBD_MAX_POWER 100
17 #define USBD_LANGID_STRING 1033
18
19 /*!< config descriptor size */
20 #define USB_HID_CONFIG_DESC_SIZ 34
21 /*!< report descriptor size */
22 #define HID_MOUSE_REPORT_DESC_SIZE 74
23
24 #ifdef CONFIG_USBDEV_ADVANCE_DESC
25 static const uint8_t device_descriptor[] = {
26 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
27 };
28
29 static const uint8_t config_descriptor[] = {
30 USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_REMOTE_WAKEUP | USB_CONFIG_SELF_POWERED, USBD_MAX_POWER),
31
32 /************** Descriptor of Joystick Mouse interface ****************/
33 /* 09 */
34 0x09, /* bLength: Interface Descriptor size */
35 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
36 0x00, /* bInterfaceNumber: Number of Interface */
37 0x00, /* bAlternateSetting: Alternate setting */
38 0x01, /* bNumEndpoints */
39 0x03, /* bInterfaceClass: HID */
40 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
41 0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
42 0, /* iInterface: Index of string descriptor */
43 /******************** Descriptor of Joystick Mouse HID ********************/
44 /* 18 */
45 0x09, /* bLength: HID Descriptor size */
46 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
47 0x11, /* bcdHID: HID Class Spec release number */
48 0x01,
49 0x00, /* bCountryCode: Hardware target country */
50 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
51 0x22, /* bDescriptorType */
52 HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
53 0x00,
54 /******************** Descriptor of Mouse endpoint ********************/
55 /* 27 */
56 0x07, /* bLength: Endpoint Descriptor size */
57 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
58 HID_INT_EP, /* bEndpointAddress: Endpoint Address (IN) */
59 0x03, /* bmAttributes: Interrupt endpoint */
60 HID_INT_EP_SIZE, /* wMaxPacketSize: 4 Byte max */
61 0x00,
62 HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
63 /* 34 */
64 };
65
66 static const uint8_t device_quality_descriptor[] = {
67 ///////////////////////////////////////
68 /// device qualifier descriptor
69 ///////////////////////////////////////
70 0x0a,
71 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
72 0x00,
73 0x02,
74 0x00,
75 0x00,
76 0x00,
77 0x40,
78 0x00,
79 0x00,
80 };
81
82 static const char *string_descriptors[] = {
83 (const char[]){ 0x09, 0x04 }, /* Langid */
84 "CherryUSB", /* Manufacturer */
85 "CherryUSB HID DEMO", /* Product */
86 "2022123456", /* Serial Number */
87 };
88
device_descriptor_callback(uint8_t speed)89 static const uint8_t *device_descriptor_callback(uint8_t speed)
90 {
91 return device_descriptor;
92 }
93
config_descriptor_callback(uint8_t speed)94 static const uint8_t *config_descriptor_callback(uint8_t speed)
95 {
96 return config_descriptor;
97 }
98
device_quality_descriptor_callback(uint8_t speed)99 static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
100 {
101 return device_quality_descriptor;
102 }
103
string_descriptor_callback(uint8_t speed,uint8_t index)104 static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
105 {
106 if (index > 3) {
107 return NULL;
108 }
109 return string_descriptors[index];
110 }
111
112 const struct usb_descriptor hid_descriptor = {
113 .device_descriptor_callback = device_descriptor_callback,
114 .config_descriptor_callback = config_descriptor_callback,
115 .device_quality_descriptor_callback = device_quality_descriptor_callback,
116 .string_descriptor_callback = string_descriptor_callback
117 };
118 #else
119 /*!< global descriptor */
120 const uint8_t hid_descriptor[] = {
121 USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
122 USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_REMOTE_WAKEUP | USB_CONFIG_SELF_POWERED, USBD_MAX_POWER),
123
124 /************** Descriptor of Joystick Mouse interface ****************/
125 /* 09 */
126 0x09, /* bLength: Interface Descriptor size */
127 USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
128 0x00, /* bInterfaceNumber: Number of Interface */
129 0x00, /* bAlternateSetting: Alternate setting */
130 0x01, /* bNumEndpoints */
131 0x03, /* bInterfaceClass: HID */
132 0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
133 0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
134 0, /* iInterface: Index of string descriptor */
135 /******************** Descriptor of Joystick Mouse HID ********************/
136 /* 18 */
137 0x09, /* bLength: HID Descriptor size */
138 HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
139 0x11, /* bcdHID: HID Class Spec release number */
140 0x01,
141 0x00, /* bCountryCode: Hardware target country */
142 0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
143 0x22, /* bDescriptorType */
144 HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
145 0x00,
146 /******************** Descriptor of Mouse endpoint ********************/
147 /* 27 */
148 0x07, /* bLength: Endpoint Descriptor size */
149 USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
150 HID_INT_EP, /* bEndpointAddress: Endpoint Address (IN) */
151 0x03, /* bmAttributes: Interrupt endpoint */
152 HID_INT_EP_SIZE, /* wMaxPacketSize: 4 Byte max */
153 0x00,
154 HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
155 /* 34 */
156 ///////////////////////////////////////
157 /// string0 descriptor
158 ///////////////////////////////////////
159 USB_LANGID_INIT(USBD_LANGID_STRING),
160 ///////////////////////////////////////
161 /// string1 descriptor
162 ///////////////////////////////////////
163 0x14, /* bLength */
164 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
165 'C', 0x00, /* wcChar0 */
166 'h', 0x00, /* wcChar1 */
167 'e', 0x00, /* wcChar2 */
168 'r', 0x00, /* wcChar3 */
169 'r', 0x00, /* wcChar4 */
170 'y', 0x00, /* wcChar5 */
171 'U', 0x00, /* wcChar6 */
172 'S', 0x00, /* wcChar7 */
173 'B', 0x00, /* wcChar8 */
174 ///////////////////////////////////////
175 /// string2 descriptor
176 ///////////////////////////////////////
177 0x26, /* bLength */
178 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
179 'C', 0x00, /* wcChar0 */
180 'h', 0x00, /* wcChar1 */
181 'e', 0x00, /* wcChar2 */
182 'r', 0x00, /* wcChar3 */
183 'r', 0x00, /* wcChar4 */
184 'y', 0x00, /* wcChar5 */
185 'U', 0x00, /* wcChar6 */
186 'S', 0x00, /* wcChar7 */
187 'B', 0x00, /* wcChar8 */
188 ' ', 0x00, /* wcChar9 */
189 'H', 0x00, /* wcChar10 */
190 'I', 0x00, /* wcChar11 */
191 'D', 0x00, /* wcChar12 */
192 ' ', 0x00, /* wcChar13 */
193 'D', 0x00, /* wcChar14 */
194 'E', 0x00, /* wcChar15 */
195 'M', 0x00, /* wcChar16 */
196 'O', 0x00, /* wcChar17 */
197 ///////////////////////////////////////
198 /// string3 descriptor
199 ///////////////////////////////////////
200 0x16, /* bLength */
201 USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
202 '2', 0x00, /* wcChar0 */
203 '0', 0x00, /* wcChar1 */
204 '2', 0x00, /* wcChar2 */
205 '2', 0x00, /* wcChar3 */
206 '1', 0x00, /* wcChar4 */
207 '2', 0x00, /* wcChar5 */
208 '3', 0x00, /* wcChar6 */
209 '4', 0x00, /* wcChar7 */
210 '5', 0x00, /* wcChar8 */
211 '6', 0x00, /* wcChar9 */
212 #ifdef CONFIG_USB_HS
213 ///////////////////////////////////////
214 /// device qualifier descriptor
215 ///////////////////////////////////////
216 0x0a,
217 USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
218 0x00,
219 0x02,
220 0x00,
221 0x00,
222 0x00,
223 0x40,
224 0x00,
225 0x00,
226 #endif
227 0x00
228 };
229 #endif
230
231 /*!< hid mouse report descriptor */
232 static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
233 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
234 0x09, 0x02, // USAGE (Mouse)
235 0xA1, 0x01, // COLLECTION (Application)
236 0x09, 0x01, // USAGE (Pointer)
237
238 0xA1, 0x00, // COLLECTION (Physical)
239 0x05, 0x09, // USAGE_PAGE (Button)
240 0x19, 0x01, // USAGE_MINIMUM (Button 1)
241 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
242
243 0x15, 0x00, // LOGICAL_MINIMUM (0)
244 0x25, 0x01, // LOGICAL_MAXIMUM (1)
245 0x95, 0x03, // REPORT_COUNT (3)
246 0x75, 0x01, // REPORT_SIZE (1)
247
248 0x81, 0x02, // INPUT (Data,Var,Abs)
249 0x95, 0x01, // REPORT_COUNT (1)
250 0x75, 0x05, // REPORT_SIZE (5)
251 0x81, 0x01, // INPUT (Cnst,Var,Abs)
252
253 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
254 0x09, 0x30, // USAGE (X)
255 0x09, 0x31, // USAGE (Y)
256 0x09, 0x38,
257
258 0x15, 0x81, // LOGICAL_MINIMUM (-127)
259 0x25, 0x7F, // LOGICAL_MAXIMUM (127)
260 0x75, 0x08, // REPORT_SIZE (8)
261 0x95, 0x03, // REPORT_COUNT (2)
262
263 0x81, 0x06, // INPUT (Data,Var,Rel)
264 0xC0, 0x09,
265 0x3c, 0x05,
266 0xff, 0x09,
267
268 0x01, 0x15,
269 0x00, 0x25,
270 0x01, 0x75,
271 0x01, 0x95,
272
273 0x02, 0xb1,
274 0x22, 0x75,
275 0x06, 0x95,
276 0x01, 0xb1,
277
278 0x01, 0xc0 // END_COLLECTION
279 };
280
281 /*!< mouse report struct */
282 struct hid_mouse {
283 uint8_t buttons;
284 int8_t x;
285 int8_t y;
286 int8_t wheel;
287 };
288
289 /*!< mouse report */
290 static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct hid_mouse mouse_cfg;
291
292 #define HID_STATE_IDLE 0
293 #define HID_STATE_BUSY 1
294
295 /*!< hid state ! Data can be sent only when state is idle */
296 static volatile uint8_t hid_state = HID_STATE_IDLE;
297
usbd_event_handler(uint8_t busid,uint8_t event)298 static void usbd_event_handler(uint8_t busid, uint8_t event)
299 {
300 switch (event) {
301 case USBD_EVENT_RESET:
302 break;
303 case USBD_EVENT_CONNECTED:
304 break;
305 case USBD_EVENT_DISCONNECTED:
306 break;
307 case USBD_EVENT_RESUME:
308 break;
309 case USBD_EVENT_SUSPEND:
310 break;
311 case USBD_EVENT_CONFIGURED:
312 hid_state = HID_STATE_IDLE;
313 break;
314 case USBD_EVENT_SET_REMOTE_WAKEUP:
315 break;
316 case USBD_EVENT_CLR_REMOTE_WAKEUP:
317 break;
318
319 default:
320 break;
321 }
322 }
323
324 /* function ------------------------------------------------------------------*/
usbd_hid_int_callback(uint8_t busid,uint8_t ep,uint32_t nbytes)325 static void usbd_hid_int_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
326 {
327 hid_state = HID_STATE_IDLE;
328 }
329
330 /*!< endpoint call back */
331 static struct usbd_endpoint hid_in_ep = {
332 .ep_cb = usbd_hid_int_callback,
333 .ep_addr = HID_INT_EP
334 };
335
336 static struct usbd_interface intf0;
337
hid_mouse_init(uint8_t busid,uintptr_t reg_base)338 void hid_mouse_init(uint8_t busid, uintptr_t reg_base)
339 {
340 #ifdef CONFIG_USBDEV_ADVANCE_DESC
341 usbd_desc_register(busid, &hid_descriptor);
342 #else
343 usbd_desc_register(busid, hid_descriptor);
344 #endif
345 usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_mouse_report_desc, HID_MOUSE_REPORT_DESC_SIZE));
346 usbd_add_endpoint(busid, &hid_in_ep);
347
348 usbd_initialize(busid, reg_base, usbd_event_handler);
349
350 /*!< init mouse report data */
351 mouse_cfg.buttons = 0;
352 mouse_cfg.wheel = 0;
353 mouse_cfg.x = 0;
354 mouse_cfg.y = 0;
355 }
356
357 #define CURSOR_STEP 2U
358 #define CURSOR_WIDTH 20U
359
draw_circle(uint8_t * buf)360 void draw_circle(uint8_t *buf)
361 {
362 static int32_t move_cnt = 0;
363 static uint8_t step_x_y = 0;
364 static int8_t x = 0, y = 0;
365
366 move_cnt++;
367 if (move_cnt > CURSOR_WIDTH) {
368 step_x_y++;
369 step_x_y = step_x_y % 4;
370 move_cnt = 0;
371 }
372 switch (step_x_y) {
373 case 0: {
374 y = 0;
375 x = CURSOR_STEP;
376
377 } break;
378
379 case 1: {
380 x = 0;
381 y = CURSOR_STEP;
382
383 } break;
384
385 case 2: {
386 y = 0;
387 x = (int8_t)(-CURSOR_STEP);
388
389 } break;
390
391 case 3: {
392 x = 0;
393 y = (int8_t)(-CURSOR_STEP);
394
395 } break;
396 }
397
398 buf[0] = 0;
399 buf[1] = x;
400 buf[2] = y;
401 buf[3] = 0;
402 }
403
404 /* https://cps-check.com/cn/polling-rate-check */
hid_mouse_test(uint8_t busid)405 void hid_mouse_test(uint8_t busid)
406 {
407 static uint32_t count = 1000;
408 int ret;
409
410 if(usb_device_is_configured(busid) == false) {
411 return;
412 }
413
414 // if (gpio_read_pin(GPIO_PIN) == 1) {
415 // ret = usbd_send_remote_wakeup(busid);
416 // if (ret < 0) {
417 // return;
418 // }
419 // count = 5000;
420 // }
421
422 while (count) {
423 draw_circle((uint8_t *)&mouse_cfg);
424 hid_state = HID_STATE_BUSY;
425 usbd_ep_start_write(busid, HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
426 while (hid_state == HID_STATE_BUSY) {
427 }
428
429 count--;
430 }
431 }
432