1 /*
2 * Copyright (c) 2018 qianfan Zhao
3 * Copyright (c) 2018, 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <sample_usbd.h>
9
10 #include <string.h>
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/input/input.h>
16 #include <zephyr/sys/util.h>
17
18 #include <zephyr/usb/usbd.h>
19 #include <zephyr/usb/class/usbd_hid.h>
20
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
23
24 static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
25 static const uint8_t hid_report_desc[] = HID_MOUSE_REPORT_DESC(2);
26
27 #define MOUSE_BTN_LEFT 0
28 #define MOUSE_BTN_RIGHT 1
29
30 enum mouse_report_idx {
31 MOUSE_BTN_REPORT_IDX = 0,
32 MOUSE_X_REPORT_IDX = 1,
33 MOUSE_Y_REPORT_IDX = 2,
34 MOUSE_WHEEL_REPORT_IDX = 3,
35 MOUSE_REPORT_COUNT = 4,
36 };
37
38 K_MSGQ_DEFINE(mouse_msgq, MOUSE_REPORT_COUNT, 2, 1);
39 static bool mouse_ready;
40
input_cb(struct input_event * evt,void * user_data)41 static void input_cb(struct input_event *evt, void *user_data)
42 {
43 static uint8_t tmp[MOUSE_REPORT_COUNT];
44
45 ARG_UNUSED(user_data);
46
47 switch (evt->code) {
48 case INPUT_KEY_0:
49 WRITE_BIT(tmp[MOUSE_BTN_REPORT_IDX], MOUSE_BTN_LEFT, evt->value);
50 break;
51 case INPUT_KEY_1:
52 WRITE_BIT(tmp[MOUSE_BTN_REPORT_IDX], MOUSE_BTN_RIGHT, evt->value);
53 break;
54 case INPUT_KEY_2:
55 if (evt->value) {
56 tmp[MOUSE_X_REPORT_IDX] += 10U;
57 }
58
59 break;
60 case INPUT_KEY_3:
61 if (evt->value) {
62 tmp[MOUSE_Y_REPORT_IDX] += 10U;
63 }
64
65 break;
66 default:
67 LOG_INF("Unrecognized input code %u value %d",
68 evt->code, evt->value);
69 return;
70 }
71
72 if (k_msgq_put(&mouse_msgq, tmp, K_NO_WAIT) != 0) {
73 LOG_ERR("Failed to put new input event");
74 }
75
76 tmp[MOUSE_X_REPORT_IDX] = 0U;
77 tmp[MOUSE_Y_REPORT_IDX] = 0U;
78
79 }
80
81 INPUT_CALLBACK_DEFINE(NULL, input_cb, NULL);
82
mouse_iface_ready(const struct device * dev,const bool ready)83 static void mouse_iface_ready(const struct device *dev, const bool ready)
84 {
85 LOG_INF("HID device %s interface is %s",
86 dev->name, ready ? "ready" : "not ready");
87 mouse_ready = ready;
88 }
89
mouse_get_report(const struct device * dev,const uint8_t type,const uint8_t id,const uint16_t len,uint8_t * const buf)90 static int mouse_get_report(const struct device *dev,
91 const uint8_t type, const uint8_t id, const uint16_t len,
92 uint8_t *const buf)
93 {
94 LOG_WRN("Get Report not implemented, Type %u ID %u", type, id);
95
96 return 0;
97 }
98
99 struct hid_device_ops mouse_ops = {
100 .iface_ready = mouse_iface_ready,
101 .get_report = mouse_get_report,
102 };
103
main(void)104 int main(void)
105 {
106 struct usbd_context *sample_usbd;
107 const struct device *hid_dev;
108 int ret;
109
110 if (!gpio_is_ready_dt(&led0)) {
111 LOG_ERR("LED device %s is not ready", led0.port->name);
112 return 0;
113 }
114
115 ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT);
116 if (ret != 0) {
117 LOG_ERR("Failed to configure the LED pin, error: %d", ret);
118 return 0;
119 }
120
121 hid_dev = DEVICE_DT_GET_ONE(zephyr_hid_device);
122 if (!device_is_ready(hid_dev)) {
123 LOG_ERR("HID Device is not ready");
124 return -EIO;
125 }
126
127 ret = hid_device_register(hid_dev,
128 hid_report_desc, sizeof(hid_report_desc),
129 &mouse_ops);
130 if (ret != 0) {
131 LOG_ERR("Failed to register HID Device, %d", ret);
132 return ret;
133 }
134
135 sample_usbd = sample_usbd_init_device(NULL);
136 if (sample_usbd == NULL) {
137 LOG_ERR("Failed to initialize USB device");
138 return -ENODEV;
139 }
140
141 ret = usbd_enable(sample_usbd);
142 if (ret != 0) {
143 LOG_ERR("Failed to enable device support");
144 return ret;
145 }
146
147 LOG_DBG("USB device support enabled");
148
149 while (true) {
150 UDC_STATIC_BUF_DEFINE(report, MOUSE_REPORT_COUNT);
151
152 k_msgq_get(&mouse_msgq, &report, K_FOREVER);
153
154 if (!mouse_ready) {
155 LOG_INF("USB HID device is not ready");
156 continue;
157 }
158
159 ret = hid_device_submit_report(hid_dev, MOUSE_REPORT_COUNT, report);
160 if (ret) {
161 LOG_ERR("HID submit report error, %d", ret);
162 } else {
163 /* Toggle LED on sent report */
164 (void)gpio_pin_toggle(led0.port, led0.pin);
165 }
166 }
167
168 return 0;
169 }
170