summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--main.c14
-rw-r--r--tusb_callbacks.c141
-rw-r--r--tusb_config.h30
-rw-r--r--tusb_helpers.h9
-rwxr-xr-xtusb_helpers.h.gen2
-rw-r--r--usb_common.c150
-rw-r--r--usb_common.h49
-rw-r--r--usb_keyboard.c108
-rw-r--r--usb_keyboard.h10
-rw-r--r--usbkeyboard.c15
11 files changed, 363 insertions, 174 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f229d17..bb5abcf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,9 +10,16 @@ pico_sdk_init()
add_executable(sbc_harness)
target_sources(sbc_harness PUBLIC
main.c
+ usb_common.c
+ usb_keyboard.c
)
target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # So TinyUSB can find tusb_config.h
-target_link_libraries(sbc_harness pico_stdlib)
+target_link_libraries(sbc_harness
+ pico_stdlib
+ pico_unique_id
+ tinyusb_device
+ tinyusb_board
+)
pico_enable_stdio_usb(sbc_harness 0)
pico_enable_stdio_uart(sbc_harness 1)
pico_enable_stdio_semihosting(sbc_harness 0)
diff --git a/main.c b/main.c
index 9b508c0..65db34d 100644
--- a/main.c
+++ b/main.c
@@ -6,12 +6,17 @@
#include "bsp/board_api.h"
#include "tusb.h"
+/* local */
+#include "usb_keyboard.h"
+
int main() {
/* pico-sdk initialization */
stdio_uart_init();
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
+ usb_keyboard_init();
+
/* TinyUSB initialization */
board_init();
tud_init(BOARD_TUD_RHPORT);
@@ -20,7 +25,12 @@ int main() {
/* Event loop. */
for (;;) {
- tud_task(); /* run TinyUSB */
- usbkeyboard_task();
+ tud_task();
+ usb_keyboard_task();
+ if (usb_keyboard_is_flushed()) {
+ char *msg = "Hello world!\n";
+ for (size_t i = 0; i < strlen(msg); i++)
+ usb_keyboard_send_char(msg[i]);
+ }
}
}
diff --git a/tusb_callbacks.c b/tusb_callbacks.c
deleted file mode 100644
index 84214c9..0000000
--- a/tusb_callbacks.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* tinyusb */
-#include "bsp/board_api.h"
-#include "tusb.h"
-
-/* local */
-#include "tusb_helpers.h"
-
-#define NUM_INTERFACES CFG_TUD_HID
-#define NUM_CONFIGS 1
-
-enum {
- STRID_LANGID = 0,
- STRID_MANUF,
- STRID_PRODUCT,
- STRID_SERIAL,
-
- STRID_NONE = 0,
-};
-
-/**
- * Return a pointer to the USB "String Descriptor" (see USB 2.0 §9.6.7
- * "String").
- */
-uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
- static uint16_t desc[0xFF/2];
- static const max_u16len = (sizeof desc / sizeof desc[0]) - 1;
-
- static uint16_t const langids[] = {
- LANGID_EN_US,
- };
-
- size_t bytelen = 0;
- if (index == 0) {
- memcpy(&desc[1], langids, sizeof langids);
- bytelen = sizeof langids;
- } else {
- switch (langid) {
- case LANGID_EN_US:
- switch (index) {
- case STRID_MANUF: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("Umorpha Systems"), max_u16len); break;
- case STRID_PRODUCT: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("SBC-Harness Keyboard"), max_u16len); break;
- case STRID_SERIAL: bytelen = 2 * board_usb_get_serial(&desc[1], max_u16len); break;
- default:
- return NULL;
- };
- default:
- return NULL;
- }
- }
- assert(bytelen <= 0xFF-2);
- desc[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2+bytelen));
- return desc;
-}
-
-/**
- * Return a pointer to the USB "Device Descriptor" (see USB 2.0 §9.6.1
- * "Device") as a byte-array.
- */
-uint8_t const *tud_decriptor_device_cb(void) {
- /* Our device descriptor is static, so just declare it as a
- * static const. */
- static tusb_desc_device_t const desc = {
- .bLength = sizeof(tusb_desc_device_t),
- .bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x200, /* USB 2.0 */
-
- /* Use the "base device class", which means to use information
- * form interface descriptors instead of a global device
- * descriptor. */
- .bDeviceClass = 0x00,
- .bDeviceSubClass = 0x00,
- .bDeviceProtocol = 0x00,
-
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
-
- .idVendor = 0xCAFE, /* Vendor ID (assigned by the USB-IF) */
- .idProduct = 0x4001, /* Product ID (assigned by the manufacturer) */
- .bcdDevice = 0x0100, /* Device release number */
-
- .iManufacturer = STRID_MANUF /* Index of string descriptor describing manufacturer */
- .iProduct = STRID_PRODUCT, /* Index of string descriptor describing product */
- .iSerialNumber = STRID_SERIAL, /* Index of string descriptor describing the device's serial number */
-
- .bNumConfigurations = NUM_CONFIGS, /* Number of possible configurations */
- };
- return (uint8_t const *) &desc;
-}
-
-/**
- * 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() };
-
-/**
- * Return a pointer to the USB config "Configuration Descriptor" (see
- * USB 2.0 §9.6.4 "Configuration") for the given index.
- */
-uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
- static uint8_t const configs[NUM_CONFIGS][] = {
- {
- /* USB configuration descriptor header (USB 2.0 §9.6.4 "Configuration") */
- TUD_CONFIG_DESCRIPTOR(
- 1, /* bConfigurationValue ; Value to use as an argument to the SetConfiguration() request to select this configuration */
- NUM_INTERFACES, /* bNumInterfaces ; Number of interfaces supported by this configuration */
- STRID_NONE, /* iConfiguration ; Index of string descriptor describing this configuration */
- TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN, /* wTotalLength ; Total lenggth of data returned for this configuration */
- TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, /* bmAttributes ; Bitmap of flags (self-powered and remote-wakeup are the only flags defined in USB 2.0) */
- 100), /* bMaxPower (in mA) ; Maximum power consumption of the device when in this configuration */
- /* USB-HID input-only 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_NONE, /* 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?) */
- },
- };
- if (index >= sizeof config / sizeof configs[0])
- return NULL;
- return configs[index];
-}
-
-/**
- * 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[NUM_INTERFACES] = {
- hid_report_descriptor_keyboard,
- };
- if (index >= sizeof reports / sizeof reports[0])
- return NULL;
- return reports[index];
-}
diff --git a/tusb_config.h b/tusb_config.h
index 051c39c..37b14b3 100644
--- a/tusb_config.h
+++ b/tusb_config.h
@@ -52,7 +52,6 @@ extern "C" {
#error CFG_TUSB_MCU must be defined
#endif
-#define CFG_TUSB_OS OPT_OS_NONE
#define CFG_TUSB_DEBUG 0
// USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
@@ -75,19 +74,22 @@ extern "C" {
#define CFG_TUD_ENDPOINT0_SIZE 64
// Which of TinyUSB's built-in class drivers to enable.
-#define CFG_TUD_CDC 0 // Communications Device Class (e.g. ttyUSB) https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip
-#define CFG_TUD_MSC 0 // Mass Storage Class https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf
-#define CFG_TUD_HID 1 // Human Interface Device (num is how many interfaces) https://www.usb.org/sites/default/files/hid1_11.pdf
-#define CFG_TUD_AUDIO 0 // Audio https://www.usb.org/sites/default/files/audio10.pdf
-#define CFG_TUD_VIDEO 0 // Video https://www.usb.org/sites/default/files/USB_Video_Class_1_5.zip
-#define CFG_TUD_MIDI 0 // Musical Instrument Digital Interface https://www.usb.org/sites/default/files/USB%20MIDI%20v2_0.pdf
-#define CFG_TUD_VENDOR 0 // ???
-#define CFG_TUD_USBTMC 0 // Test & Measurement Class https://www.usb.org/sites/default/files/USBTMC_1_006a.zip
-#define CFG_TUD_DFU_RUNTIME 0 // Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
-#define CFG_TUD_DFU 0 // Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
-#define CFG_TUD_ECM_RNDIS 0 // net
-#define CFG_TUD_NCM 0 // net
-#define CFG_TUD_BTH 0 // Bluetooth
+//
+// If a class takes an int, that's the maximum number of interfaces of
+// that type that may be listed in the same configuration descriptor.
+#define CFG_TUD_CDC 0 // int : Communications Device Class (e.g. ttyUSB) https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip
+#define CFG_TUD_MSC 0 // bool: Mass Storage Class https://www.usb.org/sites/default/files/Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf
+#define CFG_TUD_HID 1 // int : Human Interface Device https://www.usb.org/sites/default/files/hid1_11.pdf
+#define CFG_TUD_AUDIO 0 // int : Audio https://www.usb.org/sites/default/files/audio10.pdf
+#define CFG_TUD_VIDEO 0 // int : Video https://www.usb.org/sites/default/files/USB_Video_Class_1_5.zip
+#define CFG_TUD_MIDI 0 // int : Musical Instrument Digital Interface https://www.usb.org/sites/default/files/USB%20MIDI%20v2_0.pdf
+#define CFG_TUD_VENDOR 0 // int : ???
+#define CFG_TUD_USBTMC 0 // bool: Test & Measurement Class https://www.usb.org/sites/default/files/USBTMC_1_006a.zip
+#define CFG_TUD_DFU_RUNTIME 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
+#define CFG_TUD_DFU 0 // bool: Device Firmware Upgrade https://www.usb.org/sites/default/files/DFU_1.1.pdf
+#define CFG_TUD_ECM_RNDIS 0 // bool: net
+#define CFG_TUD_NCM 0 // bool: net
+#define CFG_TUD_BTH 0 // bool: Bluetooth
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 8
diff --git a/tusb_helpers.h b/tusb_helpers.h
index 452a32e..0e04988 100644
--- a/tusb_helpers.h
+++ b/tusb_helpers.h
@@ -966,4 +966,13 @@
#define TUD_ENDPOINT_OUT 0x00
#define TUD_ENDPOINT_IN 0x80
+#define UTF16(str) u ## str
+
+static inline size_t utf16_strncpy(uint16_t *dst, uint16_t *src, size_t dsize) {
+ size_t i;
+ for (i = 0; i < dsize && src && src[i]; i++)
+ dst[i] = src[i];
+ return i;
+}
+
#endif /* _USB_HELPERS_H_ */
diff --git a/tusb_helpers.h.gen b/tusb_helpers.h.gen
index 4682166..8ef83c8 100755
--- a/tusb_helpers.h.gen
+++ b/tusb_helpers.h.gen
@@ -77,7 +77,7 @@ cat <<'EOT'
#define UTF16(str) u ## str
-static inline size_t utf16_strncpy(uint16_t *dst, uint16_t *src, dsize size_t) {
+static inline size_t utf16_strncpy(uint16_t *dst, uint16_t *src, size_t dsize) {
size_t i;
for (i = 0; i < dsize && src && src[i]; i++)
dst[i] = src[i];
diff --git a/usb_common.c b/usb_common.c
new file mode 100644
index 0000000..0427122
--- /dev/null
+++ b/usb_common.c
@@ -0,0 +1,150 @@
+#include <stdint.h> /* for uint{n}_t types */
+#include <string.h> /* memcpy(newlib) */
+#include <assert.h> /* for assert(newlib) */
+#include <stdlib.h> /* for malloc(pico_malloc) and realloc(pico_malloc) */
+#include "bsp/board_api.h" /* for board_usb_get_serial(TinyUSB) */
+#include "tusb.h" /* for various tusb_*_t types */
+
+#include "tusb_helpers.h" /* for LANGID_*, UTF16(), utf16_strncpy */
+#include "usb_common.h"
+
+/* Strings ********************************************************************/
+
+/**
+ * Return a pointer to the USB "String Descriptor" (see USB 2.0 §9.6.7
+ * "String").
+ */
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+ static uint16_t desc[0xFF/2];
+ static const size_t max_u16len = (sizeof desc / sizeof desc[0]) - 1;
+
+ static uint16_t const langids[] = {
+ LANGID_EN_US,
+ };
+
+ size_t bytelen = 0;
+ if (index == 0) {
+ memcpy(&desc[1], langids, sizeof langids);
+ bytelen = sizeof langids;
+ } else {
+ switch (langid) {
+ case LANGID_EN_US:
+ switch (index) {
+ case STRID_MANUF: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("Umorpha Systems"), max_u16len); break;
+ case STRID_PRODUCT: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("SBC-Harness Keyboard"), max_u16len); break;
+ case STRID_SERIAL: bytelen = 2 * board_usb_get_serial(&desc[1], max_u16len); break;
+ case STRID_CFG: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("Standard Configuration"), max_u16len); break;
+ case STRID_KBD_IFC: bytelen = 2 * utf16_strncpy(&desc[1], UTF16("Keyboard Interface"), max_u16len); break;
+ default:
+ return NULL;
+ };
+ default:
+ return NULL;
+ }
+ }
+ assert(bytelen <= 0xFF-2);
+ desc[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2+bytelen));
+ return desc;
+}
+
+/* Globals ********************************************************************/
+
+uint8_t cfgnum_std = 0;
+
+void usb_common_init(void) {
+ if (cfgnum_std)
+ return;
+ cfgnum_std = usb_add_config(
+ STRID_CFG, /* iConfiguration ; Index of string descriptor describing this configuration */
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, /* bmAttributes ; Bitmap of flags (self-powered and remote-wakeup are the only flags defined in USB 2.0) */
+ 100); /* bMaxPower (in mA) ; Maximum power consumption of the device when in this configuration */
+}
+
+/* Main utilities *************************************************************/
+
+static uint8_t configc = 0;
+static uint8_t **configv = NULL;
+
+uint8_t usb_add_config(uint8_t iConfiguration, uint8_t bmAttributes, uint8_t bMaxPower_mA) {
+ uint8_t *desc;
+
+ configv = realloc(configv, (sizeof configv[0]) * ++configc);
+ desc = configv[configc-1] = malloc(TUD_CONFIG_DESC_LEN);
+
+ memcpy(desc, (uint8_t[]){
+ /* USB configuration descriptor header (USB 2.0 §9.6.4 "Configuration") */
+ TUD_CONFIG_DESCRIPTOR(
+ configc, /* bConfigurationValue */
+ 0, /* bNumInterfaces (will be incremented by usb_add_interface() */
+ iConfiguration, /* iConfiguration */
+ TUD_CONFIG_DESC_LEN, /* wTotalLength (will be incremented by usb_add_interface() */
+ bmAttributes, /* bmAttributes */
+ bMaxPower_mA+1), /* bMaxPower (+1 because tusb just does n/2 instead of (n+1)/2) */
+ }, TUD_CONFIG_DESC_LEN);
+
+ return configc;
+}
+
+uint8_t usb_add_interface(uint8_t cfg_num, uint16_t ifc_len, uint8_t *ifc_dat) {
+ assert(cfg_num > 0 && cfg_num <= configc);
+ assert(ifc_len >= 3);
+ assert(ifc_dat);
+
+ uint8_t *desc = configv[cfg_num-1];
+ // wTotalLength
+ uint16_t total_len = TU_U16(desc[3], desc[2]) + ifc_len;
+ desc[3] = TU_U16_HIGH(total_len);
+ desc[2] = TU_U16_LOW(total_len);
+ // bNumInterfaces
+ ifc_dat[3] = desc[4]++;
+
+ desc = configv[cfg_num-1] = realloc(desc, total_len);
+ memcpy(&desc[total_len-ifc_len], ifc_dat, ifc_len);
+
+ return ifc_dat[3];
+}
+
+/**
+ * Return a pointer to the USB "Device Descriptor" (see USB 2.0 §9.6.1
+ * "Device") as a byte-array.
+ */
+uint8_t const *tud_descriptor_device_cb(void) {
+ /* Our device descriptor is static, so just declare it as a
+ * static const. */
+ static tusb_desc_device_t desc = {
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x200, /* USB 2.0 */
+
+ /* Use the "base device class", which means to use information
+ * from interface descriptors instead of a global device
+ * descriptor. */
+ .bDeviceClass = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = 0xCAFE, /* Vendor ID (assigned by the USB-IF) */
+ .idProduct = 0x4001, /* Product ID (assigned by the manufacturer) */
+ .bcdDevice = 0x0100, /* Device release number */
+
+ .iManufacturer = STRID_MANUF, /* Index of string descriptor describing manufacturer */
+ .iProduct = STRID_PRODUCT, /* Index of string descriptor describing product */
+ .iSerialNumber = STRID_SERIAL, /* Index of string descriptor describing the device's serial number */
+
+ .bNumConfigurations = 0, /* Number of possible configurations */
+ };
+ desc.bNumConfigurations = configc;
+ return (uint8_t const *) &desc;
+}
+
+/**
+ * Return a pointer to the USB config "Configuration Descriptor" (see
+ * USB 2.0 §9.6.4 "Configuration") for the given index.
+ */
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
+ if (index >= configc)
+ return NULL;
+ return configv[index];
+}
diff --git a/usb_common.h b/usb_common.h
new file mode 100644
index 0000000..f0ed844
--- /dev/null
+++ b/usb_common.h
@@ -0,0 +1,49 @@
+#ifndef _USB_COMMON_H_
+#define _USB_COMMON_H_
+
+/* Strings ********************************************************************/
+
+enum {
+ /* Be sure to keep this list in-sync with
+ * usb_common.c:tud_descriptor_string_cb() */
+ STRID_LANGID = 0,
+ STRID_MANUF,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+ STRID_CFG,
+ STRID_KBD_IFC,
+
+ STRID_NONE = 0,
+};
+
+/* Globals ********************************************************************/
+
+extern uint8_t cfgnum_std;
+void usb_common_init(void);
+
+/* Main utilities *************************************************************/
+
+/**
+ * Declare a new TUD configuration.
+ *
+ * @param iConfiguration : ID of the string descriptor describing this configuration
+ * @param bmAttributes : bitmap of flags; TUSB_DESC_CONFIG_ATT_{REMOTE_WAKUP,SELF_POWERED}
+ * @param bMaxPower_mA : maximum power consumption of the device when in this configuration, in mA
+ * @return the configuration number for the created config
+ */
+uint8_t usb_add_config(uint8_t iConfiguration, uint8_t bmAttributes, uint8_t bMaxPower_mA);
+
+/**
+ * Add an interface to a configuration that has been created with usb_add_config().
+ *
+ * @param cfg_num : the value returned from usb_add_config()
+ * @param ifc_len : the length of ifc_Dat
+ * @param ifc_dat : the raw descriptor data for the interface (probably created by
+ * TUD_{CLASS}_DESCRIPTOR(); grep TinyUSB/src/device/usbd.h for '#define
+ * TUD_\S*_DESCRIPTOR(_itfnum'). The interface number in this data is overwritten with the
+ * appropriate number for this config.
+ * @return the interface number for the added interface
+ */
+uint8_t usb_add_interface(uint8_t cfg_num, uint16_t ifc_len, uint8_t *ifc_dat);
+
+#endif /* _USB_COMMON_H_ */
diff --git a/usb_keyboard.c b/usb_keyboard.c
new file mode 100644
index 0000000..5647403
--- /dev/null
+++ b/usb_keyboard.c
@@ -0,0 +1,108 @@
+#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_init();
+
+ 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?) */
+ });
+}
+
+#define kbd_buf_cap 1024
+static uint32_t kbd_buf[kbd_buf_cap];
+static size_t kbd_buf_beg = 0;
+static size_t kbd_buf_len = 0;
+
+static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE };
+
+void usb_keyboard_task(void) {
+ if (tud_hid_n_ready(kbd_ifc)) {
+ uint8_t const report_id = 0;
+ uint8_t modifier = 0;
+ uint8_t keycodes[6] = {0};
+
+ if (kbd_buf_len) {
+ if (ascii2keycode[kbd_buf[kbd_buf_beg]][0])
+ modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
+ keycodes[0] = ascii2keycode[kbd_buf[kbd_buf_beg]][1];
+
+ kbd_buf_beg++;
+ if (kbd_buf_beg == kbd_buf_cap)
+ kbd_buf_beg = 0;
+ kbd_buf_len--;
+ }
+
+ tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
+ }
+}
+
+bool usb_keyboard_send_char(uint32_t ch) {
+ if (kbd_buf_len == kbd_buf_cap) /* buffer full */
+ return false;
+ if (ch > 0x7F) /* not ASCII */
+ return false;
+ kbd_buf[(kbd_buf_beg + kbd_buf_len++) % kbd_buf_cap] = ch;
+}
+
+bool usb_keyboard_is_flushed(void) {
+ return kbd_buf_len == 0;
+}
+
+/**
+ * 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 >= sizeof reports / sizeof reports[0])
+ 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/usb_keyboard.h b/usb_keyboard.h
new file mode 100644
index 0000000..9460feb
--- /dev/null
+++ b/usb_keyboard.h
@@ -0,0 +1,10 @@
+#ifndef _USB_KEYBOARD_H_
+#define _USB_KEYBOARD_H_
+
+void usb_keyboard_init(void);
+void usb_keyboard_task(void);
+
+bool usb_keyboard_send_char(uint32_t ch);
+bool usb_keyboard_is_flushed(void);
+
+#endif /* _USB_KEYBOARD_H_ */
diff --git a/usbkeyboard.c b/usbkeyboard.c
deleted file mode 100644
index 436610c..0000000
--- a/usbkeyboard.c
+++ /dev/null
@@ -1,15 +0,0 @@
-void usbkeyboard_send_char(uint32_t ch) {
-}
-
-char
-
-enum {
- IFACE_KEYBOARD = 0
-};
-
-void usbkeyboard_task(void) {
- if (tud_hid_n_ready(0)) {
- uint8_t keycode[6]
- }
-}
-