ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_host_keyboard_device.c
Go to the documentation of this file.
1
25
26#include <stdint.h>
27#include <string.h>
28
29#include "ra8_board_ek_ra8d2.h"
30#include "ra8_err.h"
31#include "ra8_usb.h"
33
34#ifndef RA8_OFF_TARGET
35#include "tx_api.h"
36#include "ux_api.h"
37#include "ux_dcd_ra8_usb.h"
38#include "ux_device_class_hid.h"
39#include "ux_device_stack.h"
40
41/* -------------------------------------------------------------------------- */
42/* Device-worker progress markers */
43/* -------------------------------------------------------------------------- */
44
56
57/* USBX LANGID descriptor 0x0409 (English-US), little-endian byte pair. */
58typedef enum : uint8_t {
62
63/* -------------------------------------------------------------------------- */
64/* Typed keycodes the fake keyboard "types" */
65/* -------------------------------------------------------------------------- */
66
68static const uint8_t s_kbd_keys[k_hid_nkeys] = {
69 (uint8_t)k_hid_kc_r,
70 (uint8_t)k_hid_kc_a,
71 (uint8_t)k_hid_kc_8,
72 (uint8_t)k_hid_kc_d,
73 (uint8_t)k_hid_kc_2,
74};
75
76/* -------------------------------------------------------------------------- */
77/* ThreadX worker + USBX pool storage */
78/* -------------------------------------------------------------------------- */
79
87
94
101
108static UX_SLAVE_CLASS_HID* s_hid_class = UX_NULL;
109
110/* -------------------------------------------------------------------------- */
111/* J-Link probes (device side) */
112/* -------------------------------------------------------------------------- */
113
115static volatile uint32_t s_dbg_dev_sent;
117static volatile uint32_t s_dbg_dev_step;
119static volatile uint32_t s_dbg_dev_err;
120
121/* -------------------------------------------------------------------------- */
122/* HID Report Descriptor (vendor-defined, one 8-byte input report) */
123/* -------------------------------------------------------------------------- */
124
125/* USB HID boot-keyboard report descriptor (HID 1.11 Appendix B.1), input-only
126 * variant (no LED output report, so no OUT endpoint / SET_REPORT is needed):
127 * an 8-byte input report [modifier][reserved][keycode x6]. 45 bytes (0x2D). The
128 * host enumerates this as a real boot keyboard (interface subclass 1 /
129 * protocol 1) and decodes the keycodes in bytes 2.. back to ASCII. */
130static UCHAR s_report_descriptor[] = {
131 0x05U, 0x01U, /* Usage Page (Generic Desktop) */
132 0x09U, 0x06U, /* Usage (Keyboard) */
133 0xA1U, 0x01U, /* Collection (Application) */
134 0x05U, 0x07U, /* Usage Page (Keyboard/Keypad) */
135 0x19U, 0xE0U, /* Usage Minimum (Left Control) */
136 0x29U, 0xE7U, /* Usage Maximum (Right GUI) */
137 0x15U, 0x00U, /* Logical Minimum (0) */
138 0x25U, 0x01U, /* Logical Maximum (1) */
139 0x75U, 0x01U, /* Report Size (1) */
140 0x95U, 0x08U, /* Report Count (8) -- modifier bits */
141 0x81U, 0x02U, /* Input (Data,Var,Abs) */
142 0x95U, 0x01U, /* Report Count (1) */
143 0x75U, 0x08U, /* Report Size (8) -- reserved byte */
144 0x81U, 0x01U, /* Input (Const) */
145 0x95U, 0x06U, /* Report Count (6) -- key array */
146 0x75U, 0x08U, /* Report Size (8) */
147 0x15U, 0x00U, /* Logical Minimum (0) */
148 0x25U, 0x65U, /* Logical Maximum (101) */
149 0x05U, 0x07U, /* Usage Page (Keyboard/Keypad) */
150 0x19U, 0x00U, /* Usage Minimum (0) */
151 0x29U, 0x65U, /* Usage Maximum (101) */
152 0x81U, 0x00U, /* Input (Data,Array) -- 6 keycodes */
153 0xC0U, /* End Collection */
154};
155
156/* -------------------------------------------------------------------------- */
157/* USB descriptors (HID: one interface, one interrupt-IN endpoint) */
158/* -------------------------------------------------------------------------- */
159
160/* HID config: one HID interface (class 0x03, no boot subclass), one
161 * interrupt-IN endpoint EP1 IN (64-byte MPS), no OUT endpoint. Total config
162 * blob = 9 (config) + 9 (interface) + 9 (HID class) + 7 (EP IN) = 34 = 0x22.
163 * Layout per USB 2.0 sec 9.6 + HID 1.11 sec 6.2.1. PID 0x0018 marks the HID
164 * self-test identity. */
165static UCHAR s_device_framework_fs[] = {
166 /* Device descriptor (USB 2.0 sec 9.6.1) -- 18 bytes. */
167 0x12U,
168 0x01U,
169 0x00U,
170 0x02U,
171 0x00U,
172 0x00U,
173 0x00U,
174 0x40U,
175 0x09U,
176 0x12U,
177 0x18U, /* PID = 0x0018 (pid.codes test). */
178 0x00U,
179 0x00U,
180 0x01U,
181 0x01U,
182 0x02U,
183 0x03U,
184 0x01U,
185 /* Configuration descriptor (34 bytes total = 0x22). */
186 0x09U,
187 0x02U,
188 0x22U,
189 0x00U,
190 0x01U,
191 0x01U,
192 0x00U,
193 0x80U,
194 0x32U,
195 /* Interface descriptor -- HID, boot subclass (1), keyboard protocol (1). */
196 0x09U,
197 0x04U,
198 0x00U,
199 0x00U,
200 0x01U,
201 0x03U,
202 0x01U, /* bInterfaceSubClass = 1 (Boot) */
203 0x01U, /* bInterfaceProtocol = 1 (Keyboard) */
204 0x00U,
205 /* HID class descriptor (HID 1.11 sec 6.2.1) -- 9 bytes. bcdHID 0x0111,
206 one report descriptor of sizeof(s_report_descriptor) = 45 (0x2D). */
207 0x09U,
208 0x21U,
209 0x11U,
210 0x01U,
211 0x00U,
212 0x01U,
213 0x22U,
214 0x2DU, /* wDescriptorLength = 45 (boot-keyboard report descriptor) */
215 0x00U,
216 /* Interrupt-IN endpoint (EP1 IN, 64-byte MPS, 1 ms poll). */
217 0x07U,
218 0x05U,
219 0x81U,
220 0x03U,
221 0x40U,
222 0x00U,
223 0x01U,
224};
225
233static UCHAR s_string_framework[] = {
234 /* idx 1: "Brighton Sikarskie". */
235 0x09U,
236 0x04U,
237 0x01U,
238 0x12U,
239 'B',
240 'r',
241 'i',
242 'g',
243 'h',
244 't',
245 'o',
246 'n',
247 ' ',
248 'S',
249 'i',
250 'k',
251 'a',
252 'r',
253 's',
254 'k',
255 'i',
256 'e',
257 /* idx 2: "RA8D2 HID TEST". */
258 0x09U,
259 0x04U,
260 0x02U,
261 0x0EU,
262 'R',
263 'A',
264 '8',
265 'D',
266 '2',
267 ' ',
268 'H',
269 'I',
270 'D',
271 ' ',
272 'T',
273 'E',
274 'S',
275 'T',
276 /* idx 3: serial. */
277 0x09U,
278 0x04U,
279 0x03U,
280 0x08U,
281 '0',
282 '0',
283 '0',
284 '0',
285 '0',
286 '0',
287 '1',
288 '3',
289};
290
297
298/* -------------------------------------------------------------------------- */
299/* Shared HID report pattern */
300/* -------------------------------------------------------------------------- */
301
302void hid_fill_report_body(uint8_t* out, uint32_t len)
303{
304 /* Boot-keyboard report: byte 1 = reserved, bytes 2.. = up to six keycodes
305 * (the typed "RA8D2"), the remainder 0 (no key). Byte 0 (modifier) is set by
306 * the caller. Deterministic, so the host computes the same body to verify. */
307 for (uint32_t i = (uint32_t)k_hid_body_idx; i < len; i++) {
308 out[i] = 0U;
309 }
310 for (uint32_t i = 0U; i < (uint32_t)k_hid_nkeys; i++) {
311 const uint32_t idx = (uint32_t)k_hid_key0_idx + i;
312 if (idx < len) {
313 out[idx] = s_kbd_keys[i];
314 }
315 }
316}
317
318/* -------------------------------------------------------------------------- */
319/* HID activate / deactivate callbacks */
320/* -------------------------------------------------------------------------- */
321
340static VOID hid_activate(VOID* hid_instance)
341{
342 s_hid_class = (UX_SLAVE_CLASS_HID*)hid_instance;
343 if (_ux_system_slave != UX_NULL) {
344 _ux_system_slave->ux_system_slave_device.ux_slave_device_state =
345 (unsigned long)UX_DEVICE_CONFIGURED;
346 }
347 (void)tx_semaphore_put(&s_usb_host_keyboard_hid_active_sem);
348}
349
363static VOID hid_deactivate(VOID* hid_instance)
364{
365 (void)hid_instance;
366 s_hid_class = UX_NULL;
367}
368
369/* -------------------------------------------------------------------------- */
370/* Device side: USBX HID interrupt-IN reports */
371/* -------------------------------------------------------------------------- */
372
390{
391 if (_ux_system_initialize(s_usbx_pool, k_hid_usbx_pool_bytes, UX_NULL, 0) != UX_SUCCESS) {
392 return UX_ERROR;
393 }
394 return _ux_device_stack_initialize((UCHAR*)UX_NULL,
395 0,
397 sizeof(s_device_framework_fs),
399 sizeof(s_string_framework),
402 UX_NULL);
403}
404
426static UINT hid_get_callback(UX_SLAVE_CLASS_HID* hid, UX_SLAVE_CLASS_HID_EVENT* hid_event)
427{
428 (void)hid;
429 hid_event->ux_device_class_hid_event_length = (ULONG)k_hid_report_len;
430 hid_event->ux_device_class_hid_event_report_id = 0UL;
431 hid_event->ux_device_class_hid_event_report_type = (ULONG)UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT;
432 hid_fill_report_body(hid_event->ux_device_class_hid_event_buffer, (uint32_t)k_hid_report_len);
433 hid_event->ux_device_class_hid_event_buffer[k_hid_seq_idx] = 0U;
434 return UX_SUCCESS;
435}
436
456{
457 UX_SLAVE_CLASS_HID_PARAMETER hid_params = {
458 .ux_slave_class_hid_instance_activate = hid_activate,
459 .ux_slave_class_hid_instance_deactivate = hid_deactivate,
460 .ux_device_class_hid_parameter_report_address = s_report_descriptor,
461 .ux_device_class_hid_parameter_report_id = 0UL,
462 .ux_device_class_hid_parameter_report_length = (ULONG)sizeof(s_report_descriptor),
463 .ux_device_class_hid_parameter_callback = UX_NULL,
464 .ux_device_class_hid_parameter_get_callback = hid_get_callback,
465 };
466 static UCHAR s_class_name[] = "ux_slave_class_hid";
467
468 return _ux_device_stack_class_register(s_class_name,
469 _ux_device_class_hid_entry,
470 1,
471 0,
472 &hid_params);
473}
474
494static void hid_send_iter(uint32_t* seq)
495{
496 if (_ux_system_slave != UX_NULL) {
497 _ux_system_slave->ux_system_slave_device.ux_slave_device_state =
498 (unsigned long)UX_DEVICE_CONFIGURED;
499 }
500 UX_SLAVE_CLASS_HID_EVENT ev;
501 (void)memset(&ev, 0, sizeof(ev));
502 ev.ux_device_class_hid_event_length = (ULONG)k_hid_report_len;
503 ev.ux_device_class_hid_event_report_id = 0UL;
504 ev.ux_device_class_hid_event_report_type = (ULONG)UX_DEVICE_CLASS_HID_REPORT_TYPE_INPUT;
505 hid_fill_report_body(ev.ux_device_class_hid_event_buffer, (uint32_t)k_hid_report_len);
506 ev.ux_device_class_hid_event_buffer[k_hid_seq_idx] = (UCHAR)(*seq & (uint32_t)k_hid_byte_mask);
507 if (_ux_device_class_hid_event_set(s_hid_class, &ev) == UX_SUCCESS) {
508 (*seq)++;
511 }
512 tx_thread_sleep(1U);
513}
514
516{
517 (void)arg;
518
519 UINT ux = hid_usbx_stack_up();
520 if (ux != UX_SUCCESS) {
521 s_dbg_dev_err = (uint32_t)ux;
522 return;
523 }
525 ux = hid_class_register();
526 if (ux != UX_SUCCESS) {
527 s_dbg_dev_err = (uint32_t)ux;
528 return;
529 }
532 if (e != k_ra8_ok) {
533 s_dbg_dev_err = (uint32_t)e;
534 return;
535 }
538 if (e != k_ra8_ok) {
539 s_dbg_dev_err = (uint32_t)e;
540 return;
541 }
543
544 uint32_t seq = 0U;
545 while (1) {
546 if (s_hid_class == UX_NULL) {
547 (void)tx_semaphore_get(&s_usb_host_keyboard_hid_active_sem, TX_WAIT_FOREVER);
548 continue;
549 }
551 hid_send_iter(&seq);
552 }
553}
554
570
571#endif /* !RA8_OFF_TARGET */
static TX_THREAD s_device_thread
ThreadX TCB for the USBX device-side worker thread.
Definition main.c:164
static UCHAR s_string_framework[]
USBX string descriptor table (vendor / product / serial).
Definition main.c:299
static UCHAR s_usbx_pool[k_wlun_usbx_pool_bytes]
USBX memory pool (USBX uses tx_byte_pool internally).
Definition main.c:193
usb_langid_byte_t
Definition main.c:358
@ k_usb_langid_en_us_lo
LANGID 0x0409 low byte.
Definition main.c:359
@ k_usb_langid_en_us_hi
LANGID 0x0409 high byte.
Definition main.c:360
static UCHAR s_device_framework_fs[]
Definition main.c:234
static UCHAR s_language_id_framework[]
USBX language-id table – US English.
Definition main.c:368
static UCHAR s_device_stack[k_wlun_thread_stack]
Stack backing storage for s_device_thread.
Definition main.c:171
static volatile uint32_t s_dbg_dev_step
Device worker progress: 1 stack, 2 class, 3 dcd, 4 attach, 5 parked.
Definition main.c:219
static volatile uint32_t s_dbg_dev_err
Device worker first failing return code (0 = none).
Definition main.c:221
static CHAR s_device_thread_name[]
Definition main.c:201
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
Native USB controller driver public API (device + host modes).
ra8_err_t ra8_usb_device_attach(ra8_usb_speed_t speed, bool attached)
Raise / drop the D+ pull-up to advertise the device to the host.
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
#define tx_thread_create
#define tx_thread_sleep
#define TX_NO_TIME_SLICE
char CHAR
ThreadX-compatible CHAR (host stub).
#define TX_AUTO_START
#define TX_WAIT_FOREVER
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
Opaque thread stand-in for the host build.
void usb_host_keyboard_device_thread_create(void)
Create + auto-start the USBX HID device worker thread.
static const uint8_t s_kbd_keys[k_hid_nkeys]
Keycodes the fake keyboard "types": R, A, 8, D, 2.
VOID hid_device_worker(ULONG arg)
Device-side worker: bring the HID device up, then send reports.
hid_dev_step_t
J-Link probe values marking device-worker bring-up progress.
@ k_hid_dev_step_stack
USBX system + device stack up.
@ k_hid_dev_step_dcd
DCD bridge initialized.
@ k_hid_dev_step_send
Report-send loop running.
@ k_hid_dev_step_attach
Device attached (DPRPU).
@ k_hid_dev_step_class
HID class registered.
static VOID hid_activate(VOID *hid_instance)
HID activate callback.
void hid_fill_report_body(uint8_t *out, uint32_t len)
Fill the fixed body of a HID report (bytes 1..len-1).
static UINT hid_class_register(void)
Register the HID class against configuration 1, interface 0.
static VOID hid_deactivate(VOID *hid_instance)
HID deactivate callback.
static UINT hid_usbx_stack_up(void)
Bring USBX system + device stack up with the HID framework.
static UCHAR s_report_descriptor[]
static void hid_send_iter(uint32_t *seq)
One device send iteration: queue a fresh input report.
static volatile uint32_t s_dbg_dev_sent
Device-side report-queue successes (one hid_event_set each).
static UINT hid_get_callback(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_EVENT *hid_event)
HID GET_REPORT control-pipe callback: hand back a neutral report.
static UX_SLAVE_CLASS_HID * s_hid_class
Active HID class instance, captured by the activate callback.
Shared seam between usb_host_keyboard main.c and its sibling TUs.
VOID hid_device_worker(ULONG arg)
Device-side worker: bring the HID device up, then send reports.
@ k_hid_report_len
Vendor input report width (bytes).
@ k_hid_nkeys
Keycodes typed ("RA8D2").
@ k_hid_key0_idx
Boot-keyboard first-keycode byte.
@ k_hid_body_idx
Report body starts at byte 1.
@ k_hid_byte_mask
Byte mask.
@ k_hid_seq_idx
Report byte 0: modifier / rolling seq.
@ k_hid_kc_a
Keycode for 'a' / 'A'.
@ k_hid_kc_d
Keycode for 'd' / 'D'.
@ k_hid_kc_r
Keycode for 'r' / 'R'.
@ k_hid_kc_8
Keycode for '8'.
@ k_hid_kc_2
Keycode for '2'.
TX_SEMAPHORE s_usb_host_keyboard_hid_active_sem
Activation semaphore shared by the device worker and main.c.
Definition main.c:163
@ k_hid_thread_stack
Device worker stack (bytes).
@ k_hid_usbx_pool_bytes
USBX memory pool (bytes).
@ k_hid_dev_priority
Device bring-up worker priority.
USBX device-controller-driver (DCD) bridge to ra8_usb.
ra8_err_t ux_dcd_ra8_usb_initialize(ra8_usb_speed_t speed)
Register the ra8_usb bridge as the active USBX DCD.