diff options
Diffstat (limited to 'cmd/harness')
-rw-r--r-- | cmd/harness/main.c | 48 | ||||
-rw-r--r-- | cmd/harness/usb_keyboard.c | 113 | ||||
-rw-r--r-- | cmd/harness/usb_keyboard.h | 17 |
3 files changed, 178 insertions, 0 deletions
diff --git a/cmd/harness/main.c b/cmd/harness/main.c new file mode 100644 index 0000000..1fd9f8c --- /dev/null +++ b/cmd/harness/main.c @@ -0,0 +1,48 @@ +/* main.c - Main entry point and event loop for sbc-harness + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +/* newlib */ +#include <string.h> /* for strlen() */ + +/* pico-sdk */ +#include "pico/stdlib.h" + +/* local */ +#include "coroutine.h" +#include "usb_common.h" +#include "usb_keyboard.h" + +COROUTINE hello_world_cr(void *_chan) { + const char *msg = "Hello world!\n"; + usb_keyboard_rpc_t *chan = _chan; + cr_begin(); + + for (size_t i = 0;; i = (i+1) % strlen(msg)) { + cr_rpc_req(chan, NULL, msg[i]); + } + + cr_end(); +} + +int main() { + /* initialization */ + stdio_uart_init(); + //gpio_init(PICO_DEFAULT_LED_PIN); + //gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + usb_common_earlyinit(); + usb_keyboard_init(); + usb_common_lateinit(); + + /* set up coroutines */ + coroutine_add(usb_common_cr, NULL); + usb_keyboard_rpc_t keyboard_chan = {0}; + coroutine_add(usb_keyboard_cr, &keyboard_chan); + coroutine_add(hello_world_cr, &keyboard_chan); + + /* Event loop. */ + coroutine_main(); +} diff --git a/cmd/harness/usb_keyboard.c b/cmd/harness/usb_keyboard.c new file mode 100644 index 0000000..1989b35 --- /dev/null +++ b/cmd/harness/usb_keyboard.c @@ -0,0 +1,113 @@ +/* usb_keyboard.c - Implementation of a USB keyboard device + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include "tusb.h" + +#include "tusb_helpers.h" /* for TUD_ENDPOINT_IN */ +#include "usb_common.h" +#include "usb_keyboard.h" + +/** + * A USB-HID "Report Descriptor" (see USB-HID 1.11 §6.2.2 "Report + * Descriptor") describing a keyboard. + */ +static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; + +static uint8_t kbd_ifc = 0; + +void usb_keyboard_init() { + if (kbd_ifc) + return; + usb_common_earlyinit(); + + kbd_ifc = usb_add_interface(cfgnum_std, TUD_HID_DESC_LEN, (uint8_t[]){ + /* USB-HID input-only descriptor for inclusion in the config descriptor; consisting of 3 parts: + * 1. an interface descriptor (USB 2.0 §9.6.5 "Interface"), + * 2. a class-specific (class=HID) descriptor of type HID (USB-HID 1.11 §6.2.1 "HID Descriptor"), + * 3. an endpoint descriptor for inputs (USB 2.0 §9.6.6 "Endpoint"). + * The TUD_HID_DESCRIPTOR() macro takes care of this for us. */ + TUD_HID_DESCRIPTOR( + 0, /* interface : bInterfaceNumber ; Number of this interface (0-indexed) */ + STRID_KBD_IFC, /* interface : iInterface ; Index of string descriptor describing this interface */ + HID_ITF_PROTOCOL_KEYBOARD, /* interface : bInterfaceProtocol ; see USB-HID 1.11 §4.3 "Protocols" */ + sizeof(hid_report_descriptor_keyboard), /* hid : wDescriptorLength ; Total size of report descriptor */ + TUD_ENDPOINT_IN | 1, /* endpoint : bEndpointAddress ; Direction | endpoint number (arbitrary?) */ + CFG_TUD_HID_EP_BUFSIZE, /* endpoint : wMaxPacketSize ; Maximum packet size this endpoint is capable of sending or receiving */ + 10), /* endpoint : bInterval ; poll interval (in milliseconds?) */ + }); +} + +static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE }; + +COROUTINE usb_keyboard_cr(void *_chan) { + usb_keyboard_rpc_t *chan = _chan; + cr_begin(); + + uint8_t report_id = 0; + uint8_t modifier = 0; + uint8_t keycodes[6] = {0}; + for (;;) { + while (!tud_hid_n_ready(kbd_ifc)) + cr_yield(); + + if (cr_rpc_have_req(chan)) { + uint32_t rune; + cr_rpc_recv_req(chan, &rune); + + modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0; + keycodes[0] = ascii2keycode[rune][1]; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + + while (!tud_hid_n_ready(kbd_ifc)) + cr_yield(); + + modifier = 0; + keycodes[0] = 0; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + + cr_rpc_send_resp(chan, 1); + } else { + modifier = 0; + keycodes[0] = 0; + tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes); + } + } + + cr_end(); +} + +/** + * Return a pointer to the HID "Report Descriptor" (see USB-HID 1.11 + * §6.2.2 "Report Descriptor") for the given index. + */ +uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) { + static uint8_t const *reports[] = { + hid_report_descriptor_keyboard, + }; + if (index >= TU_ARRAY_SIZE(reports)) + return NULL; + return reports[index]; +} + +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) instance; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // TODO not implemented + (void) report_id; +} diff --git a/cmd/harness/usb_keyboard.h b/cmd/harness/usb_keyboard.h new file mode 100644 index 0000000..6b65360 --- /dev/null +++ b/cmd/harness/usb_keyboard.h @@ -0,0 +1,17 @@ +/* usb_keyboard.h - Implementation of a USB keyboard device + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _USB_KEYBOARD_H_ +#define _USB_KEYBOARD_H_ + +#include "coroutine_rpc.h" + +typedef cr_rpc_t(uint32_t, int) usb_keyboard_rpc_t; + +void usb_keyboard_init(void); +COROUTINE usb_keyboard_cr(void *arg); + +#endif /* _USB_KEYBOARD_H_ */ |