diff --git a/.github/workflows/build-and-push-firmware.yml b/.github/workflows/build-and-push-firmware.yml index 59c02701..c4203c67 100644 --- a/.github/workflows/build-and-push-firmware.yml +++ b/.github/workflows/build-and-push-firmware.yml @@ -25,6 +25,7 @@ jobs: uses: actions/checkout@v6 with: ref: ${{ github.ref }} + submodules: recursive - name: Prepare image uses: ./.github/actions/prepare-image diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..39cba351 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common/dep/tinyusb"] + path = common/dep/tinyusb + url = https://github.com/intechstudio/tinyusb.git diff --git a/common/.gitignore b/common/.gitignore index 66d56a13..c723264f 100644 --- a/common/.gitignore +++ b/common/.gitignore @@ -27,5 +27,8 @@ !dep/vmp !dep/vmp/** +!dep/tinyusb +!dep/tinyusb/** + !test/tests.h !test/*.c diff --git a/common/dep/tinyusb b/common/dep/tinyusb new file mode 160000 index 00000000..975c481f --- /dev/null +++ b/common/dep/tinyusb @@ -0,0 +1 @@ +Subproject commit 975c481f0db900a92cc20910efef2d74506ada00 diff --git a/common/src/c/grid_decode.c b/common/src/c/grid_decode.c index e3b145cc..225800a6 100644 --- a/common/src/c/grid_decode.c +++ b/common/src/c/grid_decode.c @@ -70,7 +70,7 @@ uint8_t grid_decode_midi_to_usb(char* header, char* chunk) { .byte3 = param2, }; - grid_midi_tx_push(event); + grid_usb_midi_tx_push(&grid_usb_midi_state, event); return 0; } @@ -94,8 +94,6 @@ uint8_t grid_decode_sysex_to_usb(char* header, char* chunk) { grid_port_debug_printf("sysex invalid: %d %d", first, last); } - uint32_t packets_dropped = 0; - struct grid_midi_event_desc event; for (uint16_t i = 0; i < length;) { @@ -128,12 +126,7 @@ uint8_t grid_decode_sysex_to_usb(char* header, char* chunk) { } } - // grid_port_debug_printf("packet: %d %d %d %d", event.byte0, event.byte1, event.byte2, event.byte3); - packets_dropped += grid_midi_tx_push(event); - } - - if (packets_dropped) { - grid_port_debug_printf("sysex_to_usb: %d packets dropped", packets_dropped); + grid_usb_midi_tx_push(&grid_usb_midi_state, event); } return 0; @@ -150,14 +143,14 @@ uint8_t grid_decode_mousebutton_to_usb(char* header, char* chunk) { uint8_t state = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDMOUSEBUTTON_STATE); uint8_t button = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDMOUSEBUTTON_BUTTON); - struct grid_usb_keyboard_event_desc key = { - .ismodifier = 3, // 0: no, 1: yes, 2: mousemove, 3: mousebutton, f: delay + struct grid_macro_event_desc key = { + .type = GRID_MACRO_EVENT_TYPE_MOUSE_BUTTON, .ispressed = state, .keycode = button, .delay = 1, }; - if (grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key)) { + if (grid_usb_macro_tx_push(&grid_macro_state, key)) { grid_port_debug_printf("mouse button: packet dropped"); } @@ -175,14 +168,14 @@ uint8_t grid_decode_mousemove_to_usb(char* header, char* chunk) { uint8_t position = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDMOUSEMOVE_POSITION); uint8_t axis = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDMOUSEMOVE_AXIS); - struct grid_usb_keyboard_event_desc key = { - .ismodifier = 2, // 0: no, 1: yes, 2: mousemove, 3: mousebutton, f: delay + struct grid_macro_event_desc key = { + .type = GRID_MACRO_EVENT_TYPE_MOUSE_MOVE, .ispressed = position, .keycode = axis, .delay = 1, }; - if (grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key)) { + if (grid_usb_macro_tx_push(&grid_macro_state, key)) { grid_port_debug_printf("mouse move: packet dropped"); } @@ -202,7 +195,7 @@ uint8_t grid_decode_gamepadmove_to_usb(char* header, char* chunk) { int8_t position = position_raw - 128; - grid_usb_gamepad_axis_move(axis, position); + grid_usb_gamepad_axis_move(&grid_gamepad_state, axis, position); return 0; } @@ -218,7 +211,7 @@ uint8_t grid_decode_gamepadbutton_to_usb(char* header, char* chunk) { uint8_t button = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDGAMEPADBUTTON_BUTTON); uint8_t state = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_HIDGAMEPADBUTTON_STATE); - grid_usb_gamepad_button_change(button, state); + grid_usb_gamepad_button_change(&grid_gamepad_state, button, state); return 0; } @@ -245,9 +238,9 @@ uint8_t grid_decode_keyboard_to_usb(char* header, char* chunk) { if (key_ismodifier == 0 || key_ismodifier == 1) { - struct grid_usb_keyboard_event_desc key = { + struct grid_macro_event_desc key = { key.keycode = key_code, - key.ismodifier = key_ismodifier, + key.type = key_ismodifier ? GRID_MACRO_EVENT_TYPE_MODIFIER : GRID_MACRO_EVENT_TYPE_KEY, key.ispressed = key_state, key.delay = default_delay, }; @@ -256,14 +249,14 @@ uint8_t grid_decode_keyboard_to_usb(char* header, char* chunk) { if (key_state == 2) { key.ispressed = 1; - packets_dropped += grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key); + packets_dropped += grid_usb_macro_tx_push(&grid_macro_state, key); key.ispressed = 0; - packets_dropped += grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key); + packets_dropped += grid_usb_macro_tx_push(&grid_macro_state, key); } // Single press or release else { - packets_dropped += grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key); + packets_dropped += grid_usb_macro_tx_push(&grid_macro_state, key); } } else if (key_ismodifier == 0xf) { @@ -271,14 +264,14 @@ uint8_t grid_decode_keyboard_to_usb(char* header, char* chunk) { uint16_t delay = grid_frame_get_parameter((uint8_t*)chunk, GRID_CLASS_HIDKEYBOARD_DELAY_offset + i, GRID_CLASS_HIDKEYBOARD_DELAY_length); // Special delay event - struct grid_usb_keyboard_event_desc key = { - key.ismodifier = key_ismodifier, + struct grid_macro_event_desc key = { + key.type = GRID_MACRO_EVENT_TYPE_DELAY, key.ispressed = 0, key.keycode = 0, key.delay = delay, }; - packets_dropped += grid_usb_keyboard_tx_push(&grid_usb_keyboard_state, key); + packets_dropped += grid_usb_macro_tx_push(&grid_macro_state, key); } else { @@ -286,10 +279,6 @@ uint8_t grid_decode_keyboard_to_usb(char* header, char* chunk) { } } - if (packets_dropped) { - grid_port_debug_printf("keyboard: %d packets dropped", packets_dropped); - } - return 0; } @@ -1253,7 +1242,7 @@ uint8_t grid_decode_config_to_ui(char* header, char* chunk) { case GRID_INSTR_EXECUTE_code: { // Disable HID - grid_usb_keyboard_disable(&grid_usb_keyboard_state); + grid_usb_keyboard_disable(&grid_keyboard_state); uint16_t scriptlength = grid_msg_get_parameter_raw((uint8_t*)chunk, CLASS_CONFIG_ACTIONLENGTH); diff --git a/common/src/c/grid_lua_api.c b/common/src/c/grid_lua_api.c index 3e476a46..f8606e4a 100644 --- a/common/src/c/grid_lua_api.c +++ b/common/src/c/grid_lua_api.c @@ -534,7 +534,7 @@ int l_grid_cat(lua_State* L) { return 0; } -/*static*/ int l_grid_usb_keyboard_send(lua_State* L) { +/*static*/ int l_grid_keyboard_send(lua_State* L) { int nargs = lua_gettop(L); diff --git a/common/src/c/grid_lua_api.h b/common/src/c/grid_lua_api.h index 8494f715..a25e0636 100644 --- a/common/src/c/grid_lua_api.h +++ b/common/src/c/grid_lua_api.h @@ -24,7 +24,7 @@ extern void grid_platform_delay_ms(uint32_t delay_milliseconds); /*static*/ int l_grid_elementname_get(lua_State* L); /*static*/ int l_grid_string_get(lua_State* L); -/*static*/ int l_grid_usb_keyboard_send(lua_State* L); +/*static*/ int l_grid_keyboard_send(lua_State* L); /*static*/ int l_grid_mousemove_send(lua_State* L); /*static*/ int l_grid_mousebutton_send(lua_State* L); diff --git a/common/src/c/grid_platform.h b/common/src/c/grid_platform.h index da94851a..5ea0f6f7 100644 --- a/common/src/c/grid_platform.h +++ b/common/src/c/grid_platform.h @@ -76,10 +76,6 @@ extern void grid_platform_send_frame(void* swsr, uint32_t size, uint8_t dir); extern uint8_t grid_platform_reset_grid_transmitter(uint8_t direction); -extern int32_t grid_platform_usb_serial_ready(); - -extern int32_t grid_platform_usb_serial_write(char* buffer, uint32_t length); - extern void* grid_platform_allocate_volatile(size_t size); extern char* grid_platform_read_file_contents(const char* path); diff --git a/common/src/c/grid_port.c b/common/src/c/grid_port.c index 3fa9f00f..b9694fbf 100644 --- a/common/src/c/grid_port.c +++ b/common/src/c/grid_port.c @@ -8,6 +8,9 @@ #include "grid_decode.h" #include "grid_platform.h" #include "grid_protocol.h" +#include "grid_usb_acm.h" + +extern bool grid_usb_connected(void); extern struct grid_decoder_collection* grid_decoder_to_ui_reference; extern struct grid_decoder_collection* grid_decoder_to_usb_reference; @@ -242,6 +245,10 @@ void grid_port_send_usb(struct grid_port* port) { assert(port->type == GRID_PORT_USB); + if (grid_usb_connected() && !grid_usb_acm_tx_ready(&grid_usb_acm_state)) { + return; + } + struct grid_swsr_t* tx = grid_port_get_tx(port); // Allocated statically due to the implementation of usb serial writes @@ -253,10 +260,7 @@ void grid_port_send_usb(struct grid_port* port) { } grid_port_decode_msg(grid_decoder_to_usb_reference, &msg); - - if (grid_platform_usb_serial_ready()) { - grid_platform_usb_serial_write(msg.data, msg.length); - } + grid_usb_acm_write(&grid_usb_acm_state, msg.data, msg.length); } void grid_port_send_ui(struct grid_port* port) { diff --git a/common/src/c/grid_protocol.h b/common/src/c/grid_protocol.h index 5c62c4e7..db640e33 100644 --- a/common/src/c/grid_protocol.h +++ b/common/src/c/grid_protocol.h @@ -293,7 +293,7 @@ #define GRID_LUA_FNC_G_KEYBOARD_SEND_short "gks" #define GRID_LUA_FNC_G_KEYBOARD_SEND_human "keyboard_send" -#define GRID_LUA_FNC_G_KEYBOARD_SEND_fnptr l_grid_usb_keyboard_send +#define GRID_LUA_FNC_G_KEYBOARD_SEND_fnptr l_grid_keyboard_send #define GRID_LUA_FNC_G_MOUSEMOVE_SEND_short "gmms" #define GRID_LUA_FNC_G_MOUSEMOVE_SEND_human "mouse_move_send" diff --git a/common/src/c/grid_transport.c b/common/src/c/grid_transport.c index c538246a..b1848a0d 100644 --- a/common/src/c/grid_transport.c +++ b/common/src/c/grid_transport.c @@ -5,6 +5,8 @@ #include #include +#include "grid_usb_acm.h" + struct grid_transport grid_transport_state; void grid_transport_malloc(struct grid_transport* transport, size_t port_count) { @@ -250,6 +252,10 @@ void grid_transport_rx_broadcast_tx(struct grid_transport* transport, struct gri grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_BLUE, 128); } + if (type == GRID_PORT_USB) { + grid_usb_acm_state.tx_dropped++; + } + continue; } diff --git a/common/src/c/grid_ui.c b/common/src/c/grid_ui.c index 165a82a7..290c8783 100644 --- a/common/src/c/grid_ui.c +++ b/common/src/c/grid_ui.c @@ -915,7 +915,7 @@ static void grid_ui_page_read(struct grid_ui_model* ui, uint8_t page) { grid_lua_semaphore_release(&grid_lua_state); - grid_usb_keyboard_enable(&grid_usb_keyboard_state); + grid_usb_keyboard_enable(&grid_keyboard_state); } #pragma GCC diagnostic push diff --git a/common/src/c/grid_usb.c b/common/src/c/grid_usb.c index ae166b5a..2bca5e2b 100644 --- a/common/src/c/grid_usb.c +++ b/common/src/c/grid_usb.c @@ -3,543 +3,47 @@ * * Created: 7/6/2020 12:07:54 PM * Author: suku + * + * USB functionality has been refactored into: + * grid_usb_midi.c - MIDI buffer/TX/RX/SysEx/RTM + * grid_usb_hid.c - HID keyboard model + gamepad + enable/disable */ #include "grid_usb.h" - -#include -#include - -#include "grid_msg.h" -#include "grid_platform.h" +#include "grid_protocol.h" #include "grid_swsr.h" +#include "grid_usb_acm.h" +#include "grid_usb_hid.h" +#include "grid_usb_midi.h" +#include "tusb.h" -struct grid_swsr_t grid_midi_tx; -struct grid_swsr_t grid_midi_rx; - -// New buffers for SysEx and RTM -struct grid_swsr_t grid_midi_sysex_rx; -struct grid_swsr_t grid_midi_rtm_rx; - -// SysEx assembly buffer for accumulating bytes until complete message -static uint8_t sysex_assembly_buffer[GRID_MIDI_SYSEX_RX_BUFFER_length]; -static uint16_t sysex_assembly_index = 0; - -struct grid_usb_keyboard_model grid_usb_keyboard_state; - -void grid_usb_midi_buffer_init() { - - size_t typesize = sizeof(struct grid_midi_event_desc); - - assert(grid_swsr_malloc(&grid_midi_tx, GRID_MIDI_TX_BUFFER_length * typesize) == 0); - assert(grid_swsr_malloc(&grid_midi_rx, GRID_MIDI_RX_BUFFER_length * typesize) == 0); - - // Initialize new buffers for SysEx and RTM (store raw bytes) - assert(grid_swsr_malloc(&grid_midi_sysex_rx, GRID_MIDI_SYSEX_RX_BUFFER_length) == 0); - assert(grid_swsr_malloc(&grid_midi_rtm_rx, GRID_MIDI_RTM_RX_BUFFER_length) == 0); -} - -void grid_usb_keyboard_model_init(struct grid_usb_keyboard_model* kb, uint8_t buffer_length) { - - kb->tx_rtc_lasttimestamp = grid_platform_rtc_get_micros(); - kb->tx_write_index = 0; - kb->tx_read_index = 0; - - kb->tx_buffer_length = buffer_length; - - kb->tx_buffer = (struct grid_usb_keyboard_event_desc*)malloc(buffer_length * sizeof(struct grid_usb_keyboard_event_desc)); - - for (uint16_t i = 0; i < kb->tx_buffer_length; i++) { - kb->tx_buffer[i].ismodifier = 0; - kb->tx_buffer[i].keycode = 0; - kb->tx_buffer[i].ispressed = 0; - kb->tx_buffer[i].delay = 0; - } - - for (uint8_t i = 0; i < GRID_KEYBOARD_KEY_maxcount; i++) { - - kb->active_key_list[i].ismodifier = 0; - kb->active_key_list[i].keycode = 255; - kb->active_key_list[i].ispressed = 0; - } - - kb->active_key_count = 0; - - grid_usb_keyboard_enable(kb); -} - -uint8_t grid_usb_keyboard_cleanup(struct grid_usb_keyboard_model* kb) { - - uint8_t changed_flag = 0; - - // Remove all inactive (released) keys - for (uint8_t i = 0; i < kb->active_key_count; i++) { - - if (kb->active_key_list[i].ispressed == false) { - - changed_flag = 1; - - kb->active_key_list[i].ismodifier = 0; - kb->active_key_list[i].ispressed = 0; - kb->active_key_list[i].keycode = 255; - - // Pop item, move each remaining after this forvard one index - for (uint8_t j = i + 1; j < kb->active_key_count; j++) { - - kb->active_key_list[j - 1] = kb->active_key_list[j]; - - kb->active_key_list[j].ismodifier = 0; - kb->active_key_list[j].ispressed = 0; - kb->active_key_list[j].keycode = 255; - } - - kb->active_key_count--; - i--; // Retest this index, because it now points to a new item - } - } - - if (changed_flag == 1) { - - // uint8_t debugtext[100] = {0}; - // snprintf(debugtext, 99, "count: %d | activekeys: %d, %d, %d, %d, - //%d, %d", kb->active_key_count, kb->active_key_list[0].keycode, - // kb->active_key_list[1].keycode, kb->active_key_list[2].keycode, - // kb->active_key_list[3].keycode, kb->active_key_list[4].keycode, - // kb->active_key_list[5].keycode); - // grid_port_debug_print_text(debugtext); - - // USB SEND - } - - return changed_flag; -} - -extern int32_t grid_platform_usb_keyboard_keys_state_change(struct grid_usb_keyboard_event_desc* active_key_list, uint8_t keys_count); - -int32_t grid_usb_keyboard_keychange(struct grid_usb_keyboard_model* kb, struct grid_usb_keyboard_event_desc* key) { - - uint8_t item_index = 255; - uint8_t changed_flag = 0; - - grid_usb_keyboard_cleanup(kb); - - for (uint8_t i = 0; i < kb->active_key_count; i++) { - - if (kb->active_key_list[i].keycode == key->keycode && kb->active_key_list[i].ismodifier == key->ismodifier) { - // key is already in the list - item_index = i; - - if (kb->active_key_list[i].ispressed == true) { - - if (key->ispressed == true) { - // OK nothing to do here - } else { - // Release the damn key - kb->active_key_list[i].ispressed = false; - changed_flag = 1; - } - } - } - } - - grid_usb_keyboard_cleanup(kb); - - if (item_index == 255) { - - // item not in list - - if (kb->active_key_count < GRID_KEYBOARD_KEY_maxcount) { - - if (key->ispressed == true) { - - kb->active_key_list[kb->active_key_count] = *key; - kb->active_key_count++; - changed_flag = 1; - } - } else { - // grid_port_debug_print_text("activekeys limit hit!"); - } - } - - if (changed_flag == 1) { - - if (grid_usb_keyboard_isenabled(kb)) { - - int32_t result = grid_platform_usb_keyboard_keys_state_change(kb->active_key_list, kb->active_key_count); - return result; // Return USB status (0=success, non-zero=busy/error) - } else { - - grid_port_debug_print_text("KB IS DISABLED"); - - struct grid_msg msg; - uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; - grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); - - grid_msg_add_frame(&msg, GRID_CLASS_HIDKEYSTATUS_frame); - grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); - grid_msg_set_parameter(&msg, CLASS_HIDKEYSTATUS_ISENABLED, kb->isenabled); - - if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { - grid_transport_send_msg_to_all(&grid_transport_state, &msg); - } - - return 0; // Keyboard disabled, but not an error - } - } - - return 0; // No change, nothing to send -} - -uint8_t grid_midi_tx_push(struct grid_midi_event_desc event) { - - uint8_t dropped = 0; - - if (!grid_swsr_writable(&grid_midi_tx, sizeof(struct grid_midi_event_desc))) { - - // Pop as many bytes as we would like to push, to make space - // (this modifies the read address, and is done under the assumption that - // there are no concurrent reads and writes in the context of midi tx) - grid_swsr_read(&grid_midi_tx, NULL, sizeof(struct grid_midi_event_desc)); - - dropped = 1; - } - - grid_swsr_write(&grid_midi_tx, &event, sizeof(struct grid_midi_event_desc)); - - return dropped; -} - -void grid_midi_tx_pop() { - - if (!grid_swsr_readable(&grid_midi_tx, sizeof(struct grid_midi_event_desc))) { - return; - } - - if (grid_platform_usb_midi_write_status() == 1) { - return; - } - - struct grid_midi_event_desc event; - grid_swsr_read(&grid_midi_tx, &event, sizeof(struct grid_midi_event_desc)); - - grid_platform_usb_midi_write(event.byte0, event.byte1, event.byte2, event.byte3); -} - -bool grid_midi_tx_readable() { return grid_swsr_readable(&grid_midi_tx, sizeof(struct grid_midi_event_desc)); } - -static void grid_midi_rx_push_rtm(uint8_t rtm_byte) { - if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIRTM) & GRID_RX_MODE_FORWARD_FROM_USB)) { - return; - } - if (grid_swsr_writable(&grid_midi_rtm_rx, 1)) { - grid_swsr_write(&grid_midi_rtm_rx, &rtm_byte, 1); - } -} - -static int grid_midi_rx_process_sysex(uint8_t cin, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - - static uint8_t MIDI_RX_STATE_IS_SYSEX = 0; +bool grid_usb_connected(void) { return tud_mounted(); } - bool is_sysex_start = (cin == GRID_MIDI_CIN_SYSEX_START && byte1 == GRID_MIDI_SYSEX_START); +void grid_usb_task(void) { tud_task_ext(0, false); } - if (!MIDI_RX_STATE_IS_SYSEX && !is_sysex_start) { - return 0; - } +void grid_usb_on_connect(void) {} - MIDI_RX_STATE_IS_SYSEX = (cin == GRID_MIDI_CIN_SYSEX_START); +void grid_usb_on_disconnect(void) { + grid_usb_acm_state.dtr = false; + grid_usb_acm_state.tx_ready = 0; - switch (cin) { - case GRID_MIDI_CIN_SYSEX_START: - return 3; - case GRID_MIDI_CIN_SYSEX_END_1BYTE: - return 1; - case GRID_MIDI_CIN_SYSEX_END_2BYTE: - return 2; - case GRID_MIDI_CIN_SYSEX_END_3BYTE: - return 3; - } + grid_swsr_read(&grid_usb_midi_state.tx, NULL, grid_swsr_size(&grid_usb_midi_state.tx)); - return 0; -} - -static void grid_midi_rx_push_normal(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - - if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIVOICE) & GRID_RX_MODE_FORWARD_FROM_USB)) { - return; - } - - struct grid_midi_event_desc event = {byte0, byte1, byte2, byte3}; - if (grid_swsr_writable(&grid_midi_rx, sizeof(struct grid_midi_event_desc))) { - grid_swsr_write(&grid_midi_rx, &event, sizeof(struct grid_midi_event_desc)); - } -} - -void grid_midi_rx_push_sysex(uint8_t sysex_length, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - - if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDISYSEX) & GRID_RX_MODE_FORWARD_FROM_USB)) { - return; - } - - if (!grid_swsr_writable(&grid_midi_sysex_rx, sysex_length)) { - return; - } - - uint8_t bytes[3] = {byte1, byte2, byte3}; - grid_swsr_write(&grid_midi_sysex_rx, bytes, sysex_length); -} - -void grid_midi_rx_push(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - - uint8_t cin = byte0 & 0x0F; - - // 1. REAL-TIME MESSAGES: identified by status byte >= 0xF8, not CIN. - // Per MIDI spec these are single-byte and may be interleaved within SysEx. - if (byte1 >= GRID_MIDI_RTM_TIMING_CLOCK) { - grid_midi_rx_push_rtm(byte1); - return; - } - - // 2. SYSEX MESSAGES - int sysex_length = grid_midi_rx_process_sysex(cin, byte1, byte2, byte3); - if (sysex_length) { - grid_midi_rx_push_sysex(sysex_length, byte1, byte2, byte3); - return; - } - - // 3. NORMAL MIDI MESSAGES - grid_midi_rx_push_normal(byte0, byte1, byte2, byte3); -} - -void grid_midi_sysex_rx_pop(); - -void grid_midi_rx_pop() { - - if (!grid_swsr_readable(&grid_midi_rx, sizeof(struct grid_midi_event_desc))) { - return; - } - - struct grid_msg msg = {0}; - uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; - grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); + grid_swsr_read(&grid_macro_state.tx, NULL, grid_swsr_size(&grid_macro_state.tx)); + grid_macro_state.has_next = false; - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); - - // Combine up to 8 midi messages into a packet - for (uint8_t i = 0; i < 8; ++i) { - - if (!grid_swsr_readable(&grid_midi_rx, sizeof(struct grid_midi_event_desc))) { - break; - } - - struct grid_midi_event_desc event; - grid_swsr_read(&grid_midi_rx, &event, sizeof(struct grid_midi_event_desc)); - - grid_msg_add_frame(&msg, GRID_CLASS_MIDI_frame); - grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); - - grid_msg_set_parameter(&msg, CLASS_MIDI_CHANNEL, event.byte1 & 0x0f); - grid_msg_set_parameter(&msg, CLASS_MIDI_COMMAND, event.byte1 & 0xf0); - grid_msg_set_parameter(&msg, CLASS_MIDI_PARAM1, event.byte2); - grid_msg_set_parameter(&msg, CLASS_MIDI_PARAM2, event.byte3); - } - - if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { - uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIVOICE); - if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { - grid_transport_send_msg_to_all(&grid_transport_state, &msg); - } else { - grid_transport_send_msg_to_ui(&grid_transport_state, &msg); - } - } + grid_swsr_read(&grid_gamepad_state.tx, NULL, grid_swsr_size(&grid_gamepad_state.tx)); } -bool grid_midi_rx_writable() { return grid_swsr_writable(&grid_midi_rx, sizeof(struct grid_midi_event_desc)); } - -void grid_midi_rtm_rx_pop(void) { - - if (!grid_swsr_readable(&grid_midi_rtm_rx, 1)) { - return; - } - - struct grid_msg msg = {0}; - uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; - grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); - - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); +void tud_mount_cb(void) { grid_usb_on_connect(); } - for (uint8_t i = 0; i < 16; ++i) { +void tud_umount_cb(void) { grid_usb_on_disconnect(); } - if (!grid_swsr_readable(&grid_midi_rtm_rx, 1)) { - break; - } - - uint8_t rtm_byte; - grid_swsr_read(&grid_midi_rtm_rx, &rtm_byte, 1); - - grid_msg_add_frame(&msg, GRID_CLASS_MIDIRTM_frame); - grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); - grid_msg_set_parameter(&msg, CLASS_MIDIRTM_BYTE, rtm_byte); - } - - if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { - uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIRTM); - if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { - grid_transport_send_msg_to_all(&grid_transport_state, &msg); - } else { - grid_transport_send_msg_to_ui(&grid_transport_state, &msg); - } - } +void grid_usb_infrastructure_init(void) { + grid_usb_acm_init(&grid_usb_acm_state, GRID_PARAMETER_SPI_TRANSACTION_length * 2); + grid_usb_midi_init(&grid_usb_midi_state, GRID_MIDI_TX_BUFFER_SIZE, GRID_MIDI_VOICE_RX_BUFFER_SIZE, GRID_MIDI_SYSEX_BUFFER_SIZE, GRID_MIDI_RTM_BUFFER_SIZE); + grid_usb_keyboard_init(&grid_keyboard_state); + grid_usb_mouse_init(&grid_mouse_state); + grid_usb_macro_init(&grid_macro_state, GRID_MACRO_TX_BUFFER_SIZE, &grid_keyboard_state, &grid_mouse_state); + grid_usb_gamepad_init(&grid_gamepad_state, GRID_GAMEPAD_TX_BUFFER_SIZE); } - -static void grid_midi_sysex_process_complete(uint8_t* sysex_data, uint16_t length) { - - if (length < 2 || sysex_data[0] != GRID_MIDI_SYSEX_START || sysex_data[length - 1] != GRID_MIDI_SYSEX_END) { - return; // Invalid SysEx message - } - - struct grid_msg msg = {0}; - uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; - grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); - - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); - grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); - - grid_msg_add_frame(&msg, GRID_CLASS_MIDISYSEX_frame_start); - grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); - - grid_msg_set_parameter(&msg, CLASS_MIDISYSEX_LENGTH, length); - - if (grid_msg_add_hex_bytes(&msg, sysex_data, length) < 0) { - return; // Data overrun, data loss occurred - } - - grid_msg_add_frame(&msg, GRID_CLASS_MIDISYSEX_frame_end); - - if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { - uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDISYSEX); - if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { - grid_transport_send_msg_to_all(&grid_transport_state, &msg); - } else { - grid_transport_send_msg_to_ui(&grid_transport_state, &msg); - } - } -} - -void grid_midi_sysex_rx_pop() { - - uint8_t byte = 0; - while (byte != GRID_MIDI_SYSEX_END) { - - if (!grid_swsr_readable(&grid_midi_sysex_rx, 1)) { - return; - } - - grid_swsr_read(&grid_midi_sysex_rx, &byte, 1); - - if (sysex_assembly_index >= GRID_MIDI_SYSEX_RX_BUFFER_length) { - sysex_assembly_index = 0; - } - - assert(sysex_assembly_index < GRID_MIDI_SYSEX_RX_BUFFER_length); - sysex_assembly_buffer[sysex_assembly_index++] = byte; - } - - assert(byte == GRID_MIDI_SYSEX_END); - grid_midi_sysex_process_complete(sysex_assembly_buffer, sysex_assembly_index); - sysex_assembly_index = 0; -} - -uint8_t grid_usb_keyboard_tx_push(struct grid_usb_keyboard_model* kb, struct grid_usb_keyboard_event_desc keyboard_event) { - - // printf("R: %d, W: %d\r\n", grid_midi_tx_read_index, - // grid_midi_tx_write_index); printf("kb tx R: %d, W: %d\r\n", - // kb->tx_read_index, kb->tx_write_index); - - kb->tx_buffer[kb->tx_write_index] = keyboard_event; - - kb->tx_write_index = (kb->tx_write_index + 1) % kb->tx_buffer_length; - - uint32_t space_in_buffer = (kb->tx_read_index - kb->tx_write_index + kb->tx_buffer_length) % kb->tx_buffer_length; - - uint8_t return_packet_was_dropped = 0; - - if (space_in_buffer == 0) { - return_packet_was_dropped = 1; - // Increment the read index to drop latest packet and make space for a new - // one. - kb->tx_read_index = (kb->tx_read_index + 1) % kb->tx_buffer_length; - } - - // printf("W: %d %d : %d\r\n", kb->tx_write_index, kb->tx_read_index, - // space_in_buffer); - - return return_packet_was_dropped; -} - -void grid_usb_keyboard_tx_pop(struct grid_usb_keyboard_model* kb) { - - if (!grid_usb_keyboard_tx_readable(kb)) { - return; - } - - struct grid_usb_keyboard_event_desc key; - - key.ismodifier = kb->tx_buffer[kb->tx_read_index].ismodifier; - key.keycode = kb->tx_buffer[kb->tx_read_index].keycode; - key.ispressed = kb->tx_buffer[kb->tx_read_index].ispressed; - key.delay = 0; - - // 0: no, 1: yes, 2: mousemove, 3: mousebutton, f: delay - - if (key.ismodifier == 0 || key.ismodifier == 1) { - // Keyboard event - if (grid_usb_keyboard_keychange(&grid_usb_keyboard_state, &key)) { - return; // USB busy, keep event in buffer for retry - } - } else if (key.ismodifier == 2) { - // Mouse move - uint8_t axis = key.keycode; - int8_t position = key.ispressed - 128; - if (grid_platform_usb_mouse_move(position, axis)) { - return; // USB busy, keep event in buffer for retry - } - } else if (key.ismodifier == 3) { - // Mouse button - uint8_t state = key.ispressed; - uint8_t button = key.keycode; - if (grid_platform_usb_mouse_button_change(state, button)) { - return; // USB busy, keep event in buffer for retry - } - } else if (key.ismodifier == 0xf) { - // Delay event, nothing to do - } else { - // Invalid event type, discard - } - - // Event successfully processed, advance read pointer - kb->tx_read_index = (kb->tx_read_index + 1) % kb->tx_buffer_length; - kb->tx_rtc_lasttimestamp = grid_platform_rtc_get_micros(); -} - -bool grid_usb_keyboard_tx_readable(struct grid_usb_keyboard_model* kb) { - - if (kb->tx_read_index == kb->tx_write_index) { - return false; - } - - uint64_t elapsed = grid_platform_rtc_get_elapsed_time(kb->tx_rtc_lasttimestamp); - - return elapsed > kb->tx_buffer[kb->tx_read_index].delay * MS_TO_US; -} - -void grid_usb_gamepad_axis_move(uint8_t axis, int32_t move) { grid_platform_usb_gamepad_axis_move(axis, move); } - -void grid_usb_gamepad_button_change(uint8_t button, uint8_t value) { grid_platform_usb_gamepad_button_change(button, value); } - -void grid_usb_keyboard_enable(struct grid_usb_keyboard_model* kb) { kb->isenabled = 1; } - -void grid_usb_keyboard_disable(struct grid_usb_keyboard_model* kb) { kb->isenabled = 0; } - -uint8_t grid_usb_keyboard_isenabled(struct grid_usb_keyboard_model* kb) { return kb->isenabled; } diff --git a/common/src/c/grid_usb.h b/common/src/c/grid_usb.h index 97b74296..86c1e766 100644 --- a/common/src/c/grid_usb.h +++ b/common/src/c/grid_usb.h @@ -11,149 +11,23 @@ #include #include +// Pull in CFG_TUD_CDC / CFG_TUD_MIDI / CFG_TUD_HID for the language server +#include "tusb_config.h" + #include "grid_sys.h" #include "grid_transport.h" - -extern int32_t grid_platform_usb_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); -extern int32_t grid_platform_usb_midi_write_status(void); -extern int32_t grid_platform_usb_mouse_button_change(uint8_t b_state, uint8_t type); -extern int32_t grid_platform_usb_mouse_move(int8_t position, uint8_t axis); - -int32_t grid_platform_usb_gamepad_axis_move(uint8_t axis, int32_t value); -int32_t grid_platform_usb_gamepad_button_change(uint8_t button, uint8_t value); +#include "grid_usb_hid.h" +#include "grid_usb_midi.h" extern uint64_t grid_platform_rtc_get_elapsed_time(uint64_t told); extern void grid_platform_sync1_pulse_send(); -void grid_usb_midi_buffer_init(); - -enum grid_usb_keyboard_key_state_t { GRID_USB_KEYBOARD_KEY_STATEUP, GRID_USB_KEYBOARD_KEY_STATEDOWN }; - -// USB MIDI Code Index Number (CIN) values -enum grid_midi_cin_type { - GRID_MIDI_CIN_MISC = 0x00, // Miscellaneous function codes - GRID_MIDI_CIN_CABLE_EVENT = 0x01, // Cable events - GRID_MIDI_CIN_SYSCOM_2BYTE = 0x02, // Two-byte System Common (MTC, SongSelect) - GRID_MIDI_CIN_SYSCOM_3BYTE = 0x03, // Three-byte System Common (SPP) - GRID_MIDI_CIN_SYSEX_START = 0x04, // SysEx starts or continues (3 bytes) - GRID_MIDI_CIN_SYSEX_END_1BYTE = 0x05, // SysEx ends with 1 byte or single-byte System Common - GRID_MIDI_CIN_SYSEX_END_2BYTE = 0x06, // SysEx ends with 2 bytes - GRID_MIDI_CIN_SYSEX_END_3BYTE = 0x07, // SysEx ends with 3 bytes - GRID_MIDI_CIN_NOTE_OFF = 0x08, // Note-off - GRID_MIDI_CIN_NOTE_ON = 0x09, // Note-on - GRID_MIDI_CIN_POLY_KEYPRESS = 0x0A, // Poly-KeyPress - GRID_MIDI_CIN_CONTROL_CHANGE = 0x0B, // Control Change - GRID_MIDI_CIN_PROGRAM_CHANGE = 0x0C, // Program Change - GRID_MIDI_CIN_CHANNEL_PRESSURE = 0x0D, // Channel Pressure - GRID_MIDI_CIN_PITCHBEND = 0x0E, // PitchBend Change - GRID_MIDI_CIN_SINGLE_BYTE = 0x0F // Single Byte (including Real-Time) -}; - -// MIDI System messages -enum grid_midi_system_type { GRID_MIDI_SYSEX_START = 0xF0, GRID_MIDI_SYSEX_END = 0xF7 }; - -// MIDI Real-Time Message bytes -enum grid_midi_rtm_type { - GRID_MIDI_RTM_TIMING_CLOCK = 0xF8, - GRID_MIDI_RTM_UNDEFINED_F9 = 0xF9, - GRID_MIDI_RTM_START = 0xFA, - GRID_MIDI_RTM_CONTINUE = 0xFB, - GRID_MIDI_RTM_STOP = 0xFC, - GRID_MIDI_RTM_UNDEFINED_FD = 0xFD, - GRID_MIDI_RTM_ACTIVE_SENSING = 0xFE, - GRID_MIDI_RTM_SYSTEM_RESET = 0xFF -}; - -struct grid_midi_event_desc { - - uint8_t byte0; - uint8_t byte1; - uint8_t byte2; - uint8_t byte3; -}; - -#define GRID_MIDI_TX_BUFFER_length 128 - -extern struct grid_midi_event_desc grid_midi_tx_buffer[GRID_MIDI_TX_BUFFER_length]; -extern uint16_t grid_midi_tx_write_index; -extern uint16_t grid_midi_tx_read_index; - -uint8_t grid_midi_tx_push(struct grid_midi_event_desc midi_event); -void grid_midi_tx_pop(); -bool grid_midi_tx_readable(); - -#define GRID_MIDI_RX_BUFFER_length 128 - -extern struct grid_midi_event_desc grid_midi_rx_buffer[GRID_MIDI_RX_BUFFER_length]; -extern uint16_t grid_midi_rx_write_index; -extern uint16_t grid_midi_rx_read_index; - -void grid_midi_rx_push(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); -void grid_midi_rx_pop(); -bool grid_midi_rx_writable(); - -// MIDI SysEx RX buffer (raw bytes) -#define GRID_MIDI_SYSEX_RX_BUFFER_length 256 - -// MIDI Real-Time Message RX buffer (raw bytes) -#define GRID_MIDI_RTM_RX_BUFFER_length 32 - -void grid_midi_rtm_rx_pop(void); -void grid_midi_sysex_rx_pop(); - -struct grid_usb_keyboard_event_desc { - - uint8_t keycode; - uint8_t ismodifier; - uint8_t ispressed; - uint32_t delay; -}; - -/** Describes the USB HID Keyboard Key descriptors. */ -struct grid_usb_hid_kb_desc { - /* HID Key Value, defined in usb_protocol_hid.h */ - uint8_t key_id; - /* Flag whether it is a modifier key */ - bool b_modifier; - /* Key State */ - enum grid_usb_keyboard_key_state_t state; -}; - -#define GRID_KEYBOARD_KEY_maxcount 6 - -struct grid_usb_keyboard_model { - - uint8_t tx_buffer_length; - struct grid_usb_keyboard_event_desc* tx_buffer; - - uint16_t tx_write_index; - uint16_t tx_read_index; - uint64_t tx_rtc_lasttimestamp; - - struct grid_usb_keyboard_event_desc active_key_list[GRID_KEYBOARD_KEY_maxcount]; - uint8_t active_key_count; - - uint8_t isenabled; -}; - -uint8_t grid_usb_keyboard_tx_push(struct grid_usb_keyboard_model* kb, struct grid_usb_keyboard_event_desc keyboard_event); -void grid_usb_keyboard_tx_pop(struct grid_usb_keyboard_model* kb); -bool grid_usb_keyboard_tx_readable(struct grid_usb_keyboard_model* kb); - -extern struct grid_usb_keyboard_model grid_usb_keyboard_state; - -void grid_usb_keyboard_model_init(struct grid_usb_keyboard_model* kb, uint8_t buffer_length); - -uint8_t grid_usb_keyboard_cleanup(struct grid_usb_keyboard_model* kb); - -int32_t grid_usb_keyboard_keychange(struct grid_usb_keyboard_model* kb, struct grid_usb_keyboard_event_desc* key); - -void grid_usb_gamepad_axis_move(uint8_t axis, int32_t move); -void grid_usb_gamepad_button_change(uint8_t button, uint8_t value); +void grid_usb_infrastructure_init(void); -void grid_usb_keyboard_enable(struct grid_usb_keyboard_model* kb); -void grid_usb_keyboard_disable(struct grid_usb_keyboard_model* kb); -uint8_t grid_usb_keyboard_isenabled(struct grid_usb_keyboard_model* kb); +bool grid_usb_connected(void); +void grid_usb_task(void); +void grid_usb_on_connect(void); +void grid_usb_on_disconnect(void); #endif /* GRID_USB_H */ diff --git a/common/src/c/grid_usb_acm.c b/common/src/c/grid_usb_acm.c new file mode 100644 index 00000000..135dcb3a --- /dev/null +++ b/common/src/c/grid_usb_acm.c @@ -0,0 +1,129 @@ +#include "grid_usb_acm.h" + +#include + +#include "tusb.h" + +#include "grid_msg.h" +#include "grid_platform.h" +#include "grid_protocol.h" +#include "grid_swsr.h" +#include "grid_transport.h" +#include "grid_usb.h" + +#if CFG_TUD_CDC + +struct grid_usb_acm_model grid_usb_acm_state; + +static uint8_t acm_rx_buf[512]; + +void tud_cdc_rx_cb(uint8_t itf) { + (void)itf; + + uint32_t available = tud_cdc_available(); + if (available == 0) { + return; + } + + struct grid_swsr_t* rx = &grid_usb_acm_state.rx; + uint32_t to_read = available < sizeof(acm_rx_buf) ? available : sizeof(acm_rx_buf); + + if (!grid_swsr_writable(rx, to_read)) { + return; + } + + uint32_t rx_size = tud_cdc_read(acm_rx_buf, to_read); + if (rx_size == 0) { + return; + } + + assert(rx_size <= to_read); + assert(grid_swsr_writable(rx, rx_size)); + grid_swsr_write(rx, acm_rx_buf, rx_size); +} + +void grid_usb_acm_rx_process(struct grid_usb_acm_model* usb_acm) { + + struct grid_msg msg; + if (!grid_msg_from_swsr(&msg, &usb_acm->rx)) { + return; + } + + if (grid_frame_verify((uint8_t*)msg.data, msg.length) == 0) { + grid_transport_recv_usb(&grid_transport_state, (uint8_t*)msg.data, msg.length); + } +} + +void grid_usb_acm_rx_poll(struct grid_usb_acm_model* usb_acm) { + (void)usb_acm; + tud_cdc_rx_cb(0); +} + +void tud_cdc_tx_complete_cb(uint8_t itf) { + (void)itf; + if (tud_cdc_write_available() == CFG_TUD_CDC_TX_BUFSIZE) { + grid_usb_acm_state.tx_ready = 1; + } +} + +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { + (void)itf; + (void)rts; + grid_usb_acm_state.dtr = dtr; + if (dtr) { + grid_usb_acm_state.tx_ready = 1; + } +} + +int32_t grid_usb_acm_tx_ready(struct grid_usb_acm_model* usb_acm) { return usb_acm->tx_ready; } + +bool grid_usb_acm_dtr(struct grid_usb_acm_model* usb_acm) { return usb_acm->dtr; } + +int32_t grid_usb_acm_write(struct grid_usb_acm_model* usb_acm, char* buffer, uint32_t length) { + if (!usb_acm->tx_ready || tud_cdc_write_available() < length) { + usb_acm->tx_dropped++; + return 0; + } + usb_acm->tx_ready = 0; + uint32_t written = tud_cdc_write(buffer, length); + if (written != length) { + usb_acm->tx_dropped++; + } + tud_cdc_write_flush(); + return (int32_t)written; +} + +void grid_usb_acm_init(struct grid_usb_acm_model* usb_acm, uint16_t rx_buffer_size) { + assert(grid_swsr_malloc(&usb_acm->rx, rx_buffer_size) == 0); + usb_acm->tx_ready = 1; +} + +#else // !CFG_TUD_CDC + +int32_t grid_usb_acm_tx_ready(struct grid_usb_acm_model* usb_acm) { + (void)usb_acm; + return 0; +} + +bool grid_usb_acm_dtr(struct grid_usb_acm_model* usb_acm) { + (void)usb_acm; + return false; +} + +int32_t grid_usb_acm_write(struct grid_usb_acm_model* usb_acm, char* buffer, uint32_t length) { + (void)usb_acm; + (void)buffer; + (void)length; + return 0; +} + +void grid_usb_acm_init(struct grid_usb_acm_model* usb_acm, uint16_t rx_buffer_size) { + (void)usb_acm; + (void)rx_buffer_size; +} + +void grid_usb_acm_rx_poll(struct grid_usb_acm_model* usb_acm) { (void)usb_acm; } + +void grid_usb_acm_rx_process(struct grid_usb_acm_model* usb_acm) { (void)usb_acm; } + +#endif // CFG_TUD_CDC diff --git a/common/src/c/grid_usb_acm.h b/common/src/c/grid_usb_acm.h new file mode 100644 index 00000000..24ef296c --- /dev/null +++ b/common/src/c/grid_usb_acm.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "grid_swsr.h" + +struct grid_usb_acm_model { + struct grid_swsr_t rx; + uint8_t tx_ready; + bool dtr; + uint32_t tx_dropped; +}; + +extern struct grid_usb_acm_model grid_usb_acm_state; + +void grid_usb_acm_init(struct grid_usb_acm_model* usb_acm, uint16_t rx_buffer_size); + +int32_t grid_usb_acm_tx_ready(struct grid_usb_acm_model* usb_acm); +bool grid_usb_acm_dtr(struct grid_usb_acm_model* usb_acm); +int32_t grid_usb_acm_write(struct grid_usb_acm_model* usb_acm, char* buffer, uint32_t length); +void grid_usb_acm_rx_poll(struct grid_usb_acm_model* usb_acm); +void grid_usb_acm_rx_process(struct grid_usb_acm_model* usb_acm); diff --git a/common/src/c/grid_usb_hid.c b/common/src/c/grid_usb_hid.c new file mode 100644 index 00000000..7cf850a4 --- /dev/null +++ b/common/src/c/grid_usb_hid.c @@ -0,0 +1,381 @@ +#include + +#include "tusb.h" + +#include "grid_usb_hid.h" + +#include "grid_msg.h" +#include "grid_platform.h" +#include "grid_usb.h" + +struct grid_macro_model grid_macro_state = {0}; +struct grid_keyboard_model grid_keyboard_state = {0}; +struct grid_mouse_model grid_mouse_state = {0}; +struct grid_gamepad_model grid_gamepad_state = {0}; + +static struct grid_keyboard_report grid_usb_keyboard_report_build(struct grid_keyboard_model* usb_keyboard); +static int32_t grid_usb_keyboard_report_send(struct grid_keyboard_report* report); +static bool grid_usb_hid_ready(void); +static int32_t grid_usb_mouse_button_change(struct grid_mouse_model* usb_mouse, uint8_t b_state, uint8_t type); +static int32_t grid_usb_mouse_move(struct grid_mouse_model* usb_mouse, int8_t position, uint8_t axis); +static int32_t grid_usb_gamepad_report_send(struct grid_gamepad_model* usb_gamepad); + +void grid_usb_keyboard_init(struct grid_keyboard_model* usb_keyboard) { + + for (uint8_t i = 0; i < GRID_KEYBOARD_KEY_maxcount; i++) { + usb_keyboard->active_key_list[i].type = GRID_MACRO_EVENT_TYPE_KEY; + usb_keyboard->active_key_list[i].ispressed = 0; + } + + usb_keyboard->active_key_count = 0; + usb_keyboard->isenabled = 1; +} + +void grid_usb_macro_init(struct grid_macro_model* usb_macro, uint16_t buffer_size, struct grid_keyboard_model* usb_keyboard, struct grid_mouse_model* usb_mouse) { + + usb_macro->tx_rtc_lasttimestamp = grid_platform_rtc_get_micros(); + usb_macro->has_next = false; + usb_macro->keyboard = usb_keyboard; + usb_macro->mouse = usb_mouse; + + assert(grid_swsr_malloc(&usb_macro->tx, buffer_size) == 0); +} + +void grid_usb_mouse_init(struct grid_mouse_model* usb_mouse) { usb_mouse->buttons = 0; } + +void grid_usb_gamepad_init(struct grid_gamepad_model* usb_gamepad, uint16_t buffer_size) { + usb_gamepad->buttons = 0; + usb_gamepad->hat = 0; + for (uint8_t i = 0; i < GAMEPAD_AXIS_COUNT; i++) { + usb_gamepad->axis[i] = 0; + } + assert(grid_swsr_malloc(&usb_gamepad->tx, buffer_size) == 0); +} + +int32_t grid_usb_gamepad_axis_move(struct grid_gamepad_model* usb_gamepad, uint8_t axis, int32_t value) { + (void)usb_gamepad; + if (axis >= GAMEPAD_AXIS_COUNT) { + return 0; + } + struct grid_gamepad_event_desc event = {.type = GRID_GAMEPAD_EVENT_AXIS, .index = axis, .value = (uint8_t)(value + 128)}; + return grid_usb_gamepad_tx_push(&grid_gamepad_state, event); +} + +int32_t grid_usb_gamepad_button_change(struct grid_gamepad_model* usb_gamepad, uint8_t button, uint8_t value) { + (void)usb_gamepad; + struct grid_gamepad_event_desc event = {.type = GRID_GAMEPAD_EVENT_BUTTON, .index = button, .value = value}; + return grid_usb_gamepad_tx_push(&grid_gamepad_state, event); +} + +static uint8_t grid_usb_keyboard_cleanup(struct grid_keyboard_model* usb_keyboard) { + + uint8_t changed_flag = 0; + + for (uint8_t i = 0; i < usb_keyboard->active_key_count; i++) { + + if (usb_keyboard->active_key_list[i].ispressed == false) { + + changed_flag = 1; + + for (uint8_t j = i + 1; j < usb_keyboard->active_key_count; j++) { + usb_keyboard->active_key_list[j - 1] = usb_keyboard->active_key_list[j]; + } + + usb_keyboard->active_key_count--; + i--; + } + } + + return changed_flag; +} + +static int32_t grid_usb_keyboard_keychange(struct grid_keyboard_model* usb_keyboard, struct grid_macro_event_desc* key) { + + bool found = false; + uint8_t changed_flag = 0; + + for (uint8_t i = 0; i < usb_keyboard->active_key_count; i++) { + + if (usb_keyboard->active_key_list[i].keycode == key->keycode && usb_keyboard->active_key_list[i].type == key->type) { + found = true; + + if (usb_keyboard->active_key_list[i].ispressed == true) { + + if (key->ispressed == true) { + } else { + usb_keyboard->active_key_list[i].ispressed = false; + changed_flag = 1; + } + } + } + } + + grid_usb_keyboard_cleanup(usb_keyboard); + + if (!found) { + + if (usb_keyboard->active_key_count < GRID_KEYBOARD_KEY_maxcount) { + + if (key->ispressed == true) { + + usb_keyboard->active_key_list[usb_keyboard->active_key_count] = *key; + usb_keyboard->active_key_count++; + changed_flag = 1; + } + } else { + } + } + + if (changed_flag == 1) { + + if (usb_keyboard->isenabled) { + + struct grid_keyboard_report report = grid_usb_keyboard_report_build(usb_keyboard); + return grid_usb_keyboard_report_send(&report); + } else { + + grid_port_debug_print_text("KB IS DISABLED"); + + struct grid_msg msg; + uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; + grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); + + grid_msg_add_frame(&msg, GRID_CLASS_HIDKEYSTATUS_frame); + grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); + grid_msg_set_parameter(&msg, CLASS_HIDKEYSTATUS_ISENABLED, usb_keyboard->isenabled); + + if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { + grid_transport_send_msg_to_all(&grid_transport_state, &msg); + } + + return 0; + } + } + + return 0; +} + +static struct grid_keyboard_report grid_usb_keyboard_report_build(struct grid_keyboard_model* usb_keyboard) { + assert(usb_keyboard->active_key_count <= GRID_KEYBOARD_KEY_maxcount); + + struct grid_keyboard_report report = {0}; + uint8_t key_idx = 0; + + for (uint8_t i = 0; i < usb_keyboard->active_key_count; i++) { + if (usb_keyboard->active_key_list[i].type == GRID_MACRO_EVENT_TYPE_MODIFIER) { + report.modifier_bm |= usb_keyboard->active_key_list[i].keycode; + } else if (usb_keyboard->active_key_list[i].ispressed && key_idx < 6) { + report.keycode[key_idx++] = usb_keyboard->active_key_list[i].keycode; + } + } + + return report; +} + +uint8_t grid_usb_macro_tx_push(struct grid_macro_model* usb_macro, struct grid_macro_event_desc event) { + + if (!grid_usb_connected()) { + usb_macro->tx_dropped++; + return 1; + } + + uint8_t dropped = 0; + + if (!grid_swsr_writable(&usb_macro->tx, sizeof(struct grid_macro_event_desc))) { + grid_swsr_read(&usb_macro->tx, NULL, sizeof(struct grid_macro_event_desc)); + usb_macro->tx_dropped++; + dropped = 1; + } + + grid_swsr_write(&usb_macro->tx, &event, sizeof(struct grid_macro_event_desc)); + + return dropped; +} + +uint8_t grid_usb_gamepad_tx_push(struct grid_gamepad_model* usb_gamepad, struct grid_gamepad_event_desc event) { + + if (!grid_usb_connected()) { + usb_gamepad->tx_dropped++; + return 1; + } + + uint8_t dropped = 0; + + if (!grid_swsr_writable(&usb_gamepad->tx, sizeof(struct grid_gamepad_event_desc))) { + grid_swsr_read(&usb_gamepad->tx, NULL, sizeof(struct grid_gamepad_event_desc)); + usb_gamepad->tx_dropped++; + dropped = 1; + } + + grid_swsr_write(&usb_gamepad->tx, &event, sizeof(struct grid_gamepad_event_desc)); + + return dropped; +} + +bool grid_usb_gamepad_tx_available(struct grid_gamepad_model* usb_gamepad) { return grid_swsr_readable(&usb_gamepad->tx, sizeof(struct grid_gamepad_event_desc)); } + +void grid_usb_gamepad_tx_flush(struct grid_gamepad_model* usb_gamepad) { + + if (!grid_swsr_readable(&usb_gamepad->tx, sizeof(struct grid_gamepad_event_desc))) { + return; + } + + if (!grid_usb_hid_ready()) { + return; + } + + struct grid_gamepad_event_desc event; + grid_swsr_read(&usb_gamepad->tx, &event, sizeof(struct grid_gamepad_event_desc)); + + if (event.type == GRID_GAMEPAD_EVENT_AXIS) { + if (event.index < GAMEPAD_AXIS_COUNT) { + usb_gamepad->axis[event.index] = (int8_t)(event.value - 128); + } + } else if (event.type == GRID_GAMEPAD_EVENT_BUTTON) { + if (event.value) { + usb_gamepad->buttons |= (1u << event.index); + } else { + usb_gamepad->buttons &= ~(1u << event.index); + } + } + + assert(grid_usb_gamepad_report_send(usb_gamepad) == 0); +} + +void grid_usb_macro_tx_flush(struct grid_macro_model* usb_macro) { + + if (!usb_macro->has_next) { + if (!grid_swsr_readable(&usb_macro->tx, sizeof(struct grid_macro_event_desc))) { + return; + } + grid_swsr_read(&usb_macro->tx, &usb_macro->next, sizeof(struct grid_macro_event_desc)); + usb_macro->has_next = true; + } + + uint64_t elapsed = grid_platform_rtc_get_elapsed_time(usb_macro->tx_rtc_lasttimestamp); + if (elapsed <= usb_macro->next.delay * MS_TO_US) { + return; + } + + if (usb_macro->next.type == GRID_MACRO_EVENT_TYPE_KEY || usb_macro->next.type == GRID_MACRO_EVENT_TYPE_MODIFIER) { + if (!grid_usb_hid_ready()) { + return; + } + if (grid_usb_keyboard_keychange(usb_macro->keyboard, &usb_macro->next)) { + return; + } + } else if (usb_macro->next.type == GRID_MACRO_EVENT_TYPE_MOUSE_MOVE) { + if (!grid_usb_hid_ready()) { + return; + } + uint8_t axis = usb_macro->next.keycode; + int8_t position = usb_macro->next.ispressed - 128; + if (grid_usb_mouse_move(usb_macro->mouse, position, axis)) { + return; + } + } else if (usb_macro->next.type == GRID_MACRO_EVENT_TYPE_MOUSE_BUTTON) { + if (!grid_usb_hid_ready()) { + return; + } + uint8_t state = usb_macro->next.ispressed; + uint8_t button = usb_macro->next.keycode; + if (grid_usb_mouse_button_change(usb_macro->mouse, state, button)) { + return; + } + } else if (usb_macro->next.type == GRID_MACRO_EVENT_TYPE_DELAY) { + } else { + } + + usb_macro->has_next = false; + usb_macro->tx_rtc_lasttimestamp = grid_platform_rtc_get_micros(); +} + +bool grid_usb_macro_tx_available(struct grid_macro_model* usb_macro) { return usb_macro->has_next || grid_swsr_readable(&usb_macro->tx, sizeof(struct grid_macro_event_desc)); } + +void grid_usb_keyboard_enable(struct grid_keyboard_model* usb_keyboard) { usb_keyboard->isenabled = 1; } + +void grid_usb_keyboard_disable(struct grid_keyboard_model* usb_keyboard) { usb_keyboard->isenabled = 0; } + +#if CFG_TUD_HID + +static const uint8_t s_hid_report_desc[] = {GRID_HID_REPORT_DESC_CONTENT}; + +uint8_t const* tud_hid_descriptor_report_cb(uint8_t instance) { + (void)instance; + return s_hid_report_desc; +} + +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) { + (void)instance; + (void)report_id; + (void)report_type; + (void)buffer; + (void)reqlen; + return 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) { + (void)instance; + (void)report_id; + (void)report_type; + (void)buffer; + (void)bufsize; +} + +static bool grid_usb_hid_ready(void) { return tud_hid_ready(); } + +static int32_t grid_usb_mouse_button_change(struct grid_mouse_model* usb_mouse, uint8_t b_state, uint8_t type) { + if (b_state) { + usb_mouse->buttons |= type; + } else { + usb_mouse->buttons &= (uint8_t)~type; + } + return 0 == tud_hid_mouse_report(HID_ITF_PROTOCOL_MOUSE, usb_mouse->buttons, 0, 0, 0, 0); +} + +static int32_t grid_usb_mouse_move(struct grid_mouse_model* usb_mouse, int8_t position, uint8_t axis) { + int8_t delta[3] = {0}; + if (axis < MOUSE_AXIS_X || axis >= MOUSE_AXIS_COUNT) { + return 0; + } + delta[axis - 1] = position; + return 0 == tud_hid_mouse_report(HID_ITF_PROTOCOL_MOUSE, usb_mouse->buttons, delta[0], delta[1], delta[2], 0); +} + +// Axes RX/RY/RZ (3,4,5) are passed in reverse order to match the HID descriptor layout. +static int32_t grid_usb_gamepad_report_send(struct grid_gamepad_model* usb_gamepad) { + return 0 == tud_hid_gamepad_report(3, usb_gamepad->axis[0], usb_gamepad->axis[1], usb_gamepad->axis[2], usb_gamepad->axis[5], usb_gamepad->axis[4], usb_gamepad->axis[3], usb_gamepad->hat, + usb_gamepad->buttons); +} + +static int32_t grid_usb_keyboard_report_send(struct grid_keyboard_report* report) { return 0 == tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, report->modifier_bm, report->keycode); } + +#else // !CFG_TUD_HID + +static bool grid_usb_hid_ready(void) { return true; } + +static int32_t grid_usb_mouse_button_change(struct grid_mouse_model* usb_mouse, uint8_t b_state, uint8_t type) { + (void)usb_mouse; + (void)b_state; + (void)type; + return 0; +} + +static int32_t grid_usb_mouse_move(struct grid_mouse_model* usb_mouse, int8_t position, uint8_t axis) { + (void)usb_mouse; + (void)position; + (void)axis; + return 0; +} + +static int32_t grid_usb_gamepad_report_send(struct grid_gamepad_model* usb_gamepad) { + (void)usb_gamepad; + return 0; +} + +static int32_t grid_usb_keyboard_report_send(struct grid_keyboard_report* report) { + (void)report; + return 0; +} + +#endif // CFG_TUD_HID diff --git a/common/src/c/grid_usb_hid.h b/common/src/c/grid_usb_hid.h new file mode 100644 index 00000000..db8ddf71 --- /dev/null +++ b/common/src/c/grid_usb_hid.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include + +#include "grid_swsr.h" + +enum mouse_move_type { MOUSE_AXIS_X = 0x01, MOUSE_AXIS_Y = 0x02, MOUSE_AXIS_SCROLL = 0x03, MOUSE_AXIS_COUNT = 0x04 }; + +enum gamepad_axis_t { GAMEPAD_AXIS_X = 0, GAMEPAD_AXIS_Y, GAMEPAD_AXIS_Z, GAMEPAD_AXIS_RX, GAMEPAD_AXIS_RY, GAMEPAD_AXIS_RZ, GAMEPAD_AXIS_COUNT }; + +#if CFG_TUD_HID + +#define GRID_HID_REPORT_DESC_EXTRA , TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(3)) + +#define GRID_HID_REPORT_DESC_CONTENT TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_ITF_PROTOCOL_KEYBOARD)), TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_ITF_PROTOCOL_MOUSE)) GRID_HID_REPORT_DESC_EXTRA + +#define GRID_HID_REPORT_DESC_SIZE sizeof((uint8_t[]){GRID_HID_REPORT_DESC_CONTENT}) + +#endif // CFG_TUD_HID + +#define GRID_MACRO_TX_BUFFER_SIZE 800 +#define GRID_GAMEPAD_TX_BUFFER_SIZE 64 + +enum grid_macro_event_type { + GRID_MACRO_EVENT_TYPE_KEY = 0, // regular (non-modifier) key press/release + GRID_MACRO_EVENT_TYPE_MODIFIER = 1, // modifier key press/release (Ctrl, Shift, …) + GRID_MACRO_EVENT_TYPE_MOUSE_MOVE = 2, // mouse axis movement + GRID_MACRO_EVENT_TYPE_MOUSE_BUTTON = 3, // mouse button press/release + GRID_MACRO_EVENT_TYPE_DELAY = 0xf, // timed delay between events +}; + +struct grid_macro_event_desc { + + uint8_t keycode; + enum grid_macro_event_type type; + uint8_t ispressed; + uint32_t delay; +}; + +enum grid_gamepad_event_type { + GRID_GAMEPAD_EVENT_AXIS = 0, + GRID_GAMEPAD_EVENT_BUTTON = 1, +}; + +struct grid_gamepad_event_desc { + uint8_t type; + uint8_t index; + uint8_t value; // axis: int8_t encoded as value+128; button: 0/1 + uint8_t _pad; +}; + +#define GRID_KEYBOARD_KEY_maxcount 6 + +struct grid_macro_model { + struct grid_swsr_t tx; + struct grid_macro_event_desc next; + bool has_next; + uint64_t tx_rtc_lasttimestamp; + uint32_t tx_dropped; + struct grid_keyboard_model* keyboard; + struct grid_mouse_model* mouse; +}; + +struct grid_keyboard_model { + struct grid_macro_event_desc active_key_list[GRID_KEYBOARD_KEY_maxcount]; + uint8_t active_key_count; + uint8_t isenabled; +}; + +struct grid_keyboard_report { + uint8_t modifier_bm; + uint8_t keycode[6]; +}; + +struct grid_mouse_model { + uint8_t buttons; +}; + +struct grid_gamepad_model { + struct grid_swsr_t tx; + uint32_t tx_dropped; + uint32_t buttons; + int8_t axis[GAMEPAD_AXIS_COUNT]; + uint8_t hat; +}; + +extern struct grid_macro_model grid_macro_state; +extern struct grid_keyboard_model grid_keyboard_state; +extern struct grid_mouse_model grid_mouse_state; +extern struct grid_gamepad_model grid_gamepad_state; + +int32_t grid_usb_gamepad_axis_move(struct grid_gamepad_model* usb_gamepad, uint8_t axis, int32_t value); +int32_t grid_usb_gamepad_button_change(struct grid_gamepad_model* usb_gamepad, uint8_t button, uint8_t value); + +uint8_t grid_usb_gamepad_tx_push(struct grid_gamepad_model* usb_gamepad, struct grid_gamepad_event_desc event); +void grid_usb_gamepad_tx_flush(struct grid_gamepad_model* usb_gamepad); +bool grid_usb_gamepad_tx_available(struct grid_gamepad_model* usb_gamepad); + +uint8_t grid_usb_macro_tx_push(struct grid_macro_model* usb_macro, struct grid_macro_event_desc event); +void grid_usb_macro_tx_flush(struct grid_macro_model* usb_macro); +bool grid_usb_macro_tx_available(struct grid_macro_model* usb_macro); + +void grid_usb_macro_init(struct grid_macro_model* usb_macro, uint16_t buffer_size, struct grid_keyboard_model* usb_keyboard, struct grid_mouse_model* usb_mouse); +void grid_usb_keyboard_init(struct grid_keyboard_model* usb_keyboard); +void grid_usb_mouse_init(struct grid_mouse_model* usb_mouse); +void grid_usb_gamepad_init(struct grid_gamepad_model* usb_gamepad, uint16_t buffer_size); + +void grid_usb_keyboard_enable(struct grid_keyboard_model* usb_keyboard); +void grid_usb_keyboard_disable(struct grid_keyboard_model* usb_keyboard); diff --git a/common/src/c/grid_usb_midi.c b/common/src/c/grid_usb_midi.c new file mode 100644 index 00000000..894e2616 --- /dev/null +++ b/common/src/c/grid_usb_midi.c @@ -0,0 +1,309 @@ +#include "grid_usb_midi.h" + +#include + +#include "tusb.h" + +#include "grid_msg.h" +#include "grid_platform.h" +#include "grid_swsr.h" +#include "grid_transport.h" +#include "grid_usb.h" + +struct grid_usb_midi_model grid_usb_midi_state; + +void grid_usb_midi_init(struct grid_usb_midi_model* usb_midi, uint16_t tx_buffer_size, uint16_t rx_buffer_size, uint16_t sysex_buffer_size, uint16_t rtm_buffer_size) { + + assert(grid_swsr_malloc(&usb_midi->tx, tx_buffer_size) == 0); + assert(grid_swsr_malloc(&usb_midi->voice_rx, rx_buffer_size) == 0); + + assert(grid_swsr_malloc(&usb_midi->sysex_rx, sysex_buffer_size) == 0); + assert(grid_swsr_malloc(&usb_midi->rtm_rx, rtm_buffer_size) == 0); +} + +uint8_t grid_usb_midi_tx_push(struct grid_usb_midi_model* usb_midi, struct grid_midi_event_desc event) { + + if (!grid_usb_connected()) { + usb_midi->tx_dropped++; + return 1; + } + + uint8_t dropped = 0; + + if (!grid_swsr_writable(&usb_midi->tx, sizeof(struct grid_midi_event_desc))) { + + grid_swsr_read(&usb_midi->tx, NULL, sizeof(struct grid_midi_event_desc)); + + usb_midi->tx_dropped++; + dropped = 1; + } + + grid_swsr_write(&usb_midi->tx, &event, sizeof(struct grid_midi_event_desc)); + + return dropped; +} + +void grid_usb_midi_tx_flush(struct grid_usb_midi_model* usb_midi) { + + if (!tud_midi_mounted()) { + return; + } + + uint32_t n_packets = tud_midi_tx_available() / 4; + if (n_packets == 0) { + return; + } + + uint32_t ring_packets = grid_swsr_size(&usb_midi->tx) / 4; + if (ring_packets == 0) { + return; + } + + if (n_packets > ring_packets) { + n_packets = ring_packets; + } + + uint8_t batch[CFG_TUD_MIDI_TX_BUFSIZE]; + grid_swsr_read(&usb_midi->tx, batch, n_packets * 4); + tud_midi_packet_write_n(batch, n_packets); +} + +bool grid_usb_midi_tx_available(struct grid_usb_midi_model* usb_midi) { return grid_swsr_readable(&usb_midi->tx, 4); } + +static void grid_usb_midi_rx_queue_rtm(struct grid_usb_midi_model* usb_midi, uint8_t rtm_byte) { + if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIRTM) & GRID_RX_MODE_FORWARD_FROM_USB)) { + return; + } + assert(grid_swsr_writable(&usb_midi->rtm_rx, 1)); + grid_swsr_write(&usb_midi->rtm_rx, &rtm_byte, 1); +} + +static int grid_midi_rx_process_sysex(struct grid_usb_midi_model* usb_midi, uint8_t cin, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + + bool is_sysex_start = (cin == GRID_MIDI_CIN_SYSEX_START && byte1 == GRID_MIDI_SYSEX_START); + + if (!usb_midi->sysex_in_progress && !is_sysex_start) { + return 0; + } + + usb_midi->sysex_in_progress = (cin == GRID_MIDI_CIN_SYSEX_START); + + switch (cin) { + case GRID_MIDI_CIN_SYSEX_START: + return 3; + case GRID_MIDI_CIN_SYSEX_END_1BYTE: + return 1; + case GRID_MIDI_CIN_SYSEX_END_2BYTE: + return 2; + case GRID_MIDI_CIN_SYSEX_END_3BYTE: + return 3; + } + + return 0; +} + +static void grid_usb_midi_rx_queue_voice(struct grid_usb_midi_model* usb_midi, uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + + if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIVOICE) & GRID_RX_MODE_FORWARD_FROM_USB)) { + return; + } + + struct grid_midi_event_desc event = {byte0, byte1, byte2, byte3}; + assert(grid_swsr_writable(&usb_midi->voice_rx, sizeof(struct grid_midi_event_desc))); + grid_swsr_write(&usb_midi->voice_rx, &event, sizeof(struct grid_midi_event_desc)); +} + +static void grid_usb_midi_rx_queue_sysex(struct grid_usb_midi_model* usb_midi, uint8_t sysex_length, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + + if (!(grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDISYSEX) & GRID_RX_MODE_FORWARD_FROM_USB)) { + return; + } + + assert(grid_swsr_writable(&usb_midi->sysex_rx, sysex_length)); + uint8_t bytes[3] = {byte1, byte2, byte3}; + grid_swsr_write(&usb_midi->sysex_rx, bytes, sysex_length); +} + +void grid_usb_midi_rx_queue(struct grid_usb_midi_model* usb_midi, uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { + + uint8_t cin = byte0 & 0x0F; + + if (byte1 >= GRID_MIDI_RTM_TIMING_CLOCK) { + grid_usb_midi_rx_queue_rtm(usb_midi, byte1); + return; + } + + int sysex_length = grid_midi_rx_process_sysex(usb_midi, cin, byte1, byte2, byte3); + if (sysex_length) { + grid_usb_midi_rx_queue_sysex(usb_midi, sysex_length, byte1, byte2, byte3); + return; + } + + grid_usb_midi_rx_queue_voice(usb_midi, byte0, byte1, byte2, byte3); +} + +void grid_usb_midi_rx_voice_process(struct grid_usb_midi_model* usb_midi) { + + if (!grid_swsr_readable(&usb_midi->voice_rx, sizeof(struct grid_midi_event_desc))) { + return; + } + + struct grid_msg msg = {0}; + uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; + grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); + + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); + + for (uint8_t i = 0; i < GRID_MIDI_VOICE_BATCH_MAX; ++i) { + + if (!grid_swsr_readable(&usb_midi->voice_rx, sizeof(struct grid_midi_event_desc))) { + break; + } + + struct grid_midi_event_desc event; + grid_swsr_read(&usb_midi->voice_rx, &event, sizeof(struct grid_midi_event_desc)); + + grid_msg_add_frame(&msg, GRID_CLASS_MIDI_frame); + grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); + + grid_msg_set_parameter(&msg, CLASS_MIDI_CHANNEL, event.byte1 & 0x0f); + grid_msg_set_parameter(&msg, CLASS_MIDI_COMMAND, event.byte1 & 0xf0); + grid_msg_set_parameter(&msg, CLASS_MIDI_PARAM1, event.byte2); + grid_msg_set_parameter(&msg, CLASS_MIDI_PARAM2, event.byte3); + } + + if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { + uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIVOICE); + if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { + grid_transport_send_msg_to_all(&grid_transport_state, &msg); + } else { + grid_transport_send_msg_to_ui(&grid_transport_state, &msg); + } + } +} + +bool grid_usb_midi_rx_writable(struct grid_usb_midi_model* usb_midi) { + return grid_swsr_writable(&usb_midi->voice_rx, sizeof(struct grid_midi_event_desc)) && grid_swsr_writable(&usb_midi->sysex_rx, 3) && grid_swsr_writable(&usb_midi->rtm_rx, 1); +} + +void grid_usb_midi_rx_rtm_process(struct grid_usb_midi_model* usb_midi) { + + if (!grid_swsr_readable(&usb_midi->rtm_rx, 1)) { + return; + } + + struct grid_msg msg = {0}; + uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; + grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); + + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); + + for (uint8_t i = 0; i < GRID_MIDI_RTM_BATCH_MAX; ++i) { + + if (!grid_swsr_readable(&usb_midi->rtm_rx, 1)) { + break; + } + + uint8_t rtm_byte; + grid_swsr_read(&usb_midi->rtm_rx, &rtm_byte, 1); + + grid_msg_add_frame(&msg, GRID_CLASS_MIDIRTM_frame); + grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); + grid_msg_set_parameter(&msg, CLASS_MIDIRTM_BYTE, rtm_byte); + } + + if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { + uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDIRTM); + if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { + grid_transport_send_msg_to_all(&grid_transport_state, &msg); + } else { + grid_transport_send_msg_to_ui(&grid_transport_state, &msg); + } + } +} + +static void grid_midi_sysex_process_complete(struct grid_usb_midi_model* usb_midi) { + + uint8_t* sysex_data = usb_midi->sysex_assembly_buffer; + uint16_t length = usb_midi->sysex_assembly_index; + + if (length < 2 || sysex_data[0] != GRID_MIDI_SYSEX_START || sysex_data[length - 1] != GRID_MIDI_SYSEX_END) { + return; + } + + struct grid_msg msg = {0}; + uint8_t xy = GRID_PARAMETER_GLOBAL_POSITION; + grid_msg_init_brc(&grid_msg_state, &msg, xy, xy); + + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SX, xy); + grid_msg_set_parameter_raw((uint8_t*)msg.data, BRC_SY, xy); + + grid_msg_add_frame(&msg, GRID_CLASS_MIDISYSEX_frame_start); + grid_msg_set_parameter(&msg, INSTR, GRID_INSTR_REPORT_code); + + grid_msg_set_parameter(&msg, CLASS_MIDISYSEX_LENGTH, length); + + if (grid_msg_add_hex_bytes(&msg, sysex_data, length) < 0) { + return; + } + + grid_msg_add_frame(&msg, GRID_CLASS_MIDISYSEX_frame_end); + + if (grid_msg_close_brc(&grid_msg_state, &msg) >= 0) { + uint8_t mode = grid_sys_get_rx_mode(&grid_sys_state, GRID_RX_TYPE_MIDISYSEX); + if (mode & GRID_RX_MODE_FORWARD_FROM_USB) { + grid_transport_send_msg_to_all(&grid_transport_state, &msg); + } else { + grid_transport_send_msg_to_ui(&grid_transport_state, &msg); + } + } +} + +void grid_usb_midi_rx_sysex_process(struct grid_usb_midi_model* usb_midi) { + + uint8_t byte = 0; + while (byte != GRID_MIDI_SYSEX_END) { + + if (!grid_swsr_readable(&usb_midi->sysex_rx, 1)) { + return; + } + + grid_swsr_read(&usb_midi->sysex_rx, &byte, 1); + + if (usb_midi->sysex_assembly_index >= GRID_MIDI_SYSEX_BUFFER_SIZE) { + usb_midi->sysex_assembly_index = 0; + } + + assert(usb_midi->sysex_assembly_index < GRID_MIDI_SYSEX_BUFFER_SIZE); + usb_midi->sysex_assembly_buffer[usb_midi->sysex_assembly_index++] = byte; + } + + assert(byte == GRID_MIDI_SYSEX_END); + grid_midi_sysex_process_complete(usb_midi); + usb_midi->sysex_assembly_index = 0; +} + +#if CFG_TUD_MIDI + +void tud_midi_rx_cb(uint8_t itf) { + (void)itf; + + uint8_t packet[4]; + + while (grid_usb_midi_rx_writable(&grid_usb_midi_state) && tud_midi_packet_read(packet)) { + grid_usb_midi_rx_queue(&grid_usb_midi_state, packet[0], packet[1], packet[2], packet[3]); + } +} + +void grid_usb_midi_rx_poll(struct grid_usb_midi_model* usb_midi) { + tud_midi_rx_cb(0); + (void)usb_midi; +} + +#else // !CFG_TUD_MIDI + +void grid_usb_midi_rx_poll(struct grid_usb_midi_model* usb_midi) { (void)usb_midi; } + +#endif // CFG_TUD_MIDI diff --git a/common/src/c/grid_usb_midi.h b/common/src/c/grid_usb_midi.h new file mode 100644 index 00000000..1ff8527b --- /dev/null +++ b/common/src/c/grid_usb_midi.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include + +#include "grid_swsr.h" + +// USB MIDI Code Index Number (CIN) values +enum grid_midi_cin_type { + GRID_MIDI_CIN_MISC = 0x00, + GRID_MIDI_CIN_CABLE_EVENT = 0x01, + GRID_MIDI_CIN_SYSCOM_2BYTE = 0x02, + GRID_MIDI_CIN_SYSCOM_3BYTE = 0x03, + GRID_MIDI_CIN_SYSEX_START = 0x04, + GRID_MIDI_CIN_SYSEX_END_1BYTE = 0x05, + GRID_MIDI_CIN_SYSEX_END_2BYTE = 0x06, + GRID_MIDI_CIN_SYSEX_END_3BYTE = 0x07, + GRID_MIDI_CIN_NOTE_OFF = 0x08, + GRID_MIDI_CIN_NOTE_ON = 0x09, + GRID_MIDI_CIN_POLY_KEYPRESS = 0x0A, + GRID_MIDI_CIN_CONTROL_CHANGE = 0x0B, + GRID_MIDI_CIN_PROGRAM_CHANGE = 0x0C, + GRID_MIDI_CIN_CHANNEL_PRESSURE = 0x0D, + GRID_MIDI_CIN_PITCHBEND = 0x0E, + GRID_MIDI_CIN_SINGLE_BYTE = 0x0F +}; + +enum grid_midi_system_type { GRID_MIDI_SYSEX_START = 0xF0, GRID_MIDI_SYSEX_END = 0xF7 }; + +enum grid_midi_rtm_type { + GRID_MIDI_RTM_TIMING_CLOCK = 0xF8, + GRID_MIDI_RTM_UNDEFINED_F9 = 0xF9, + GRID_MIDI_RTM_START = 0xFA, + GRID_MIDI_RTM_CONTINUE = 0xFB, + GRID_MIDI_RTM_STOP = 0xFC, + GRID_MIDI_RTM_UNDEFINED_FD = 0xFD, + GRID_MIDI_RTM_ACTIVE_SENSING = 0xFE, + GRID_MIDI_RTM_SYSTEM_RESET = 0xFF +}; + +struct grid_midi_event_desc { + uint8_t byte0; + uint8_t byte1; + uint8_t byte2; + uint8_t byte3; +}; + +#define GRID_MIDI_TX_BUFFER_SIZE 512 +#define GRID_MIDI_VOICE_RX_BUFFER_SIZE 512 +#define GRID_MIDI_SYSEX_BUFFER_SIZE 256 +#define GRID_MIDI_RTM_BUFFER_SIZE 32 + +#define GRID_MIDI_VOICE_BATCH_MAX 8 +#define GRID_MIDI_RTM_BATCH_MAX 16 + +struct grid_usb_midi_model { + struct grid_swsr_t tx; + struct grid_swsr_t voice_rx; + struct grid_swsr_t sysex_rx; + struct grid_swsr_t rtm_rx; + uint32_t tx_dropped; + uint8_t sysex_assembly_buffer[GRID_MIDI_SYSEX_BUFFER_SIZE]; + uint16_t sysex_assembly_index; + bool sysex_in_progress; +}; + +extern struct grid_usb_midi_model grid_usb_midi_state; + +void grid_usb_midi_init(struct grid_usb_midi_model* usb_midi, uint16_t tx_buffer_size, uint16_t rx_buffer_size, uint16_t sysex_buffer_size, uint16_t rtm_buffer_size); + +uint8_t grid_usb_midi_tx_push(struct grid_usb_midi_model* usb_midi, struct grid_midi_event_desc midi_event); +void grid_usb_midi_tx_flush(struct grid_usb_midi_model* usb_midi); +bool grid_usb_midi_tx_available(struct grid_usb_midi_model* usb_midi); + +void grid_usb_midi_rx_queue(struct grid_usb_midi_model* usb_midi, uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); +void grid_usb_midi_rx_voice_process(struct grid_usb_midi_model* usb_midi); + +void grid_usb_midi_rx_rtm_process(struct grid_usb_midi_model* usb_midi); +void grid_usb_midi_rx_sysex_process(struct grid_usb_midi_model* usb_midi); + +void grid_usb_midi_rx_poll(struct grid_usb_midi_model* usb_midi); diff --git a/d51n20a/atmel_start.c b/d51n20a/atmel_start.c index 98c7bff1..a58782e3 100644 --- a/d51n20a/atmel_start.c +++ b/d51n20a/atmel_start.c @@ -5,6 +5,5 @@ **/ void atmel_start_init(void) { system_init(); - usb_init(); stdio_redirect_init(); } diff --git a/d51n20a/atmel_start.h b/d51n20a/atmel_start.h index ca16fd00..7761baca 100644 --- a/d51n20a/atmel_start.h +++ b/d51n20a/atmel_start.h @@ -8,7 +8,6 @@ extern "C" { #include "driver_init.h" #include "rtos_start.h" #include "stdio_start.h" -#include "usb_start.h" /** * Initializes MCU, drivers and middleware in the project diff --git a/d51n20a/gcc/Makefile b/d51n20a/gcc/Makefile index c4ba42dd..2bc192ac 100644 --- a/d51n20a/gcc/Makefile +++ b/d51n20a/gcc/Makefile @@ -14,11 +14,15 @@ BUILD_DIRS = \ \ $(BUILD_DIR)/grid/d51 \ $(BUILD_DIR)/grid/vmp \ - $(BUILD_DIR)/grid/usb/class/midi \ - $(BUILD_DIR)/grid/usb/class/midi/device \ + \ + $(BUILD_DIR)/common/dep/tinyusb/src/common \ + $(BUILD_DIR)/common/dep/tinyusb/src/device \ + $(BUILD_DIR)/common/dep/tinyusb/src/class/cdc \ + $(BUILD_DIR)/common/dep/tinyusb/src/class/hid \ + $(BUILD_DIR)/common/dep/tinyusb/src/class/midi \ + $(BUILD_DIR)/common/dep/tinyusb/src/portable/microchip/samd \ \ $(BUILD_DIR)/asf/hpl/adc \ - $(BUILD_DIR)/asf/usb/class/cdc/device \ $(BUILD_DIR)/asf/hpl/ramecc \ $(BUILD_DIR)/asf/samd51a/gcc/gcc \ $(BUILD_DIR)/asf/hpl/evsys \ @@ -31,7 +35,6 @@ BUILD_DIRS = \ $(BUILD_DIR)/asf/stdio_redirect \ $(BUILD_DIR)/asf/hpl/tc \ $(BUILD_DIR)/asf/hpl/osc32kctrl \ - $(BUILD_DIR)/asf/usb \ $(BUILD_DIR)/asf/hpl/dmac \ $(BUILD_DIR)/asf/hal/src \ $(BUILD_DIR)/asf/stdio_redirect/gcc \ @@ -40,7 +43,6 @@ BUILD_DIRS = \ $(BUILD_DIR)/asf/hpl/wdt \ $(BUILD_DIR)/asf/hpl/rtc \ $(BUILD_DIR)/asf/hpl/trng \ - $(BUILD_DIR)/asf/usb/class/hid/device \ $(BUILD_DIR)/asf/hpl/usb \ $(BUILD_DIR)/asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/portable/GCC/ARM_CM4F \ $(BUILD_DIR)/asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/portable/MemMang \ @@ -48,9 +50,7 @@ BUILD_DIRS = \ $(BUILD_DIR)/asf/hpl/eic \ $(BUILD_DIR)/asf/hpl/cmcc \ $(BUILD_DIR)/asf/hpl/gclk \ - $(BUILD_DIR)/asf/usb/device \ $(BUILD_DIR)/asf/hpl/pm \ - $(BUILD_DIR)/asf/usb/class/msc/device \ $(BUILD_DIR)/asf/hpl/pac \ $(BUILD_DIR)/asf/hpl/sercom \ $(BUILD_DIR)/asf/hpl/core \ @@ -90,6 +90,9 @@ SRCS = \ common/src/c/grid_ui_potmeter.c \ common/src/c/grid_ui_system.c \ common/src/c/grid_usb.c \ + common/src/c/grid_usb_acm.c \ + common/src/c/grid_usb_midi.c \ + common/src/c/grid_usb_hid.c \ common/src/c/grid_utask.c \ common/dep/lua-5.5.0/src/dirent.c \ common/dep/lua-5.5.0/src/lapi.c \ @@ -146,8 +149,15 @@ SRCS = \ grid/grid_d51_module_po16.c \ grid/grid_d51_module_ef44.c \ grid/vmp/vmp_def.c \ - grid/usb/class/midi/usb_protocol_midi.c \ - grid/usb/class/midi/device/audiodf_midi.c \ + \ + common/dep/tinyusb/src/tusb.c \ + common/dep/tinyusb/src/common/tusb_fifo.c \ + common/dep/tinyusb/src/device/usbd.c \ + common/dep/tinyusb/src/device/usbd_control.c \ + common/dep/tinyusb/src/class/cdc/cdc_device.c \ + common/dep/tinyusb/src/class/midi/midi_device.c \ + common/dep/tinyusb/src/class/hid/hid_device.c \ + common/dep/tinyusb/src/portable/microchip/samd/dcd_samd.c \ \ asf/hal/src/hal_io.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/list.c \ @@ -158,25 +168,20 @@ SRCS = \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/portable/MemMang/heap_4.c \ asf/hpl/wdt/hpl_wdt.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/croutine.c \ - asf/usb/usb_protocol.c \ asf/stdio_redirect/stdio_io.c \ asf/hal/src/hal_spi_m_dma.c \ asf/stdio_redirect/gcc/write.c \ asf/samd51a/gcc/system_samd51.c \ - asf/usb/class/hid/device/hiddf_generic.c \ asf/hal/src/hal_init.c \ asf/hpl/evsys/hpl_evsys.c \ asf/hpl/core/hpl_core_m4.c \ asf/hal/src/hal_cache.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/stream_buffer.c \ - asf/usb/class/cdc/device/cdcdf_acm.c \ asf/hal/utils/src/utils_syscalls.c \ asf/hpl/qspi/hpl_qspi.c \ asf/hpl/nvmctrl/hpl_nvmctrl.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/queue.c \ - asf/usb_start.c \ asf/hal/src/hal_timer.c \ - asf/hpl/usb/hpl_usb.c \ asf/stdio_redirect/gcc/read.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/Source/timers.c \ asf/hal/src/hal_delay.c \ @@ -184,14 +189,12 @@ SRCS = \ asf/hpl/core/hpl_init.c \ asf/hpl/ramecc/hpl_ramecc.c \ asf/hal/src/hal_wdt.c \ - asf/usb/class/hid/device/hiddf_mouse.c \ asf/hal/utils/src/utils_assert.c \ asf/hpl/dmac/hpl_dmac.c \ asf/hal/src/hal_adc_async.c \ asf/hpl/oscctrl/hpl_oscctrl.c \ asf/hal/src/hal_rand_sync.c \ asf/hpl/trng/hpl_trng.c \ - asf/usb/class/hid/device/hiddf_keyboard.c \ asf/hal/src/hal_usart_sync.c \ asf/hpl/mclk/hpl_mclk.c \ asf/hpl/gclk/hpl_gclk.c \ @@ -200,7 +203,6 @@ SRCS = \ asf/hal/src/hal_spi_m_async.c \ asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/rtos_port.c \ asf/hal/src/hal_crc_sync.c \ - asf/hal/src/hal_usb_device.c \ asf/rtos_start.c \ asf/hal/utils/src/utils_list.c \ asf/hpl/osc32kctrl/hpl_osc32kctrl.c \ @@ -208,7 +210,6 @@ SRCS = \ asf/examples/driver_examples.c \ asf/driver_init.c \ asf/hal/src/hal_usart_async.c \ - asf/usb/class/msc/device/mscdf.c \ asf/hpl/sercom/hpl_sercom.c \ asf/hal/utils/src/utils_ringbuffer.c \ asf/hal/src/hal_atomic.c \ @@ -224,7 +225,6 @@ SRCS = \ asf/hpl/adc/hpl_adc.c \ asf/samd51a/gcc/gcc/startup_samd51.c \ asf/atmel_start.c \ - asf/usb/device/usbdc.c \ asf/hpl/tc/hpl_tc.c \ asf/hpl/cmcc/hpl_cmcc.c \ asf/hpl/systick/hpl_systick.c \ @@ -243,8 +243,8 @@ INCLUDES = \ -I"grid" \ -I"grid/d51" \ -I"grid/vmp" \ - -I"grid/usb/class/midi" \ - -I"grid/usb/class/midi/device" \ + \ + -I"common/dep/tinyusb/src" \ \ -I"asf/config" \ -I"asf/examples" \ @@ -284,19 +284,6 @@ INCLUDES = \ -I"asf/thirdparty/RTOS/freertos/FreeRTOSV10.0.0/module_config" \ -I"asf/" \ -I"asf/config" \ - -I"asf/usb" \ - -I"asf/usb/class/cdc" \ - -I"asf/usb/class/cdc/device" \ - -I"asf/usb/class/composite/device" \ - -I"asf/usb/class/hid" \ - -I"asf/usb/class/hid/device" \ - -I"asf/usb/class/hub" \ - -I"asf/usb/class/msc" \ - -I"asf/usb/class/msc/device" \ - -I"asf/usb/class/vendor" \ - -I"asf/usb/device" \ - -I"asf/" \ - -I"asf/config" \ -I"asf/stdio_redirect" \ -I"asf/" \ -I"asf/CMSIS/Core/Include" \ diff --git a/d51n20a/grid/d51/grid_d51_usb.c b/d51n20a/grid/d51/grid_d51_usb.c index 15b07475..f31e38f9 100644 --- a/d51n20a/grid/d51/grid_d51_usb.c +++ b/d51n20a/grid/d51/grid_d51_usb.c @@ -1,209 +1,94 @@ -/* - * grid_d51_usb.c - * - * Created: 6/3/2020 5:02:14 PM - * Author: WPC-User - */ +#include -#include "grid_d51_usb.h" - -#include -#include - -volatile uint8_t grid_usb_serial_rx_buffer[CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_MAXPKSZ]; - -volatile uint8_t grid_usb_serial_rx_flag; -volatile uint16_t grid_usb_serial_rx_size; - -static volatile struct grid_port* host_port = NULL; - -struct grid_swsr_t usb_rx; - -static bool grid_usb_serial_bulkout_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count) { - - size_t rx_size = count; - uint8_t* buf = grid_usb_serial_rx_buffer; - - struct grid_swsr_t* rx = &usb_rx; - - if (grid_swsr_writable(rx, rx_size)) { - grid_swsr_write(rx, buf, rx_size); - } else { - grid_swsr_read(rx, NULL, grid_swsr_size(rx)); - } - - struct grid_msg msg; - - if (!grid_msg_from_swsr(&msg, rx)) { - goto bulkout_cb_end; - } - - if (grid_frame_verify((uint8_t*)msg.data, msg.length)) { - goto bulkout_cb_end; - } - - grid_transport_recv_usb(&grid_transport_state, (uint8_t*)msg.data, msg.length); - -bulkout_cb_end: - - cdcdf_acm_read((uint8_t*)grid_usb_serial_rx_buffer, sizeof(grid_usb_serial_rx_buffer)); +#include "tusb.h" - return false; -} -static bool grid_usb_serial_bulkin_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count) { - - // grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_PURPLE, 64); - - return false; /* No error. */ -} -static uint8_t usb_tx_ready = 0; - -static bool grid_usb_serial_statechange_cb(usb_cdc_control_signal_t state) { - - // grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_PURPLE, 255); - - // printf("\r\n### USB SERIAL STATE CHANGE %d ###\r\n", - // sizeof(grid_usb_serial_rx_buffer)); - - if (state.rs232.DTR || 1) { - /* After connection the R/W callbacks can be registered */ - cdcdf_acm_register_callback(CDCDF_ACM_CB_READ, (FUNC_PTR)grid_usb_serial_bulkout_cb); - cdcdf_acm_register_callback(CDCDF_ACM_CB_WRITE, (FUNC_PTR)grid_usb_serial_bulkin_cb); - /* Start Rx */ - cdcdf_acm_read((uint8_t*)grid_usb_serial_rx_buffer, sizeof(grid_usb_serial_rx_buffer)); - - usb_tx_ready = 1; - } +#include "grid_d51_usb.h" - return false; /* No error. */ +#include "grid_usb.h" + +static const tusb_desc_device_t s_device_desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x03eb, + .idProduct = 0xecad, + .bcdDevice = 0x0100, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +enum { ITF_NUM_CDC_NOTIFY = 0, ITF_NUM_CDC_DATA, ITF_NUM_MIDI, ITF_NUM_MIDI_STREAMING, ITF_NUM_HID, ITF_COUNT }; + +enum { + EP_EMPTY = 0, + EPNUM_CDC_DATA, + EPNUM_CDC_NOTIFY, + EPNUM_MIDI, + EPNUM_HID, +}; + +#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MIDI_DESC_LEN + TUD_HID_DESC_LEN) + +static const uint8_t s_cfg_desc[] = { + TUD_CONFIG_DESCRIPTOR(1, ITF_COUNT, 0, TUSB_DESC_TOTAL_LEN, 0, 250), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_NOTIFY, 5, (0x80 | EPNUM_CDC_NOTIFY), 8, EPNUM_CDC_DATA, (0x80 | EPNUM_CDC_DATA), 64), + TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 4, EPNUM_MIDI, (0x80 | EPNUM_MIDI), 64), + TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, GRID_HID_REPORT_DESC_SIZE, (0x80 | EPNUM_HID), 16, 10), +}; + +static const uint16_t s_lang_id[] = {0x0409}; + +static const void* s_str_desc[] = { + s_lang_id, "Intech Studio", "Grid", NULL, "Intech Studio: MS", "Intech Studio: CDC", +}; + +#define STR_DESC_COUNT ((uint8_t)(sizeof(s_str_desc) / sizeof(s_str_desc[0]))) +#define MAX_STR_LEN 32 + +uint8_t const* tud_descriptor_device_cb(void) { return (uint8_t const*)&s_device_desc; } + +uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { + (void)index; + return s_cfg_desc; } -int32_t grid_platform_usb_serial_ready() { return usb_tx_ready; } - -int32_t grid_platform_usb_serial_write(char* buffer, uint32_t length) { return cdcdf_acm_write((uint8_t*)buffer, length); } - -enum { MIDI_RX_BUFFER_SIZE = 64 }; - -static uint8_t midi_rx_buffer[MIDI_RX_BUFFER_SIZE] = {0}; - -struct grid_swsr_t midi_rx; - -bool grid_d51_midi_bulkout_poll() { - - while (grid_swsr_readable(&midi_rx, 4) && grid_midi_rx_writable()) { - - uint8_t event[4]; - grid_swsr_read(&midi_rx, event, 4); - - // Pass raw USB MIDI packet bytes to state machine - grid_midi_rx_push(event[0], event[1], event[2], event[3]); - - if (!grid_swsr_readable(&midi_rx, 4)) { +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; + static uint16_t desc_str[MAX_STR_LEN]; - assert(!grid_swsr_readable(&midi_rx, 1)); + uint8_t chr_count; - audiodf_midi_read(midi_rx_buffer, MIDI_RX_BUFFER_SIZE); + if (index == 0) { + memcpy(&desc_str[1], s_str_desc[0], 2); + chr_count = 1; + } else if (index < STR_DESC_COUNT && s_str_desc[index] != NULL) { + const char* str = (const char*)s_str_desc[index]; + chr_count = (uint8_t)strnlen(str, MAX_STR_LEN - 1); + for (uint8_t i = 0; i < chr_count; i++) { + desc_str[1 + i] = (uint16_t)str[i]; } + } else { + return NULL; } -} - -static bool grid_usb_midi_bulkout_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count) { - - uint32_t bytes = count; - - if (bytes > MIDI_RX_BUFFER_SIZE) { - bytes = MIDI_RX_BUFFER_SIZE; - } - - bytes /= 4; - bytes *= 4; - - assert(grid_swsr_writable(&midi_rx, MIDI_RX_BUFFER_SIZE)); - - grid_swsr_write(&midi_rx, midi_rx_buffer, bytes); - - grid_d51_midi_bulkout_poll(); - return false; + desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2u * chr_count + 2u)); + return desc_str; } -static bool grid_usb_midi_bulkin_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count) { +void USB_0_Handler(void) { dcd_int_handler(0); } +void USB_1_Handler(void) { dcd_int_handler(0); } +void USB_2_Handler(void) { dcd_int_handler(0); } +void USB_3_Handler(void) { dcd_int_handler(0); } - // printf("MIDI IN CB\n"); - // grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_PURPLE, 255); - return false; -} - -static bool grid_usb_midi_installed_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count) { - - printf("MIDI INSTALLED CB\n"); - audiodf_midi_read(midi_rx_buffer, MIDI_RX_BUFFER_SIZE); - return false; -} +void usb_d_init(void) {} void grid_d51_usb_init(void) { - - // Allocate USB RX buffer - int capacity = GRID_PARAMETER_SPI_TRANSACTION_length * 2; - assert(grid_swsr_malloc(&usb_rx, capacity) == 0); - - // Allocate MIDI RX fifo - assert(grid_swsr_malloc(&midi_rx, MIDI_RX_BUFFER_SIZE) == 0); - - audiodf_midi_init(); - composite_device_start(); - - // host_port = grid_transport_get_port_first_of_type(&grid_transport_state, GRID_PORT_TYPE_USB); - - // audiodf_midi_register_callback(AUDIODF_MIDI_CB_READ, - // (FUNC_PTR)midi_in_handler); - // audiodf_midi_register_callback(AUDIODF_MIDI_CB_WRITE, - // (FUNC_PTR)midi_out_handler); - - grid_usb_serial_rx_size = 0; - grid_usb_serial_rx_flag = 0; - - // this does not directly register the statechange callback to an endpoint, - // just to the internal driver - cdcdf_acm_register_callback(CDCDF_ACM_CB_STATE_C, (FUNC_PTR)grid_usb_serial_statechange_cb); - - audiodf_midi_register_callback(AUDIODF_MIDI_CB_READ, (FUNC_PTR)grid_usb_midi_bulkin_cb); - audiodf_midi_register_callback(AUDIODF_MIDI_CB_WRITE, (FUNC_PTR)grid_usb_midi_bulkout_cb); - - audiodf_midi_register_callback(AUDIODF_MIDI_CB_INSTALLED, (FUNC_PTR)grid_usb_midi_installed_cb); - - grid_usb_midi_buffer_init(); - - grid_usb_keyboard_model_init(&grid_usb_keyboard_state, 100); -} - -int32_t grid_platform_usb_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { return audiodf_midi_write(byte0, byte1, byte2, byte3); } - -int32_t grid_platform_usb_midi_write_status(void) { return audiodf_midi_write_status(); } - -int32_t grid_platform_usb_mouse_button_change(uint8_t b_state, uint8_t type) { return hiddf_mouse_button_change(b_state, type); } - -int32_t grid_platform_usb_mouse_move(int8_t position, uint8_t axis) { return hiddf_mouse_move(position, axis); } - -int32_t grid_platform_usb_gamepad_axis_move(uint8_t axis, int32_t value) { - grid_port_debug_printf("Gamepad Not Supported"); - return -1; // Not supported -} - -int32_t grid_platform_usb_gamepad_button_change(uint8_t button, uint8_t value) { - grid_port_debug_printf("Gamepad Not Supported"); - return -1; // Not supported -} - -int32_t grid_platform_usb_keyboard_keys_state_change(struct grid_usb_keyboard_event_desc* active_key_list, uint8_t keys_count) { - - struct grid_usb_hid_kb_desc hid_key_array[GRID_KEYBOARD_KEY_maxcount]; - for (uint8_t i = 0; i < GRID_KEYBOARD_KEY_maxcount; i++) { - - hid_key_array[i].b_modifier = active_key_list[i].ismodifier; - hid_key_array[i].key_id = active_key_list[i].keycode; - hid_key_array[i].state = active_key_list[i].ispressed; - } - - return hiddf_keyboard_keys_state_change((struct hiddf_kb_key_descriptors*)hid_key_array, keys_count); + grid_usb_infrastructure_init(); + tusb_init(); } diff --git a/d51n20a/grid/d51/grid_d51_usb.h b/d51n20a/grid/d51/grid_d51_usb.h index 6faf29d0..8ec7781f 100644 --- a/d51n20a/grid/d51/grid_d51_usb.h +++ b/d51n20a/grid/d51/grid_d51_usb.h @@ -1,58 +1,7 @@ -/* - * grid_d51_usb.h - * - * Created: 6/3/2020 5:02:04 PM - * Author: WPC-User - */ +#pragma once -#ifndef GRID_D51_USB_H_ -#define GRID_D51_USB_H_ - -#include "../usb/class/cdc/device/cdcdf_acm.h" -#include "../usb/class/hid/device/hiddf_keyboard.h" -#include "../usb/class/hid/device/hiddf_mouse.h" -#include "../usb/class/midi/device/audiodf_midi.h" -#include "grid_led.h" - -#include "config/usbd_config.h" - -#include "../../usb_start.h" -#include "grid_port.h" -#include "grid_usb.h" - -extern void grid_platform_sync1_pulse_send(); - -extern volatile uint8_t grid_usb_serial_rx_buffer[CONF_USB_COMPOSITE_CDC_ACM_DATA_BULKIN_MAXPKSZ]; - -extern volatile uint8_t grid_usb_serial_rx_flag; -extern volatile uint16_t grid_usb_serial_rx_size; - -static uint8_t* cdcdf_demo_buf; - -// SERIAL CALLBACK HANDLERS -static bool grid_usb_serial_bulkout_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count); -static bool grid_usb_serial_bulkin_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count); -static bool grid_usb_serial_statechange_cb(usb_cdc_control_signal_t state); - -int32_t grid_platform_usb_serial_write(char* buffer, uint32_t length); - -bool grid_d51_midi_bulkout_poll(); - -// MIDI CALLBACK HANDLERS -static bool grid_usb_midi_bulkout_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count); -static bool grid_usb_midi_bulkin_cb(const uint8_t ep, const enum usb_xfer_code rc, const uint32_t count); +#include "grid_usb_acm.h" +#include "grid_usb_hid.h" +#include "grid_usb_midi.h" void grid_d51_usb_init(void); - -int32_t grid_platform_usb_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); -int32_t grid_platform_usb_midi_write_status(void); - -int32_t grid_platform_usb_mouse_button_change(uint8_t b_state, uint8_t type); -int32_t grid_platform_usb_mouse_move(int8_t position, uint8_t axis); - -int32_t grid_platform_usb_gamepad_axis_move(uint8_t axis, int32_t value); -int32_t grid_platform_usb_gamepad_button_change(uint8_t button, uint8_t value); - -int32_t grid_platform_usb_keyboard_keys_state_change(struct grid_usb_keyboard_event_desc* active_key_list, uint8_t keys_count); - -#endif /* GRID_D51_USB_H_ */ diff --git a/d51n20a/grid/d51/tusb_config.h b/d51n20a/grid/d51/tusb_config.h new file mode 100644 index 00000000..fd1d4d1a --- /dev/null +++ b/d51n20a/grid/d51/tusb_config.h @@ -0,0 +1,72 @@ +/* + * TinyUSB configuration for Grid firmware (SAMD51 / D51). + * + * OPT_OS_NONE: bare-metal — tud_task() is called from the main super-loop. + * CFG_TUSB_MCU is defined here; the Makefile does not inject it. + */ +#pragma once + +// ---- MCU ---- +#define CFG_TUSB_MCU OPT_MCU_SAMD51 + +// ---- OS abstraction ---- +#define CFG_TUSB_OS OPT_OS_NONE + +// ---- Debug (0 = silent) ---- +#define CFG_TUSB_DEBUG 0 + +// ---- RHPort 0: full-speed device (required for no-arg tusb_init()) ---- +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) + +// ---- Device stack ---- +#define CFG_TUD_ENABLED 1 + +// ---- Endpoint 0 packet size ---- +#define CFG_TUD_ENDPOINT0_SIZE 64 + +// ---- Memory attributes (plain 4-byte-aligned SRAM) ---- +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4))) +#endif + +// ============================================================ +// Device class drivers +// ============================================================ + +// CDC (virtual serial) — 1 instance +#ifndef CFG_TUD_CDC +#define CFG_TUD_CDC 1 +#endif +#define CFG_TUD_CDC_RX_BUFSIZE 512 +#define CFG_TUD_CDC_TX_BUFSIZE 1024 +#define CFG_TUD_CDC_EP_BUFSIZE 512 + +// MIDI — 1 instance +#ifndef CFG_TUD_MIDI +#define CFG_TUD_MIDI 1 +#endif +#define CFG_TUD_MIDI_RX_BUFSIZE 64 +#define CFG_TUD_MIDI_TX_BUFSIZE 64 +#define CFG_TUD_MIDI_EP_BUFSIZE 64 +#define CFG_TUD_MIDI_EPSIZE CFG_TUD_MIDI_EP_BUFSIZE + +// HID (keyboard + mouse + gamepad) — 3 report IDs +#ifndef CFG_TUD_HID +#define CFG_TUD_HID 1 +#endif +#define CFG_TUD_HID_EP_BUFSIZE 64 + +// Disabled classes +#define CFG_TUD_MSC 0 +#define CFG_TUD_VENDOR 0 +#define CFG_TUD_ECM_RNDIS 0 +#define CFG_TUD_NCM 0 +#define CFG_TUD_AUDIO 0 +#define CFG_TUD_VIDEO 0 +#define CFG_TUD_DFU 0 +#define CFG_TUD_DFU_RUNTIME 0 +#define CFG_TUD_BTH 0 +#define CFG_TUD_USBTMC 0 diff --git a/d51n20a/grid/usb/class/midi/device/audiodf_midi.c b/d51n20a/grid/usb/class/midi/device/audiodf_midi.c deleted file mode 100644 index cf7398bf..00000000 --- a/d51n20a/grid/usb/class/midi/device/audiodf_midi.c +++ /dev/null @@ -1,325 +0,0 @@ -#include "audiodf_midi.h" -#include - -#define AUDIODF_MIDI_VERSION 0x00000001u - -/** USB Device Audio Midi Function Specific Data */ - -struct audiodf_midi_func_data { - /* AUDIO descriptor */ - uint8_t* audio_desc; - - uint8_t func_iface[2]; - uint8_t func_ep_in; - uint8_t func_ep_out; - uint8_t protocol; //???? - - uint8_t midi_report[4]; //???? - - uint8_t midi_report_inbound[4]; //???? - - bool enabled; -}; - -/* USB Device Audio Midi Function Instance */ -static struct usbdf_driver _audiodf_midi; - -/* USB Device Audio Midi Function Data Instance */ -static struct audiodf_midi_func_data _audiodf_midi_funcd; - -volatile uint8_t usb_debug2[10]; - -// Define the function pointer type -typedef bool (*midi_xfer_cb_t)(const uint8_t, const enum usb_xfer_code, const uint32_t); - -// Global function pointer -static midi_xfer_cb_t midi_in_cb = NULL; -static midi_xfer_cb_t midi_out_cb = NULL; -static midi_xfer_cb_t midi_installed_cb = NULL; - -/** - * \brief Enable Audio Midi Function - * \param[in] drv Pointer to USB device function driver - * \param[in] desc Pointer to USB interface descriptor - * \return Operation status. - */ -static int32_t audio_midi_enable(struct usbdf_driver* drv, struct usbd_descriptors* desc) { - - printf("MIDI ENABLE\n"); - - struct audiodf_midi_func_data* func_data = (struct audiodf_midi_func_data*)(drv->func_data); - - usb_iface_desc_t ifc_desc; - volatile usb_ep_desc_t ep_desc; - uint8_t *ifc, *ep; - uint8_t i; - - ifc = desc->sod; - -#define AUDIO_CLASS 0x01 // Audio Class -#define AUDIO_AC_SUBCLASS 0x01 // Audio Control Subclass -#define AUDIO_MS_SUBCLASS 0x03 // MidiStreaming Subclass - - for (i = 0; i < 2; i++) { - - if (NULL == ifc) { - return ERR_NOT_FOUND; - } - - ifc_desc.bInterfaceNumber = ifc[2]; - ifc_desc.bInterfaceClass = ifc[5]; - - if (AUDIO_AC_SUBCLASS == ifc_desc.bInterfaceClass || AUDIO_MS_SUBCLASS == ifc_desc.bInterfaceClass) { - if (func_data->func_iface[i] == ifc_desc.bInterfaceNumber) { // Initialized - return ERR_ALREADY_INITIALIZED; - } else if (func_data->func_iface[i] != 0xFF) { // Occupied - return ERR_NO_RESOURCE; - } else { - func_data->func_iface[i] = ifc_desc.bInterfaceNumber; - } - } else { // Not supported by this function driver - return ERR_NOT_FOUND; - } - - // #define USB_DT_AUDIO 0x24 - // Install AUDIO descriptor - //_audiodf_midi_funcd.audio_desc = usb_find_desc(usb_desc_next(desc->sod), desc->eod, USB_DT_AUDIO); - - // Install endpoints - if (i == 1) { // i==1 because only the second interface has endpoint descriptors - ep = usb_find_desc(ifc, desc->eod, USB_DT_ENDPOINT); - while (NULL != ep) { - ep_desc.bEndpointAddress = ep[2]; - ep_desc.bmAttributes = ep[3]; - ep_desc.wMaxPacketSize = usb_get_u16(ep + 4); - - usb_debug2[4] = ep_desc.wMaxPacketSize; - - usb_debug2[0] = i; - - if (usb_d_ep_init(ep_desc.bEndpointAddress, ep_desc.bmAttributes, ep_desc.wMaxPacketSize)) { - return ERR_NOT_INITIALIZED; - } - if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) { - func_data->func_ep_in = ep_desc.bEndpointAddress; - usb_d_ep_enable(func_data->func_ep_in); - } else { - func_data->func_ep_out = ep_desc.bEndpointAddress; - usb_d_ep_enable(func_data->func_ep_out); - } - desc->sod = ep; - ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod); - } - } - - ifc = usb_find_desc(usb_desc_next(desc->sod), desc->eod, USB_DT_INTERFACE); - } - - printf("MIDI TEST %d %d \r\n", _audiodf_midi_funcd.func_ep_in, _audiodf_midi_funcd.func_ep_out); - - usb_d_ep_register_callback(_audiodf_midi_funcd.func_ep_in, USB_D_EP_CB_XFER, (FUNC_PTR)midi_in_cb); - usb_d_ep_register_callback(_audiodf_midi_funcd.func_ep_out, USB_D_EP_CB_XFER, (FUNC_PTR)midi_out_cb); - - if (midi_installed_cb) { - midi_installed_cb(0, 0, 0); - } - - _audiodf_midi_funcd.enabled = true; - return ERR_NONE; -} - -/** - * \brief Disable Audio Midi Function - * \param[in] drv Pointer to USB device function driver - * \param[in] desc Pointer to USB device descriptor - * \return Operation status. - */ -static int32_t audio_midi_disable(struct usbdf_driver* drv, struct usbd_descriptors* desc) { - - struct audiodf_midi_func_data* func_data = (struct audiodf_midi_func_data*)(drv->func_data); - - usb_iface_desc_t ifc_desc; - - if (desc) { - ifc_desc.bInterfaceClass = desc->sod[5]; - // Check interface - if ((AUDIO_AC_SUBCLASS != ifc_desc.bInterfaceClass) && (AUDIO_MS_SUBCLASS != ifc_desc.bInterfaceClass)) { - return ERR_NOT_FOUND; - } - } - - if (func_data->func_iface[0] != 0xFF) { - func_data->func_iface[0] = 0xFF; - } - - if (func_data->func_iface[1] != 0xFF) { - func_data->func_iface[1] = 0xFF; - } - - if (func_data->func_ep_in != 0xFF) { - usb_d_ep_deinit(func_data->func_ep_in); - func_data->func_ep_in = 0xFF; - } - - if (func_data->func_ep_out != 0xFF) { - usb_d_ep_deinit(func_data->func_ep_out); - func_data->func_ep_out = 0xFF; - } - - _audiodf_midi_funcd.enabled = false; - return ERR_NONE; -} - -static int32_t audio_midi_ctrl(struct usbdf_driver* drv, enum usbdf_control ctrl, void* param) { - - switch (ctrl) { - case USBDF_ENABLE: - return audio_midi_enable(drv, (struct usbd_descriptors*)param); - - case USBDF_DISABLE: - return audio_midi_disable(drv, (struct usbd_descriptors*)param); - - case USBDF_GET_IFACE: - return ERR_UNSUPPORTED_OP; - - default: - return ERR_INVALID_ARG; - } -} - -static int32_t audio_midi_get_desc(uint8_t ep, struct usb_req* req) { - return usbdc_xfer(ep, _audiodf_midi_funcd.audio_desc, _audiodf_midi_funcd.audio_desc[0], false); - - // return ERR_INVALID_ARG; -} -/** - * \brief Process the Audio class request - * \param[in] ep Endpoint address. - * \param[in] req Pointer to the request. - * \return Operation status. - */ - -static int32_t audio_midi_req(uint8_t ep, struct usb_req* req, enum usb_ctrl_stage stage) { - - // return ERR_NOT_FOUND; - - if ((0x81 == req->bmRequestType) && (req->wIndex == _audiodf_midi_funcd.func_iface[0] || req->wIndex == _audiodf_midi_funcd.func_iface[1])) { - return audio_midi_get_desc(ep, req); // Never hit breakpoint here - - } else { - - if (0x01 != ((req->bmRequestType >> 5) & 0x03)) { // class request - return ERR_NOT_FOUND; // Never hit breakpoint here - } - if (req->wIndex == _audiodf_midi_funcd.func_iface[0] || req->wIndex == _audiodf_midi_funcd.func_iface[1]) { - - // Copied from Hid - // Never hit breakpoint here - switch (req->bRequest) { - case 0x03: /* Get Protocol */ - return usbdc_xfer(ep, &_audiodf_midi_funcd.protocol, 1, 0); - case 0x0B: /* Set Protocol */ - _audiodf_midi_funcd.protocol = req->wValue; - return usbdc_xfer(ep, NULL, 0, 0); - default: - return ERR_INVALID_ARG; - } - - } else { - return ERR_NOT_FOUND; - } - } - (void)stage; -} - -/** USB Device Audio Midi Handler Struct */ -static struct usbdc_handler audio_midi_req_h = {NULL, (FUNC_PTR)audio_midi_req}; - -/** - * \brief Initialize the USB Audio Midi Function Driver - */ -int32_t audiodf_midi_init(void) { - - if (usbdc_get_state() > USBD_S_POWER) { - return ERR_DENIED; - } - - _audiodf_midi.ctrl = audio_midi_ctrl; - _audiodf_midi.func_data = &_audiodf_midi_funcd; - - usbdc_register_function(&_audiodf_midi); - usbdc_register_handler(USBDC_HDL_REQ, &audio_midi_req_h); - return ERR_NONE; -} - -/** - * \brief Deinitialize the USB Audio Midi Function Driver - */ -int32_t audiodf_midi_deinit(void) { - if (usbdc_get_state() > USBD_S_POWER) { - return ERR_DENIED; - } - - _audiodf_midi.ctrl = NULL; - _audiodf_midi.func_data = NULL; - - usbdc_unregister_function(&_audiodf_midi); - usbdc_unregister_handler(USBDC_HDL_REQ, &audio_midi_req_h); - return ERR_NONE; -} - -/** - * \brief Check whether Audio Midi Function is enabled - */ -bool audiodf_midi_is_enabled(void) { return true; } - -int32_t audiodf_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - if (!audiodf_midi_is_enabled()) { - return ERR_DENIED; - } - - // if previous xfer is completed - - _audiodf_midi_funcd.midi_report[0] = byte0; - _audiodf_midi_funcd.midi_report[1] = byte1; - _audiodf_midi_funcd.midi_report[2] = byte2; - _audiodf_midi_funcd.midi_report[3] = byte3; - - return usbdc_xfer(_audiodf_midi_funcd.func_ep_in, _audiodf_midi_funcd.midi_report, 4, false); -} - -int32_t audiodf_midi_write_status() { - - struct usb_d_ep_status epstat; - return usb_d_ep_get_status(_audiodf_midi_funcd.func_ep_in, &epstat); -} - -int32_t audiodf_midi_read(uint8_t* buf, uint32_t size) { - if (!audiodf_midi_is_enabled()) { - return ERR_DENIED; - } - - return usbdc_xfer(_audiodf_midi_funcd.func_ep_out, buf, size, false); -} - -int32_t audiodf_midi_register_callback(enum audiodf_midi_cb_type cb_type, FUNC_PTR func) { - switch (cb_type) { - case AUDIODF_MIDI_CB_READ: - midi_in_cb = (midi_xfer_cb_t)func; - break; - case AUDIODF_MIDI_CB_WRITE: - midi_out_cb = (midi_xfer_cb_t)func; - break; - case AUDIODF_MIDI_CB_INSTALLED: - midi_installed_cb = (midi_xfer_cb_t)func; - break; - default: - return ERR_INVALID_ARG; - } - return ERR_NONE; -} - -/** - * \brief Return version - */ -uint32_t audiodf_midi_get_version(void) { return AUDIODF_MIDI_VERSION; } diff --git a/d51n20a/grid/usb/class/midi/device/audiodf_midi.h b/d51n20a/grid/usb/class/midi/device/audiodf_midi.h deleted file mode 100644 index 8a90fd91..00000000 --- a/d51n20a/grid/usb/class/midi/device/audiodf_midi.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef USBDF_AUDIO_MIDI_H_ -#define USBDF_AUDIO_MIDI_H_ - -#include "usbdc.h" - -/** - * \brief Initialize the USB Audio Midi Function Driver - * \return Operation status. - */ -int32_t audiodf_midi_init(void); - -/** - * \brief Deinitialize the USB Audio Midi Function Driver - * \return Operation status. - */ -int32_t audiodf_midi_deinit(void); - -/** - * \brief Check whether Audio Midi Function is enabled - * \return Operation status. - * \return true Audio Midi Function is enabled - * \return false Audio Midi Function is disabled - */ -bool audiodf_midi_is_enabled(void); - -/** AUDIO MIDI Class Callback Type */ -enum audiodf_midi_cb_type { AUDIODF_MIDI_CB_READ, AUDIODF_MIDI_CB_WRITE, AUDIODF_MIDI_CB_INSTALLED }; - -int32_t audiodf_midi_write_status(); -int32_t audiodf_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); -int32_t audiodf_midi_read(uint8_t* buf, uint32_t size); - -int32_t audiodf_midi_register_callback(enum audiodf_midi_cb_type cb_type, FUNC_PTR func); - -/** - * \brief Return version - */ -uint32_t audiodf_midi_get_version(void); - -#endif /* USBDF_AUDIO_MIDI_H_ */ diff --git a/d51n20a/grid/usb/class/midi/usb_protocol_midi.c b/d51n20a/grid/usb/class/midi/usb_protocol_midi.c deleted file mode 100644 index 096a28e6..00000000 --- a/d51n20a/grid/usb/class/midi/usb_protocol_midi.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * usb_protocol_midi.c - * - * Created: 9/30/2019 2:31:56 PM - * Author: WPC-User - */ -#ifndef _USB_PROTOCOL_AUDIO_H_ -#define _USB_PROTOCOL_AUDIO_H_ - -#include "usb_includes.h" - -typedef struct { - uint8_t header; - uint8_t byte1; - uint8_t byte2; - uint8_t byte3; -} midiEventPacket_t; - -#endif diff --git a/d51n20a/grid_d51n20a.c b/d51n20a/grid_d51n20a.c index 53a1e786..8d42a4f2 100644 --- a/d51n20a/grid_d51n20a.c +++ b/d51n20a/grid_d51n20a.c @@ -5,6 +5,8 @@ #include "grid_d51_nvm.h" #include "grid_d51_uart.h" #include "grid_d51_usb.h" +#include "grid_usb.h" +#include "grid_usb_acm.h" #include "atmel_start_pins.h" #include @@ -24,8 +26,6 @@ #include "vmp_def.h" #include "vmp_tag.h" -#include "usb/class/midi/device/audiodf_midi.h" - extern const struct luaL_Reg* grid_lua_api_generic_lib_reference; const struct luaL_Reg gui_lib[] = {{NULL, NULL}}; const struct luaL_Reg* grid_lua_api_gui_lib_reference = gui_lib; @@ -132,28 +132,53 @@ void grid_utask_heart(struct grid_utask_timer* timer) { grid_transport_heartbeat(&grid_transport_state, type, hwcfg, activepage, gccount); } -struct grid_utask_timer timer_midi_and_keyboard_tx; +struct grid_utask_timer timer_midi_tx; +struct grid_utask_timer timer_keyboard_tx; +struct grid_utask_timer timer_gamepad_tx; -void grid_utask_midi_and_keyboard_tx(struct grid_utask_timer* timer) { +struct grid_utask_timer timer_tx_dropped; - if (grid_midi_tx_readable()) { +void grid_utask_usb_tx(void) { - if (!grid_utask_timer_elapsed(timer)) { - return; + if (grid_usb_midi_tx_available(&grid_usb_midi_state)) { + if (grid_utask_timer_elapsed(&timer_midi_tx)) { + grid_usb_midi_tx_flush(&grid_usb_midi_state); } + } - for (uint8_t i = 0; i < 4; ++i) { - grid_midi_tx_pop(); + if (grid_usb_macro_tx_available(&grid_macro_state)) { + if (grid_utask_timer_elapsed(&timer_keyboard_tx)) { + grid_usb_macro_tx_flush(&grid_macro_state); } } - if (grid_usb_keyboard_tx_readable(&grid_usb_keyboard_state)) { + if (grid_usb_gamepad_tx_available(&grid_gamepad_state)) { + if (grid_utask_timer_elapsed(&timer_gamepad_tx)) { + grid_usb_gamepad_tx_flush(&grid_gamepad_state); + } + } - if (!grid_utask_timer_elapsed(timer)) { - return; + if (grid_usb_connected() && grid_usb_acm_dtr(&grid_usb_acm_state) && grid_utask_timer_elapsed(&timer_tx_dropped)) { + + if (grid_usb_midi_state.tx_dropped > 0) { + grid_port_debug_printf("MIDI TX dropped: %lu\n", (unsigned long)grid_usb_midi_state.tx_dropped); + grid_usb_midi_state.tx_dropped = 0; } - grid_usb_keyboard_tx_pop(&grid_usb_keyboard_state); + if (grid_macro_state.tx_dropped > 0) { + grid_port_debug_printf("HID macro TX dropped: %lu\n", (unsigned long)grid_macro_state.tx_dropped); + grid_macro_state.tx_dropped = 0; + } + + if (grid_gamepad_state.tx_dropped > 0) { + grid_port_debug_printf("HID gamepad TX dropped: %lu\n", (unsigned long)grid_gamepad_state.tx_dropped); + grid_gamepad_state.tx_dropped = 0; + } + + if (grid_usb_acm_state.tx_dropped > 0) { + grid_port_debug_printf("CDC TX dropped: %lu\n", (unsigned long)grid_usb_acm_state.tx_dropped); + grid_usb_acm_state.tx_dropped = 0; + } } } @@ -200,9 +225,9 @@ void grid_utask_midi_rx(struct grid_utask_timer* timer) { return; } - grid_midi_rx_pop(); - grid_midi_sysex_rx_pop(); - grid_midi_rtm_rx_pop(); + grid_usb_midi_rx_voice_process(&grid_usb_midi_state); + grid_usb_midi_rx_sysex_process(&grid_usb_midi_state); + grid_usb_midi_rx_rtm_process(&grid_usb_midi_state); } volatile uint8_t rxtimeoutselector = 0; @@ -402,10 +427,22 @@ int main(void) { .last = grid_platform_rtc_get_micros(), .period = GRID_PARAMETER_HEARTBEATINTERVAL_us, }; - timer_midi_and_keyboard_tx = (struct grid_utask_timer){ + timer_midi_tx = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 20, + }; + timer_keyboard_tx = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 20, + }; + timer_gamepad_tx = (struct grid_utask_timer){ .last = grid_platform_rtc_get_micros(), .period = 20, }; + timer_tx_dropped = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 1000000, + }; timer_led = (struct grid_utask_timer){ .last = grid_platform_rtc_get_micros(), .period = 10000, @@ -454,8 +491,11 @@ int main(void) { // grid_d51_nvic_debug_priorities(); } + // Drive TinyUSB stack (bare-metal, OPT_OS_NONE) + grid_usb_task(); + // Check if USB is connected and start animation - if (grid_msg_get_heartbeat_type(&grid_msg_state) != 1 && usb_d_get_frame_num()) { + if (grid_msg_get_heartbeat_type(&grid_msg_state) != 1 && grid_usb_connected()) { grid_platform_printf("USB CONNECTED\n"); @@ -478,7 +518,9 @@ int main(void) { } } - grid_d51_midi_bulkout_poll(); + grid_usb_midi_rx_poll(&grid_usb_midi_state); + grid_usb_acm_rx_poll(&grid_usb_acm_state); + grid_usb_acm_rx_process(&grid_usb_acm_state); // Run UI protothreads update_interrupt_mask_from_bulk_status(); @@ -518,7 +560,7 @@ int main(void) { grid_port_send_usb(port_usb); // Run transmitter-type microtasks - grid_utask_midi_and_keyboard_tx(&timer_midi_and_keyboard_tx); + grid_utask_usb_tx(); // Decode for UI grid_port_send_ui(port_ui); diff --git a/esp32s3/components/grid_common/CMakeLists.txt b/esp32s3/components/grid_common/CMakeLists.txt index ebd18823..b6fd4f4d 100644 --- a/esp32s3/components/grid_common/CMakeLists.txt +++ b/esp32s3/components/grid_common/CMakeLists.txt @@ -17,4 +17,7 @@ idf_component_register( "common/dep/lua-5.5.0/src" "common/dep/proto" "common/build/lua" + + REQUIRES + "tinyusb" ) diff --git a/esp32s3/components/grid_esp32_port/CMakeLists.txt b/esp32s3/components/grid_esp32_port/CMakeLists.txt index 03028072..3c419bad 100644 --- a/esp32s3/components/grid_esp32_port/CMakeLists.txt +++ b/esp32s3/components/grid_esp32_port/CMakeLists.txt @@ -4,5 +4,5 @@ idf_component_register( INCLUDE_DIRS "." REQUIRES - "driver" "grid_common" "esp_tinyusb" "grid_esp32_platform" "grid_esp32_pins" "grid_esp32_lcd" + "driver" "grid_common" "tinyusb" "grid_esp32_platform" "grid_esp32_pins" "grid_esp32_lcd" ) diff --git a/esp32s3/components/grid_esp32_port/grid_esp32_port.c b/esp32s3/components/grid_esp32_port/grid_esp32_port.c index f6f61a06..4ca60de4 100644 --- a/esp32s3/components/grid_esp32_port/grid_esp32_port.c +++ b/esp32s3/components/grid_esp32_port/grid_esp32_port.c @@ -19,8 +19,6 @@ #include "esp_freertos_hooks.h" #include "driver/gpio.h" -#include "tinyusb.h" - #include "esp_rom_gpio.h" #include "hal/gpio_ll.h" @@ -28,6 +26,9 @@ #include "grid_esp32_pins.h" #include "grid_esp32_platform.h" #include "grid_rollid.h" +#include "grid_usb.h" +#include "grid_usb_acm.h" + #include "grid_sys.h" #include "grid_transport.h" #include "grid_ui.h" @@ -224,26 +225,53 @@ void grid_utask_heart(struct grid_utask_timer* timer) { grid_transport_heartbeat(&grid_transport_state, type, hwcfg, activepage, gccount); } -struct grid_utask_timer timer_midi_and_keyboard_tx; +struct grid_utask_timer timer_midi_tx; +struct grid_utask_timer timer_keyboard_tx; +struct grid_utask_timer timer_gamepad_tx; -void grid_utask_midi_and_keyboard_tx(struct grid_utask_timer* timer) { +struct grid_utask_timer timer_tx_dropped; - if (grid_midi_tx_readable()) { +void grid_utask_usb_tx(void) { - if (!grid_utask_timer_elapsed(timer)) { - return; + if (grid_usb_midi_tx_available(&grid_usb_midi_state)) { + if (grid_utask_timer_elapsed(&timer_midi_tx)) { + grid_usb_midi_tx_flush(&grid_usb_midi_state); } + } - grid_midi_tx_pop(); + if (grid_usb_macro_tx_available(&grid_macro_state)) { + if (grid_utask_timer_elapsed(&timer_keyboard_tx)) { + grid_usb_macro_tx_flush(&grid_macro_state); + } } - if (grid_usb_keyboard_tx_readable(&grid_usb_keyboard_state)) { + if (grid_usb_gamepad_tx_available(&grid_gamepad_state)) { + if (grid_utask_timer_elapsed(&timer_gamepad_tx)) { + grid_usb_gamepad_tx_flush(&grid_gamepad_state); + } + } - if (!grid_utask_timer_elapsed(timer)) { - return; + if (grid_usb_connected() && grid_usb_acm_dtr(&grid_usb_acm_state) && grid_utask_timer_elapsed(&timer_tx_dropped)) { + + if (grid_usb_midi_state.tx_dropped > 0) { + grid_port_debug_printf("MIDI TX dropped: %lu\n", (unsigned long)grid_usb_midi_state.tx_dropped); + grid_usb_midi_state.tx_dropped = 0; + } + + if (grid_macro_state.tx_dropped > 0) { + grid_port_debug_printf("HID macro TX dropped: %lu\n", (unsigned long)grid_macro_state.tx_dropped); + grid_macro_state.tx_dropped = 0; + } + + if (grid_gamepad_state.tx_dropped > 0) { + grid_port_debug_printf("HID gamepad TX dropped: %lu\n", (unsigned long)grid_gamepad_state.tx_dropped); + grid_gamepad_state.tx_dropped = 0; } - grid_usb_keyboard_tx_pop(&grid_usb_keyboard_state); + if (grid_usb_acm_state.tx_dropped > 0) { + grid_port_debug_printf("CDC TX dropped: %lu\n", (unsigned long)grid_usb_acm_state.tx_dropped); + grid_usb_acm_state.tx_dropped = 0; + } } } @@ -272,9 +300,9 @@ void grid_utask_midi_rx(struct grid_utask_timer* timer) { if (!grid_utask_timer_elapsed(timer)) { return; } - grid_midi_rx_pop(); - grid_midi_sysex_rx_pop(); - grid_midi_rtm_rx_pop(); + grid_usb_midi_rx_voice_process(&grid_usb_midi_state); + grid_usb_midi_rx_sysex_process(&grid_usb_midi_state); + grid_usb_midi_rx_rtm_process(&grid_usb_midi_state); } extern struct grid_utask_timer timer_draw_event[2]; @@ -429,10 +457,22 @@ void grid_esp32_port_task(void* arg) { .last = grid_platform_rtc_get_micros(), .period = GRID_PARAMETER_HEARTBEATINTERVAL_us, }; - timer_midi_and_keyboard_tx = (struct grid_utask_timer){ + timer_midi_tx = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 20, + }; + timer_keyboard_tx = (struct grid_utask_timer){ .last = grid_platform_rtc_get_micros(), .period = 20, }; + timer_gamepad_tx = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 20, + }; + timer_tx_dropped = (struct grid_utask_timer){ + .last = grid_platform_rtc_get_micros(), + .period = 1000000, + }; timer_process_ui = (struct grid_utask_timer){ .last = grid_platform_rtc_get_micros(), .period = GRID_PARAMETER_UICOOLDOWN_us, @@ -468,7 +508,7 @@ void grid_esp32_port_task(void* arg) { } // Check if USB is connected and start animation - if (grid_msg_get_heartbeat_type(&grid_msg_state) != 1 && tud_connected()) { + if (grid_msg_get_heartbeat_type(&grid_msg_state) != 1 && grid_usb_connected()) { grid_platform_printf("USB CONNECTED\n"); @@ -517,14 +557,16 @@ void grid_esp32_port_task(void* arg) { grid_port_send_usb(port_usb); // Run transmitter-type microtasks - grid_utask_midi_and_keyboard_tx(&timer_midi_and_keyboard_tx); + grid_utask_usb_tx(); // Service tinyusb - tud_task_ext(0, false); + grid_usb_task(); // Duplicate midi rx callback used as a polling mechanism, as the // actual callback may not necessarily process all available data - tud_midi_rx_cb(0); + grid_usb_midi_rx_poll(&grid_usb_midi_state); + grid_usb_acm_rx_poll(&grid_usb_acm_state); + grid_usb_acm_rx_process(&grid_usb_acm_state); // Decode for UI grid_port_send_ui(port_ui); diff --git a/esp32s3/components/grid_esp32_usb/CMakeLists.txt b/esp32s3/components/grid_esp32_usb/CMakeLists.txt index cf3eea81..9850be41 100644 --- a/esp32s3/components/grid_esp32_usb/CMakeLists.txt +++ b/esp32s3/components/grid_esp32_usb/CMakeLists.txt @@ -4,5 +4,5 @@ idf_component_register( INCLUDE_DIRS "." REQUIRES - "driver" "grid_common" "esp_tinyusb" + "driver" "grid_common" "tinyusb" "esp_hw_support" ) diff --git a/esp32s3/components/grid_esp32_usb/grid_esp32_usb.c b/esp32s3/components/grid_esp32_usb/grid_esp32_usb.c index b5c35cf1..4ba7dbad 100644 --- a/esp32s3/components/grid_esp32_usb/grid_esp32_usb.c +++ b/esp32s3/components/grid_esp32_usb/grid_esp32_usb.c @@ -4,189 +4,39 @@ * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ -#include "grid_esp32_usb.h" - -#include "esp_check.h" +#include -#include "rom/ets_sys.h" // For ets_printf +#include "tusb.h" +#include "esp_check.h" #include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" -#include "freertos/task.h" -#include -#include - -#include "driver/gpio.h" -#include "tinyusb.h" -// #include "../../grid_common/grid_port.h" -#include "grid_transport.h" +#include "esp_private/usb_phy.h" +#include "grid_esp32_usb.h" #include "grid_usb.h" -// #include "../../grid_common/grid_sys.h" - -#include "driver/gpio.h" -#include "tinyusb.h" -#include "tinyusb_cdc_acm.h" -#include "tinyusb_default_config.h" - -static const char* TAG = "USB example"; - -void tud_midi_rx_cb(uint8_t itf) { - - (void)itf; - - // ets_printf("MIDI RX: %d\n", itf); - - // The MIDI interface always creates input and output port/jack descriptors - // regardless of these being used or not. Therefore incoming traffic should be - // read (possibly just discarded) to avoid the sender blocking in IO - uint8_t packet[4]; - - while (tud_midi_available()) { - - if (!grid_midi_rx_writable()) { - break; - } - - if (tud_midi_packet_read(packet)) { - - // Pass raw USB MIDI packet bytes to state machine - grid_midi_rx_push(packet[0], packet[1], packet[2], packet[3]); - } - } -} - -struct grid_swsr_t cdc_rx; - -void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t* event) { - - size_t rx_size = 0; - uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE + 1]; - esp_err_t err = tinyusb_cdcacm_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE, &rx_size); - - if (err != ESP_OK) { - return; - } - - struct grid_swsr_t* rx = &cdc_rx; - - if (grid_swsr_writable(rx, rx_size)) { - grid_swsr_write(rx, buf, rx_size); - } else { - grid_swsr_read(rx, NULL, grid_swsr_size(rx)); - } - - struct grid_msg msg; - - if (!grid_msg_from_swsr(&msg, rx)) { - return; - } - - if (grid_frame_verify((uint8_t*)msg.data, msg.length) == 0) { - - grid_transport_recv_usb(&grid_transport_state, (uint8_t*)msg.data, msg.length); - } -} - -static uint8_t DRAM_ATTR usb_tx_ready = 0; - -void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t* event) { - int dtr = event->line_state_changed_data.dtr; - int rts = event->line_state_changed_data.rts; - ESP_LOGI(TAG, "Line state changed on channel %d: DTR:%d, RTS:%d", itf, dtr, rts); - - usb_tx_ready = 1; -} - -void tud_cdc_tx_complete_cb(uint8_t itf) { - // ets_printf("CDC TXC\r\n"); - /*esp_err_t status = */ tinyusb_cdcacm_write_flush(0, 0); - - usb_tx_ready = 1; - // ets_printf("# %d\r\n", status); -} - -int32_t grid_platform_usb_serial_ready() { return usb_tx_ready; } - -int32_t grid_platform_usb_serial_write(char* buffer, uint32_t length) { - - // portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - // portENTER_CRITICAL(&spinlock); - - esp_err_t status = 0; - - // tinyusb_cdcacm_write_flush(0, pdMS_TO_TICKS(10)); - if (usb_tx_ready == 1) { - - // ets_printf("$\r\n"); - - usb_tx_ready = 0; - - uint32_t queued = tinyusb_cdcacm_write_queue(0, (const uint8_t*)buffer, length); - - if (queued != length) { - ets_printf("CDC QUEUE ERROR: %d %d\r\n", queued, length); - tinyusb_cdcacm_write_flush(0, 0); - } else { - status = tinyusb_cdcacm_write_flush(0, 0); - // ets_printf("$ %d\r\n", status); - } - } else { - - status = tinyusb_cdcacm_write_flush(0, 0); - - // ets_printf("SKIP %d\r\n", status); - - if (status == ESP_OK) { - // ets_printf("READY\r\n"); - usb_tx_ready = 1; - } - } - - // portEXIT_CRITICAL(&spinlock); - - return 1; -} - -// =========================== HID ======================== // - -/** - * @brief HID report descriptor - * - * In this example we implement Keyboard + Mouse HID device, - * so we must define both report descriptors - */ -const uint8_t hid_report_descriptor[] = {TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_ITF_PROTOCOL_KEYBOARD)), TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_ITF_PROTOCOL_MOUSE)), - TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(3))}; -/********* TinyUSB HID callbacks ***************/ - -// Invoked when received GET HID REPORT DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long -// enough for transfer to complete -uint8_t const* tud_hid_descriptor_report_cb(uint8_t instance) { - // We use only one interface and one HID report descriptor, so we can ignore - // parameter 'instance' - return hid_report_descriptor; -} - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -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) { - (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) {} +static const char* TAG = "USB"; + +// ========================= USB Descriptors =============================== // + +// Device descriptor. We use the IAD class because CDC is enabled. +static const tusb_desc_device_t s_device_desc = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + // IAD required when CDC is present + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303a, // Espressif VID (same as sdkconfig CUSTOM_VID) + .idProduct = 0x8123, // sdkconfig CUSTOM_PID + .bcdDevice = 0x0100, // sdkconfig BCD_DEVICE + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01, +}; // Interface counter enum interface_count { @@ -206,7 +56,6 @@ enum interface_count { // USB Endpoint numbers enum usb_endpoints { - // Available USB Endpoints: 5 IN/OUT EPs and 1 IN EP EP_EMPTY = 0, #if CFG_TUD_CDC EPNUM_CDC_NOTIFY, @@ -221,236 +70,100 @@ enum usb_endpoints { ENDPOINT_COUNT }; -// #EPNUM_MIDI_IN -// #EPNUM_MIDI_OUT - -/** TinyUSB descriptors **/ +#if CFG_TUD_HID +#define HID_DESC_LEN TUD_HID_DESC_LEN +#else +#define HID_DESC_LEN 0 +#endif -#define TUSB_DESCRIPTOR_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + CFG_TUD_MIDI * TUD_MIDI_DESC_LEN + CFG_TUD_HID * TUD_HID_DESC_LEN) +#define TUSB_DESCRIPTOR_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + CFG_TUD_MIDI * TUD_MIDI_DESC_LEN + CFG_TUD_HID * HID_DESC_LEN) -/** - * @brief String descriptor - */ -// UTF-16LE language ID (0x0409 = English US) +// String descriptors (index 0 = language ID as raw UTF-16LE bytes) static const uint16_t _usb_lang_id[] = {0x0409}; static const void* s_str_desc[6] = { - _usb_lang_id, // index 0: valid UTF-16 buffer - "Intech Studio", // 1 - "Grid", // 2 - "123456", // 3 - "Intech Grid MIDI device", // 4 - "Intech Grid CDC device", // 5 + _usb_lang_id, // 0: language ID + "Intech Studio", // 1: Manufacturer + "Grid", // 2: Product + "123456", // 3: Serial + "Intech Grid MIDI device", // 4: MIDI interface + "Intech Grid CDC device", // 5: CDC interface }; static const uint8_t strcnt = 6; -/** - * @brief Configuration descriptor - * - * This is a simple configuration descriptor that defines 1 configuration and a - * MIDI interface - */ +// Configuration descriptor static uint8_t s_cfg_desc[] = { - // Configuration number, interface count, string index, total length, - // attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_COUNT, 0, TUSB_DESCRIPTOR_TOTAL_LEN, 0, 500), #if CFG_TUD_CDC - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_NOTIFY, 5, (0x80 | EPNUM_CDC_NOTIFY), 64, EPNUM_CDC_DATA, (0x80 | EPNUM_CDC_DATA), 64), + // Notification EP reduced to 8 bytes (notifications are small) + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_NOTIFY, 5, (0x80 | EPNUM_CDC_NOTIFY), 8, EPNUM_CDC_DATA, (0x80 | EPNUM_CDC_DATA), 64), #endif #if CFG_TUD_MIDI - // Interface number, string index, EP Out & EP In address, EP size TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 4, EPNUM_MIDI, (0x80 | EPNUM_MIDI), 64), #endif #if CFG_TUD_HID - // Interface number, string index, boot protocol, report descriptor len, EP - // In address, size & polling interval - TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, false, sizeof(hid_report_descriptor), (0x80 | EPNUM_HID), 16, 10), + TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, false, GRID_HID_REPORT_DESC_SIZE, (0x80 | EPNUM_HID), 16, 10), #endif - }; -void grid_esp32_usb_init() { - - tinyusb_config_t config = TINYUSB_DEFAULT_CONFIG(); - config.descriptor.device = NULL; - config.descriptor.string = (const char**)s_str_desc; - config.descriptor.string_count = strcnt; - config.phy.skip_setup = false; - config.descriptor.full_speed_config = s_cfg_desc; - - ESP_ERROR_CHECK(tinyusb_driver_install(&config)); - - tinyusb_config_cdcacm_t acm_cfg = {//.usb_dev = TINYUSB_USBDEV_0, - .cdc_port = TINYUSB_CDC_ACM_0, - //.rx_unread_buf_sz = 64, - .callback_rx = &tinyusb_cdc_rx_callback, // the first way to register a callback - .callback_rx_wanted_char = NULL, - .callback_line_state_changed = NULL, - .callback_line_coding_changed = NULL}; +// ========================= TinyUSB Descriptor Callbacks =============================== // - ESP_ERROR_CHECK(tinyusb_cdcacm_init(&acm_cfg)); - /* the second way to register a callback */ - ESP_ERROR_CHECK(tinyusb_cdcacm_register_callback(TINYUSB_CDC_ACM_0, CDC_EVENT_LINE_STATE_CHANGED, &tinyusb_cdc_line_state_changed_callback)); +uint8_t const* tud_descriptor_device_cb(void) { return (uint8_t const*)&s_device_desc; } - // Allocate CDC RX buffer - int capacity = GRID_PARAMETER_SPI_TRANSACTION_length * 2; - assert(grid_swsr_malloc(&cdc_rx, capacity) == 0); - - // END OF USB +uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { + (void)index; // Only one configuration supported + return s_cfg_desc; } -// ========================= PLATFORM =============================== // - -int32_t grid_platform_usb_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) { - - const uint8_t buffer[] = {byte0, byte1, byte2, byte3}; - - if (tud_midi_mounted()) { - - tud_midi_packet_write(buffer); - - // tud_midi_stream_write(0, &buffer[1], 3); - - // ets_printf("MIDI\r\n"); - } - - return 0; -} - -int32_t grid_platform_usb_midi_write_status(void) { - - // ets_printf("PLATFORM MIDI STATUS \r\n"); - // ets_printf("grid_platform_usb_midi_write_status NOT IMPLEMENTED!!!"); - return 0; -} - -enum mouse_button_type { LEFT_BTN = 0x01, RIGHT_BTN = 0x02, MIDDLE_BTN = 0x04 }; - -static uint8_t hid_mouse_button_state = 0; - -static uint32_t hid_gamepad_button_state = 0; - -static int8_t hid_gamepad_axis_x = 0; -static int8_t hid_gamepad_axis_y = 0; -static int8_t hid_gamepad_axis_z = 0; - -static int8_t hid_gamepad_axis_rx = 0; -static int8_t hid_gamepad_axis_ry = 0; -static int8_t hid_gamepad_axis_rz = 0; - -static uint8_t hid_gamepad_hat = 0; - -int32_t grid_platform_usb_mouse_button_change(uint8_t b_state, uint8_t type) { - - if (b_state == 1) { // button pressed - hid_mouse_button_state |= type; - } else { - hid_mouse_button_state &= ~type; - } - - // report_id, buttons, dx, dy, wheel, pan - return 0 == tud_hid_mouse_report(HID_ITF_PROTOCOL_MOUSE, hid_mouse_button_state, 0, 0, 0, 0); -} - -int32_t grid_platform_usb_mouse_move(int8_t position, uint8_t axis) { - - int8_t delta_x = 0; - int8_t delta_y = 0; - int8_t wheel = 0; - int8_t pan = 0; // not used - - if (axis == X_AXIS_MV) { - delta_x = position; - } else if (axis == Y_AXIS_MV) { - delta_y = position; - } else if (axis == SCROLL_MV) { - wheel = position; - } else { - return 0; // Invalid axis - } - - // report_id, buttons, dx, dy, wheel, pan - return 0 == tud_hid_mouse_report(HID_ITF_PROTOCOL_MOUSE, hid_mouse_button_state, delta_x, delta_y, wheel, pan); -} - -int32_t grid_platform_usb_gamepad_axis_move(uint8_t axis, int32_t value) { - - switch (axis) { - case GAMEPAD_AXIS_X: - hid_gamepad_axis_x = value; - break; - case GAMEPAD_AXIS_Y: - hid_gamepad_axis_y = value; - break; - case GAMEPAD_AXIS_Z: - hid_gamepad_axis_z = value; - break; - case GAMEPAD_AXIS_RX: - hid_gamepad_axis_rx = value; - break; - case GAMEPAD_AXIS_RY: - hid_gamepad_axis_ry = value; - break; - case GAMEPAD_AXIS_RZ: - hid_gamepad_axis_rz = value; - break; - default: - ets_printf("INVALID AXIS\r\n"); - return 0; - } - - return 0 == tud_hid_gamepad_report(3, hid_gamepad_axis_x, hid_gamepad_axis_y, hid_gamepad_axis_z, hid_gamepad_axis_rz, hid_gamepad_axis_ry, hid_gamepad_axis_rx, hid_gamepad_hat, - hid_gamepad_button_state); -} - -int32_t grid_platform_usb_gamepad_button_change(uint8_t button, uint8_t value) { - - if (value) { - hid_gamepad_button_state |= (1 << button); +#define MAX_DESC_STR_LEN 32 + +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; + static uint16_t desc_str[MAX_DESC_STR_LEN]; + + uint8_t chr_count; + if (index == 0) { + // Language ID: copy 2 raw bytes from the uint16_t array entry + memcpy(&desc_str[1], s_str_desc[0], 2); + chr_count = 1; + } else if (index < strcnt) { + const char* str = (const char*)s_str_desc[index]; + chr_count = (uint8_t)strnlen(str, MAX_DESC_STR_LEN - 1); + for (uint8_t i = 0; i < chr_count; i++) { + desc_str[1 + i] = str[i]; // ASCII → UTF-16LE + } } else { - hid_gamepad_button_state &= ~(1 << button); + return NULL; } - return 0 == tud_hid_gamepad_report(3, hid_gamepad_axis_x, hid_gamepad_axis_y, hid_gamepad_axis_z, hid_gamepad_axis_rx, hid_gamepad_axis_ry, hid_gamepad_axis_rz, hid_gamepad_hat, - hid_gamepad_button_state); + // First word: length in bytes (header + char data) | descriptor type + desc_str[0] = (TUSB_DESC_STRING << 8) | (uint8_t)(2 * chr_count + 2); + return desc_str; } -int32_t grid_platform_usb_keyboard_keys_state_change(struct grid_usb_keyboard_event_desc* active_key_list, uint8_t keys_count) { - - struct grid_usb_hid_kb_desc key_descriptor_array[GRID_KEYBOARD_KEY_maxcount]; - for (uint8_t i = 0; i < GRID_KEYBOARD_KEY_maxcount; i++) { - - key_descriptor_array[i].b_modifier = active_key_list[i].ismodifier; - key_descriptor_array[i].key_id = active_key_list[i].keycode; - key_descriptor_array[i].state = active_key_list[i].ispressed; - } - - uint8_t keycode[6] = {0}; - - uint8_t modifier = 0; // modifier flags - - if (keys_count == 0) { - ESP_LOGD(TAG, "No Key Is Pressed"); - } - - for (uint8_t i = 0; i < keys_count; i++) { +// ========================= USB Initialization =============================== // - ESP_LOGD(TAG, "IsMod: %d, KeyCode: %d, State: %d", key_descriptor_array[i].b_modifier, key_descriptor_array[i].key_id, key_descriptor_array[i].state); +void grid_esp32_usb_init(void) { - if (key_descriptor_array[i].b_modifier) { + // 1. Configure the on-chip USB PHY for full-speed OTG device mode. + usb_phy_handle_t phy_hdl; + usb_phy_config_t phy_conf = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_DEVICE, + .otg_speed = USB_PHY_SPEED_FULL, + }; + ESP_ERROR_CHECK(usb_new_phy(&phy_conf, &phy_hdl)); - modifier |= key_descriptor_array[i].key_id; - } else if (key_descriptor_array[i].state && key_descriptor_array[i].key_id != 255) { + // 2. Initialise USB infrastructure (ACM, MIDI buffers, HID keyboard model) + grid_usb_infrastructure_init(); - keycode[keys_count] = key_descriptor_array[i].key_id; - keys_count++; - } - } + // 3. Initialise TinyUSB device stack + tusb_init(); - // Report Id, modifier, keycodearray - return 0 == tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, modifier, keycode); + ESP_LOGI(TAG, "USB initialized"); } diff --git a/esp32s3/components/grid_esp32_usb/grid_esp32_usb.h b/esp32s3/components/grid_esp32_usb/grid_esp32_usb.h index 36431e2d..fa67ad22 100644 --- a/esp32s3/components/grid_esp32_usb/grid_esp32_usb.h +++ b/esp32s3/components/grid_esp32_usb/grid_esp32_usb.h @@ -7,47 +7,15 @@ #include +#include "grid_usb_acm.h" +#include "grid_usb_hid.h" +#include "grid_usb_midi.h" + #ifdef __cplusplus extern "C" { #endif -/* -#undef CFG_TUD_CDC -#undef CFG_TUD_HID -#undef CFG_TUD_MIDI -#undef CFG_TUD_MSC -#undef CFG_TUD_VENDOR - -#define CFG_TUD_CDC 1 -#define CFG_TUD_HID 1 -#define CFG_TUD_MIDI 1 -#define CFG_TUD_MSC 0 -#define CFG_TUD_VENDOR 0 -*/ - -/* HID Mouse Class Pointer Move Type */ -enum mouse_move_type { X_AXIS_MV = 0x01, Y_AXIS_MV = 0x02, SCROLL_MV = 0x03 }; - -enum gamepad_axis_t { GAMEPAD_AXIS_X = 0, GAMEPAD_AXIS_Y, GAMEPAD_AXIS_Z, GAMEPAD_AXIS_RX, GAMEPAD_AXIS_RY, GAMEPAD_AXIS_RZ }; - -/** Helper defines **/ - void grid_esp32_usb_init(void); -void grid_esp32_usb_task(void* arg); - -extern void grid_platform_sync1_pulse_send(); - -int32_t grid_platform_usb_serial_write(char* buffer, uint32_t length); - -int32_t grid_platform_usb_midi_write(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3); - -int32_t grid_platform_usb_midi_write_status(void); - -int32_t grid_platform_usb_mouse_button_change(uint8_t b_state, uint8_t type); -int32_t grid_platform_usb_mouse_move(int8_t position, uint8_t axis); - -int32_t grid_platform_usb_gamepad_axis_move(uint8_t axis, int32_t value); -int32_t grid_platform_usb_gamepad_button_change(uint8_t button, uint8_t value); #ifdef __cplusplus } diff --git a/esp32s3/components/tinyusb/CMakeLists.txt b/esp32s3/components/tinyusb/CMakeLists.txt new file mode 100644 index 00000000..ca902d87 --- /dev/null +++ b/esp32s3/components/tinyusb/CMakeLists.txt @@ -0,0 +1,38 @@ +# Local TinyUSB component — compiles upstream hathach/tinyusb from the +# git submodule at common/dep/tinyusb (pinned to tag 0.19.0). +# +# This replaces the espressif/esp_tinyusb managed component and gives us +# full control over the TinyUSB version. + +# Path to the submodule relative to this CMakeLists.txt +set(TUSB_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../../common/dep/tinyusb") + +set(tusb_srcs + "${TUSB_ROOT}/src/tusb.c" + "${TUSB_ROOT}/src/common/tusb_fifo.c" + "${TUSB_ROOT}/src/device/usbd.c" + "${TUSB_ROOT}/src/device/usbd_control.c" + "${TUSB_ROOT}/src/class/cdc/cdc_device.c" + "${TUSB_ROOT}/src/class/midi/midi_device.c" + "${TUSB_ROOT}/src/class/hid/hid_device.c" + "${TUSB_ROOT}/src/portable/synopsys/dwc2/dcd_dwc2.c" + "${TUSB_ROOT}/src/portable/synopsys/dwc2/dwc2_common.c" +) + +idf_component_register( + SRCS ${tusb_srcs} + INCLUDE_DIRS + "include" + "${TUSB_ROOT}/src" + PRIV_INCLUDE_DIRS + "${TUSB_ROOT}/src/device" + REQUIRES + freertos +) + +# usbd.c compares uint8_t against BUILTIN_DRIVER_COUNT which may always be +# true when no built-in class drivers are enabled — suppress the warning. +set_source_files_properties( + "${TUSB_ROOT}/src/device/usbd.c" + PROPERTIES COMPILE_FLAGS "-Wno-type-limits" +) diff --git a/esp32s3/components/tinyusb/include/tusb_config.h b/esp32s3/components/tinyusb/include/tusb_config.h new file mode 100644 index 00000000..fa1ebbcd --- /dev/null +++ b/esp32s3/components/tinyusb/include/tusb_config.h @@ -0,0 +1,76 @@ +/* + * TinyUSB configuration for Grid firmware (ESP32-S3). + * + * This file is picked up by TinyUSB's tusb_option.h before any TinyUSB + * macros are defined, so keep it to plain #defines only — no TU_* macros. + * + * CFG_TUSB_MCU is injected as a compiler flag from CMakeLists.txt so that + * a single tusb_config.h works for both ESP32-S2 and ESP32-S3 targets. + */ +#pragma once + +// ---- MCU ---- +#define CFG_TUSB_MCU OPT_MCU_ESP32S3 + +// ---- OS abstraction ---- +#define CFG_TUSB_OS OPT_OS_FREERTOS + +// ---- Debug (0 = silent) ---- +#define CFG_TUSB_DEBUG 0 + +// ---- Root-hub port (full-speed device) — enables no-arg tusb_init() ---- +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) + +// ---- Device stack ---- +#define CFG_TUD_ENABLED 1 + +// ---- Endpoint 0 packet size ---- +#define CFG_TUD_ENDPOINT0_SIZE 64 + +// ---- Memory attributes ---- +// Plain 4-byte-aligned SRAM (slave mode does not require DMA-capable memory). +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4))) +#endif + +// ============================================================ +// Device class drivers +// ============================================================ + +// CDC (virtual serial) — 1 instance +#ifndef CFG_TUD_CDC +#define CFG_TUD_CDC 1 +#endif +#define CFG_TUD_CDC_RX_BUFSIZE 512 +#define CFG_TUD_CDC_TX_BUFSIZE 1024 +#define CFG_TUD_CDC_EP_BUFSIZE 512 + +// MIDI — 1 instance +#ifndef CFG_TUD_MIDI +#define CFG_TUD_MIDI 1 +#endif +#define CFG_TUD_MIDI_RX_BUFSIZE 64 +#define CFG_TUD_MIDI_TX_BUFSIZE 64 +#define CFG_TUD_MIDI_EP_BUFSIZE 64 +#define CFG_TUD_MIDI_EPSIZE CFG_TUD_MIDI_EP_BUFSIZE + +// HID (keyboard + mouse + gamepad) — 1 instance +#ifndef CFG_TUD_HID +#define CFG_TUD_HID 1 +#endif +#define CFG_TUD_HID_EP_BUFSIZE 64 + +// Disabled classes +#define CFG_TUD_MSC 0 +#define CFG_TUD_VENDOR 0 +#define CFG_TUD_ECM_RNDIS 0 +#define CFG_TUD_NCM 0 +#define CFG_TUD_AUDIO 0 +#define CFG_TUD_VIDEO 0 +#define CFG_TUD_DFU 0 +#define CFG_TUD_DFU_RUNTIME 0 +#define CFG_TUD_BTH 0 +#define CFG_TUD_USBTMC 0 diff --git a/esp32s3/main/grid_esp32s3.c b/esp32s3/main/grid_esp32s3.c index 636abf23..1e432d69 100644 --- a/esp32s3/main/grid_esp32s3.c +++ b/esp32s3/main/grid_esp32s3.c @@ -91,8 +91,7 @@ static const char* TAG = "main"; -#include "tinyusb.h" -#include "tinyusb_cdc_acm.h" +#include "tusb.h" static bool periodic_rtc_ms_cb(struct gptimer_t*, const gptimer_alarm_event_data_t*, void*) { @@ -453,8 +452,6 @@ void app_main(void) { grid_esp32_led_start(grid_led_get_pin(&grid_led_state)); grid_esp32_usb_init(); - grid_usb_midi_buffer_init(); - grid_usb_keyboard_model_init(&grid_usb_keyboard_state, 100); // GRID MODULE INITIALIZATION SEQUENCE diff --git a/esp32s3/main/idf_component.yml b/esp32s3/main/idf_component.yml index 92ad6e46..f17b35f3 100644 --- a/esp32s3/main/idf_component.yml +++ b/esp32s3/main/idf_component.yml @@ -1,6 +1,5 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp_tinyusb: "*" ## Required IDF version idf: version: ">=4.1.0" diff --git a/esp32s3/sdkconfig b/esp32s3/sdkconfig index ced53a4a..ff5e8205 100644 --- a/esp32s3/sdkconfig +++ b/esp32s3/sdkconfig @@ -2816,100 +2816,6 @@ CONFIG_WL_SECTOR_SIZE_4096=y # default: CONFIG_WL_SECTOR_SIZE=4096 # end of Wear Levelling - -# -# TinyUSB Stack -# -CONFIG_TINYUSB_DEBUG_LEVEL=1 - -# -# TinyUSB DCD -# -# CONFIG_TINYUSB_MODE_SLAVE is not set -CONFIG_TINYUSB_MODE_DMA=y -# end of TinyUSB DCD - -# -# TinyUSB callbacks -# -# CONFIG_TINYUSB_SUSPEND_CALLBACK is not set -# CONFIG_TINYUSB_RESUME_CALLBACK is not set -# end of TinyUSB callbacks - -# -# Descriptor configuration -# - -# -# You can provide your custom descriptors via tinyusb_driver_install() -# -# CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID is not set -CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303a -# CONFIG_TINYUSB_DESC_USE_DEFAULT_PID is not set -CONFIG_TINYUSB_DESC_CUSTOM_PID=0x8123 -CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100 -CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Intech Studio" -CONFIG_TINYUSB_DESC_PRODUCT_STRING="Grid" -CONFIG_TINYUSB_DESC_SERIAL_STRING="123456" -CONFIG_TINYUSB_DESC_CDC_STRING="Intech Grid CDC Device" -# end of Descriptor configuration - -# -# Mass Storage Class (MSC) -# -# CONFIG_TINYUSB_MSC_ENABLED is not set -# end of Mass Storage Class (MSC) - -# -# Communication Device Class (CDC) -# -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_CDC_COUNT=1 -CONFIG_TINYUSB_CDC_RX_BUFSIZE=512 -CONFIG_TINYUSB_CDC_TX_BUFSIZE=1024 -CONFIG_TINYUSB_CDC_EP_BUFSIZE=512 -# end of Communication Device Class (CDC) - -# -# Musical Instrument Digital Interface (MIDI) -# -CONFIG_TINYUSB_MIDI_COUNT=1 -# end of Musical Instrument Digital Interface (MIDI) - -# -# Human Interface Device Class (HID) -# -CONFIG_TINYUSB_HID_COUNT=1 -# end of Human Interface Device Class (HID) - -# -# Device Firmware Upgrade (DFU) -# -# CONFIG_TINYUSB_DFU_MODE_DFU is not set -# CONFIG_TINYUSB_DFU_MODE_DFU_RUNTIME is not set -CONFIG_TINYUSB_DFU_MODE_NONE=y -# end of Device Firmware Upgrade (DFU) - -# -# Bluetooth Host Class (BTH) -# -# CONFIG_TINYUSB_BTH_ENABLED is not set -# end of Bluetooth Host Class (BTH) - -# -# Network driver (ECM/NCM/RNDIS) -# -# CONFIG_TINYUSB_NET_MODE_ECM_RNDIS is not set -# CONFIG_TINYUSB_NET_MODE_NCM is not set -CONFIG_TINYUSB_NET_MODE_NONE=y -# end of Network driver (ECM/NCM/RNDIS) - -# -# Vendor Specific Interface -# -CONFIG_TINYUSB_VENDOR_COUNT=0 -# end of Vendor Specific Interface -# end of TinyUSB Stack # end of Component config CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/ignore-words.txt b/ignore-words.txt index 07828432..fd33e01a 100644 --- a/ignore-words.txt +++ b/ignore-words.txt @@ -1,4 +1,5 @@ synopsis +synopsys sie tree thre diff --git a/test/.gitignore b/test/.gitignore index a5849c65..96fc9142 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -2,3 +2,4 @@ !platform.c !test.c !test.h +!tusb_config.h diff --git a/test/tusb_config.h b/test/tusb_config.h new file mode 100644 index 00000000..28147b52 --- /dev/null +++ b/test/tusb_config.h @@ -0,0 +1,12 @@ +#pragma once + +/* Stub for host unit tests — actual platform tusb_config.h provides real values */ +#ifndef CFG_TUD_CDC +#define CFG_TUD_CDC 0 +#endif +#ifndef CFG_TUD_MIDI +#define CFG_TUD_MIDI 0 +#endif +#ifndef CFG_TUD_HID +#define CFG_TUD_HID 0 +#endif