1 /*
2  * Copyright (c) 2016-2018 Intel Corporation.
3  * Copyright (c) 2018-2021 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/init.h>
10 
11 #include <zephyr/usb/usb_device.h>
12 #include <zephyr/usb/class/usb_hid.h>
13 
14 #define LOG_LEVEL LOG_LEVEL_INF
15 LOG_MODULE_REGISTER(main);
16 
17 static bool configured;
18 static const struct device *hdev;
19 static struct k_work report_send;
20 static ATOMIC_DEFINE(hid_ep_in_busy, 1);
21 
22 #define HID_EP_BUSY_FLAG	0
23 #define REPORT_ID_1		0x01
24 #define REPORT_PERIOD		K_SECONDS(2)
25 
26 static struct report {
27 	uint8_t id;
28 	uint8_t value;
29 } __packed report_1 = {
30 	.id = REPORT_ID_1,
31 	.value = 0,
32 };
33 
34 static void report_event_handler(struct k_timer *dummy);
35 static K_TIMER_DEFINE(event_timer, report_event_handler, NULL);
36 
37 /*
38  * Simple HID Report Descriptor
39  * Report ID is present for completeness, although it can be omitted.
40  * Output of "usbhid-dump -d 2fe3:0006 -e descriptor":
41  *  05 01 09 00 A1 01 15 00    26 FF 00 85 01 75 08 95
42  *  01 09 00 81 02 C0
43  */
44 static const uint8_t hid_report_desc[] = {
45 	HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
46 	HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED),
47 	HID_COLLECTION(HID_COLLECTION_APPLICATION),
48 	HID_LOGICAL_MIN8(0x00),
49 	HID_LOGICAL_MAX16(0xFF, 0x00),
50 	HID_REPORT_ID(REPORT_ID_1),
51 	HID_REPORT_SIZE(8),
52 	HID_REPORT_COUNT(1),
53 	HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED),
54 	HID_INPUT(0x02),
55 	HID_END_COLLECTION,
56 };
57 
send_report(struct k_work * work)58 static void send_report(struct k_work *work)
59 {
60 	int ret, wrote;
61 
62 	if (!atomic_test_and_set_bit(hid_ep_in_busy, HID_EP_BUSY_FLAG)) {
63 		ret = hid_int_ep_write(hdev, (uint8_t *)&report_1,
64 				       sizeof(report_1), &wrote);
65 		if (ret != 0) {
66 			/*
67 			 * Do nothing and wait until host has reset the device
68 			 * and hid_ep_in_busy is cleared.
69 			 */
70 			LOG_ERR("Failed to submit report");
71 		} else {
72 			LOG_DBG("Report submitted");
73 		}
74 	} else {
75 		LOG_DBG("HID IN endpoint busy");
76 	}
77 }
78 
int_in_ready_cb(const struct device * dev)79 static void int_in_ready_cb(const struct device *dev)
80 {
81 	ARG_UNUSED(dev);
82 	if (!atomic_test_and_clear_bit(hid_ep_in_busy, HID_EP_BUSY_FLAG)) {
83 		LOG_WRN("IN endpoint callback without preceding buffer write");
84 	}
85 }
86 
87 /*
88  * On Idle callback is available here as an example even if actual use is
89  * very limited. In contrast to report_event_handler(),
90  * report value is not incremented here.
91  */
on_idle_cb(const struct device * dev,uint16_t report_id)92 static void on_idle_cb(const struct device *dev, uint16_t report_id)
93 {
94 	LOG_DBG("On idle callback");
95 	k_work_submit(&report_send);
96 }
97 
report_event_handler(struct k_timer * dummy)98 static void report_event_handler(struct k_timer *dummy)
99 {
100 	/* Increment reported data */
101 	report_1.value++;
102 	k_work_submit(&report_send);
103 }
104 
protocol_cb(const struct device * dev,uint8_t protocol)105 static void protocol_cb(const struct device *dev, uint8_t protocol)
106 {
107 	LOG_INF("New protocol: %s", protocol == HID_PROTOCOL_BOOT ?
108 		"boot" : "report");
109 }
110 
111 static const struct hid_ops ops = {
112 	.int_in_ready = int_in_ready_cb,
113 	.on_idle = on_idle_cb,
114 	.protocol_change = protocol_cb,
115 };
116 
status_cb(enum usb_dc_status_code status,const uint8_t * param)117 static void status_cb(enum usb_dc_status_code status, const uint8_t *param)
118 {
119 	switch (status) {
120 	case USB_DC_RESET:
121 		configured = false;
122 		break;
123 	case USB_DC_CONFIGURED:
124 		if (!configured) {
125 			int_in_ready_cb(hdev);
126 			configured = true;
127 		}
128 		break;
129 	case USB_DC_SOF:
130 		break;
131 	default:
132 		LOG_DBG("status %u unhandled", status);
133 		break;
134 	}
135 }
136 
main(void)137 int main(void)
138 {
139 	int ret;
140 
141 	hdev = device_get_binding("HID_0");
142 	if (hdev == NULL) {
143 		LOG_ERR("Cannot get USB HID Device");
144 		return -ENODEV;
145 	}
146 
147 	LOG_INF("HID Device: dev %p", hdev);
148 
149 	usb_hid_register_device(hdev, hid_report_desc, sizeof(hid_report_desc),
150 				&ops);
151 
152 	atomic_set_bit(hid_ep_in_busy, HID_EP_BUSY_FLAG);
153 	k_timer_start(&event_timer, REPORT_PERIOD, REPORT_PERIOD);
154 
155 	if (usb_hid_set_proto_code(hdev, HID_BOOT_IFACE_CODE_NONE)) {
156 		LOG_WRN("Failed to set Protocol Code");
157 	}
158 
159 	ret = usb_hid_init(hdev);
160 	if (ret != 0) {
161 		return ret;
162 	}
163 
164 	LOG_INF("Starting application");
165 
166 	ret = usb_enable(status_cb);
167 	if (ret != 0) {
168 		LOG_ERR("Failed to enable USB");
169 		return ret;
170 	}
171 
172 	k_work_init(&report_send, send_report);
173 
174 	return 0;
175 }
176