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