From bc0e082b890c9ed8d21e94cbc79a8d26e5516e64 Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Tue, 9 Dec 2025 18:30:42 -0500 Subject: [PATCH] starting with commands --- hello_usb.cpp | 87 +++++++++++++++++++++++++++++++++++--------- suspend_fix_notes.md | 42 +++++++++++++++++++++ 2 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 suspend_fix_notes.md diff --git a/hello_usb.cpp b/hello_usb.cpp index 138beb2..91d5d61 100644 --- a/hello_usb.cpp +++ b/hello_usb.cpp @@ -371,6 +371,29 @@ static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8 return false; } +static bool process_command(const char* input) { + if (input[0] != '/') return false; + + if (strcmp(input, "/refresh") == 0) { + printf("Command: /refresh\n"); + g_force_full_refresh = true; + send_display_update("", false); + return true; + } else if (strcmp(input, "/clear") == 0) { + printf("Command: /clear\n"); + g_entry_list.count = 0; + memset(g_entry_list.entries, 0, sizeof(g_entry_list.entries)); + g_force_full_refresh = true; + send_display_update("", false); + return true; + } else if (strcmp(input, "/wifisetup") == 0) { + printf("Command: /wifisetup (Not implemented)\n"); + return true; + } + + return false; +} + static void process_kbd_report(hid_keyboard_report_t const *report) { static hid_keyboard_report_t prev_report = { 0, 0, {0} }; @@ -403,21 +426,32 @@ static void process_kbd_report(hid_keyboard_report_t const *report) { } else if (is_enter) { printf("\n"); - // Update e-Paper (commit line) - send_display_update(g_input_buffer, true); - - // Save to last echo - strncpy(g_last_echo, g_input_buffer, sizeof(g_last_echo) - 1); - g_last_echo[sizeof(g_last_echo) - 1] = '\0'; - - // Clear buffer - g_buffer_index = 0; - g_input_buffer[0] = '\0'; - - // Update OLED - if (g_display_manager) { - g_display_manager->set_last_echo(g_last_echo); - g_display_manager->refresh("", g_last_echo); + if (process_command(g_input_buffer)) { + // Command handled, clear buffer but don't commit line + g_buffer_index = 0; + g_input_buffer[0] = '\0'; + + if (g_display_manager) { + g_display_manager->set_last_echo("Command Executed"); + g_display_manager->refresh("", "Command Executed"); + } + } else { + // Update e-Paper (commit line) + send_display_update(g_input_buffer, true); + + // Save to last echo + strncpy(g_last_echo, g_input_buffer, sizeof(g_last_echo) - 1); + g_last_echo[sizeof(g_last_echo) - 1] = '\0'; + + // Clear buffer + g_buffer_index = 0; + g_input_buffer[0] = '\0'; + + // Update OLED + if (g_display_manager) { + g_display_manager->set_last_echo(g_last_echo); + g_display_manager->refresh("", g_last_echo); + } } } else if (is_printable) { printf("%c", ch); @@ -443,12 +477,25 @@ static void process_kbd_report(hid_keyboard_report_t const *report) { // TinyUSB Callbacks //--------------------------------------------------------------------+ +static bool g_keyboard_mounted = false; + +// Invoked when device is suspended +void tuh_device_suspend_cb(uint8_t dev_addr) { + printf("Device address = %d suspended\r\n", dev_addr); +} + +// Invoked when device is resumed +void tuh_device_resume_cb(uint8_t dev_addr) { + printf("Device address = %d resumed\r\n", dev_addr); +} + void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { printf("Keyboard mounted\r\n"); + g_keyboard_mounted = true; if (g_display_manager) { g_display_manager->refresh("Keyboard Connected", nullptr); } @@ -460,8 +507,14 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); + g_keyboard_mounted = false; + + // Reset input buffer + g_buffer_index = 0; + g_input_buffer[0] = '\0'; + if (g_display_manager) { - g_display_manager->refresh("Keyboard Disconnected", nullptr); + g_display_manager->refresh("Waiting for Keyboard", nullptr); } } @@ -503,7 +556,7 @@ int main() { uint32_t now = to_ms_since_boot(get_absolute_time()); if (now - last_print > 5000) { - printf("Heartbeat: %u\n", now); + printf("Heartbeat: %u, Mounted: %d\n", now, g_keyboard_mounted); last_print = now; } } diff --git a/suspend_fix_notes.md b/suspend_fix_notes.md new file mode 100644 index 0000000..db3dde4 --- /dev/null +++ b/suspend_fix_notes.md @@ -0,0 +1,42 @@ +# TinyUSB Host Keyboard Suspend/Freeze Issues on RP2040 + +## Common Issues +1. **Device Auto-Suspend:** Some keyboards automatically enter a low-power suspend mode if they don't detect activity or if the host stops sending Start-Of-Frame (SOF) packets. +2. **Host Controller Freeze:** The RP2040 USB host controller can sometimes get into a state where it stops processing events, especially if there are signal integrity issues or if the `tuh_task()` is blocked for too long. +3. **Missing Keep-Alive:** If the host doesn't send SOFs, the device will suspend. The RP2040 host should send SOFs automatically when configured as host. + +## `tuh_task` Usage +- **Requirement:** `tuh_task()` must be called continuously and frequently in the main loop. +- **Blocking:** It should not be blocked by long delays (like `sleep_ms` or blocking display updates) in the same thread. +- **Current Code:** Your `hello_usb.cpp` calls `tuh_task()` in a tight loop, which is correct. The display updates are offloaded to Core 1, and the FIFO push is non-blocking (checked with `multicore_fifo_wready`), so Core 0 should remain responsive. + +## Potential Fixes & Debugging + +### 1. Handle Suspend/Resume Callbacks +TinyUSB provides callbacks to notify the application when a device suspends or resumes. Implementing these can help determine if the device is actually suspending. + +Add these to your `hello_usb.cpp`: + +```cpp +// Invoked when device is suspended +void tuh_device_suspend_cb(uint8_t dev_addr) { + printf("Device address = %d suspended\r\n", dev_addr); +} + +// Invoked when device is resumed +void tuh_device_resume_cb(uint8_t dev_addr) { + printf("Device address = %d resumed\r\n", dev_addr); +} +``` + +### 2. Force Resume +If the device suspends and doesn't wake up, you might need to force a resume from the host side, although usually the device initiates resume (remote wakeup) or the host keeps it awake. + +### 3. Check Power +Ensure the keyboard is receiving sufficient power. Some mechanical keyboards with LEDs draw significant current, potentially causing voltage drops that reset the USB connection or cause a freeze. + +### 4. Disable Suspend (Device Side) +Some devices have internal settings to disable sleep, but this is device-specific. + +### 5. SDK/TinyUSB Version +Ensure you are using a recent version of the Pico SDK and TinyUSB, as there have been fixes for RP2040 host mode stability.