diff --git a/common/omv_common.h b/common/omv_common.h index 472b54e98..6707e8639 100644 --- a/common/omv_common.h +++ b/common/omv_common.h @@ -49,6 +49,12 @@ #define OMV_ALIGN_DOWN(x, alignment) \ ((uintptr_t)(x) & ~((uintptr_t)(alignment) - 1)) +#define check_timeout_ms(start_ms, timeout) \ + ((mp_hal_ticks_ms() - start_ms) > timeout) + +#define check_timeout_us(start_us, timeout) \ + ((mp_hal_ticks_us() - start_us) > timeout) + #ifdef OMV_DEBUG_PRINTF #define debug_printf(fmt, ...) \ do { printf("%s(): " fmt, __func__, ##__VA_ARGS__);} while (0) diff --git a/common/tinyusb_debug.c b/common/tinyusb_debug.c index 7217f218d..4cfc3585c 100644 --- a/common/tinyusb_debug.c +++ b/common/tinyusb_debug.c @@ -25,7 +25,8 @@ */ #include "omv_boardconfig.h" -#if (OMV_TUSBDBG_ENABLE == 1) + +#if OMV_TUSBDBG_ENABLE #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" @@ -36,159 +37,175 @@ #include "usbdbg.h" #include "tinyusb_debug.h" #include "omv_common.h" +#include "cmsis_gcc.h" -#define USBDBG_BAUDRATE_SLOW (921600) -#define USBDBG_BAUDRATE_FAST (12000000) +#define USBDBG_DATA_TIMEOUT (1000) #define DEBUG_EP_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -void NORETURN __fatal_error(const char *msg); -static mp_sched_node_t tusb_debug_node; +typedef struct { + uint32_t timestamp; + uint8_t opcode; + uint32_t length; + bool debug_mode; + mp_sched_node_t sched_node; + ringbuf_t ringbuf; + uint8_t rawbuf[OMV_TUSBDBG_BUFFER]; +} debug_context_t; -typedef struct __attribute__((packed)) { - uint8_t cmd; - uint8_t request; - uint32_t xfer_length; -} -usbdbg_cmd_t; - -static uint8_t tx_array[OMV_TUSBDBG_BUFFER]; -static ringbuf_t tx_ringbuf = { tx_array, sizeof(tx_array) }; -static volatile bool tinyusb_debug_mode = false; +static debug_context_t ctx; uint32_t usb_cdc_buf_len() { - return ringbuf_avail(&tx_ringbuf); + return ringbuf_avail(&ctx.ringbuf); } uint32_t usb_cdc_get_buf(uint8_t *buf, uint32_t len) { // Read all of the request bytes. - if (ringbuf_get_bytes(&tx_ringbuf, buf, len) == 0) { + if (ringbuf_get_bytes(&ctx.ringbuf, buf, len) == 0) { return len; } + // Try to read as much data as possible. uint32_t bytes = 0; for (; bytes < len; bytes++) { - int c = ringbuf_get(&tx_ringbuf); + int c = ringbuf_get(&ctx.ringbuf); if (c == -1) { break; } buf[bytes] = c; } + return bytes; } void usb_cdc_reset_buffers(void) { - tx_ringbuf.iget = 0; - tx_ringbuf.iput = 0; + ctx.ringbuf.iget = 0; + ctx.ringbuf.iput = 0; } void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *coding) { - tx_ringbuf.iget = 0; - tx_ringbuf.iput = 0; + usb_cdc_reset_buffers(); - if (0) { - #if defined(MICROPY_BOARD_ENTER_BOOTLOADER) - } else if (coding->bit_rate == 1200) { + #if defined(MICROPY_BOARD_ENTER_BOOTLOADER) + if (coding->bit_rate == 1200) { MICROPY_BOARD_ENTER_BOOTLOADER(0, 0); - #endif - } else if (coding->bit_rate == USBDBG_BAUDRATE_SLOW || - coding->bit_rate == USBDBG_BAUDRATE_FAST) { - tinyusb_debug_mode = true; - } else { - tinyusb_debug_mode = false; } + #endif + + ctx.debug_mode = (coding->bit_rate == USBDBG_BAUDRATE_SLOW || + coding->bit_rate == USBDBG_BAUDRATE_FAST); } -bool tinyusb_debug_enabled(void) { - return tinyusb_debug_mode; -} - -extern void __real_mp_usbd_task(void); +// Wrapped MicroPython functions. void __wrap_mp_usbd_task(void) { + extern void __real_mp_usbd_task(void); + if (!tinyusb_debug_enabled()) { __real_mp_usbd_task(); } } -extern void __real_tud_cdc_rx_cb(uint8_t itf); void __wrap_tud_cdc_rx_cb(uint8_t itf) { + extern void __real_tud_cdc_rx_cb(uint8_t itf); + if (!tinyusb_debug_enabled()) { __real_tud_cdc_rx_cb(itf); } } -extern uintptr_t __real_mp_hal_stdio_poll(uintptr_t poll_flags); uintptr_t __wrap_mp_hal_stdio_poll(uintptr_t poll_flags) { + extern uintptr_t __real_mp_hal_stdio_poll(uintptr_t poll_flags); + if (!tinyusb_debug_enabled()) { return __real_mp_hal_stdio_poll(poll_flags); } return 0; } -extern mp_uint_t __real_mp_hal_stdout_tx_strn(const char *str, mp_uint_t len); mp_uint_t __wrap_mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { - if (tinyusb_debug_enabled()) { - if (tud_cdc_connected()) { - for (int i = 0; i < len; i++) { - // The ring buffer overflows occasionally, espcially when using a slow poll - // rate and fast print rate. When this happens, reset the buffer and start - // over, if this string fits entirely in the buffer. This helps the ring buffer - // self-recover from broken strings. - if (ringbuf_put(&tx_ringbuf, str[i]) == -1 && len <= tx_ringbuf.size) { - tx_ringbuf.iget = 0; - tx_ringbuf.iput = 0; - ringbuf_put(&tx_ringbuf, str[i]); - } + extern mp_uint_t __real_mp_hal_stdout_tx_strn(const char *str, mp_uint_t len); + + if (!tinyusb_debug_enabled()) { + return __real_mp_hal_stdout_tx_strn(str, len); + } else if (tud_cdc_connected()) { + for (int i = 0; i < len; i++) { + // On overflow, reset the ring buffer, if this string fits + // entirely in the buffer, to recover from broken strings. + if (ringbuf_put(&ctx.ringbuf, str[i]) == -1 && len <= ctx.ringbuf.size) { + usb_cdc_reset_buffers(); + ringbuf_put(&ctx.ringbuf, str[i]); } } - return len; - } else { - return __real_mp_hal_stdout_tx_strn(str, len); } + return len; +} + +int tinyusb_debug_init(void) { + ctx.opcode = 0; + ctx.length = 0; + if (!ctx.ringbuf.buf) { + ctx.ringbuf = (ringbuf_t) { ctx.rawbuf, sizeof(ctx.rawbuf), 0, 0 }; + } + return 0; +} + +bool tinyusb_debug_enabled(void) { + return ctx.debug_mode; } void tinyusb_debug_task(mp_sched_node_t *node) { tud_task_ext(0, false); - if (!tinyusb_debug_enabled() || !tud_cdc_connected() || tud_cdc_available() < 6) { + if (!tinyusb_debug_enabled() || !tud_cdc_connected()) { return; } - usbdbg_cmd_t cmd; - tud_cdc_read(&cmd, sizeof(cmd)); + if (!ctx.length && tud_cdc_available() >= USBDBG_HEADER_SIZE) { + uint8_t cmdbuf[USBDBG_HEADER_SIZE]; + tud_cdc_read(cmdbuf, sizeof(cmdbuf)); - if (cmd.cmd != 0x30) { - // TODO: Try to recover from this state but for now, call __fatal_error. - __fatal_error("Invalid USB CMD received."); + if (cmdbuf[0] == 0x30) { + ctx.opcode = cmdbuf[1]; + ctx.length = *((uint32_t*)(cmdbuf+2)); + usbdbg_control(NULL, ctx.opcode, ctx.length); + } + + if (ctx.length > 0) { + ctx.timestamp = mp_hal_ticks_ms(); + } } - uint8_t request = cmd.request; - uint32_t xfer_length = cmd.xfer_length; - usbdbg_control(NULL, request, xfer_length); + while (ctx.length) { + uint32_t bytes = 0; - while (xfer_length) { - // && tud_cdc_connected()) if (tud_task_event_ready()) { tud_task_ext(0, false); } - if (request & 0x80) { - // Device-to-host data phase - int size = OMV_MIN(xfer_length, tud_cdc_write_available()); - if (size) { - xfer_length -= size; - usbdbg_data_in(size, tud_cdc_write); + + if (ctx.opcode & 0x80) { + bytes = OMV_MIN(ctx.length, tud_cdc_write_available()); + if (bytes) { + ctx.length -= bytes; + usbdbg_data_in(bytes, tud_cdc_write); } - if (size > 0 && size < DEBUG_EP_SIZE) { + if (bytes > 0 && bytes < DEBUG_EP_SIZE) { tud_cdc_write_flush(); } } else { - // Host-to-device data phase - int size = OMV_MIN(xfer_length, tud_cdc_available()); - if (size) { - xfer_length -= size; - usbdbg_data_out(size, tud_cdc_read); + bytes = OMV_MIN(ctx.length, tud_cdc_available()); + if (bytes) { + ctx.length -= bytes; + usbdbg_data_out(bytes, tud_cdc_read); } } - } + + if (bytes) { + ctx.timestamp = mp_hal_ticks_ms(); + } else if (__get_PRIMASK() & 1) { + break; + } else if (check_timeout_ms(ctx.timestamp, USBDBG_DATA_TIMEOUT)) { + tinyusb_debug_init(); + } + } } // For the mimxrt, and nrf ports this replaces the weak USB IRQ handlers. @@ -197,7 +214,7 @@ void OMV_USB1_IRQ_HANDLER(void) { dcd_int_handler(0); // If there are any event to process, schedule a call to cdc loop. if (tud_task_event_ready()) { - mp_sched_schedule_node(&tusb_debug_node, tinyusb_debug_task); + mp_sched_schedule_node(&ctx.sched_node, tinyusb_debug_task); } } @@ -206,7 +223,7 @@ void OMV_USB2_IRQ_HANDLER(void) { dcd_int_handler(1); // If there are any event to process, schedule a call to cdc loop. if (tud_task_event_ready()) { - mp_sched_schedule_node(&tusb_debug_node, tinyusb_debug_task); + mp_sched_schedule_node(&ctx.sched_node, tinyusb_debug_task); } } #endif diff --git a/common/tinyusb_debug.h b/common/tinyusb_debug.h index cac290553..d8c92a966 100644 --- a/common/tinyusb_debug.h +++ b/common/tinyusb_debug.h @@ -27,5 +27,4 @@ void USBD_IRQHandler(void); int tinyusb_debug_init(void); bool tinyusb_debug_enabled(void); -void tinyusb_debug_tx_strn(const char *str, mp_uint_t len); #endif // __TUSBDBG_H__ diff --git a/common/usbdbg.c b/common/usbdbg.c index 607ad19ae..05dd303a2 100644 --- a/common/usbdbg.c +++ b/common/usbdbg.c @@ -39,6 +39,7 @@ #endif #include "framebuffer.h" #include "usbdbg.h" +#include "tinyusb_debug.h" #include "omv_boardconfig.h" #include "py_image.h" @@ -62,8 +63,10 @@ void usbdbg_init() { script_ready = false; script_running = false; irq_enabled = false; - vstr_init(&script_buf, 32); + #if OMV_TUSBDBG_ENABLE + tinyusb_debug_init(); + #endif } bool usbdbg_script_ready() { @@ -113,16 +116,6 @@ bool usbdbg_get_irq_enabled() { return irq_enabled; } -uint32_t ticks_diff_ms(uint32_t start_ms) { - uint32_t current_ms = mp_hal_ticks_ms(); - if (current_ms >= start_ms) { - return current_ms - start_ms; - } else { - // Handle wraparound - return (UINT32_MAX - start_ms) + current_ms + 1; - } -} - void usbdbg_data_in(uint32_t size, usbdbg_write_callback_t write_callback) { switch (cmd) { case USBDBG_FW_VERSION: { @@ -248,7 +241,7 @@ void usbdbg_data_in(uint32_t size, usbdbg_write_callback_t write_callback) { } // Limit the frames sent over USB to 20Hz. - if (ticks_diff_ms(last_update_ms) > 50 && + if (check_timeout_ms(last_update_ms, 50) && mutex_try_lock_fair(&JPEG_FB()->lock, MUTEX_TID_IDE)) { // If header size == 0 frame is not ready if (JPEG_FB()->size == 0) { @@ -317,93 +310,6 @@ void usbdbg_data_out(uint32_t size, usbdbg_read_callback_t read_callback) { } break; - case USBDBG_TEMPLATE_SAVE: { - #if defined(IMLIB_ENABLE_IMAGE_FILE_IO) - image_t image; - framebuffer_t *fb = framebuffer_get(0); - - framebuffer_init_image(fb, &image); - - size = MIN(128, size); - char buffer[size]; - read_callback(buffer, size); - buffer[size - 1] = 0; - - rectangle_t *roi = (rectangle_t *) buffer; - char *path = (char *) buffer + sizeof(rectangle_t); - - imlib_save_image(&image, path, roi, 50); - #endif //IMLIB_ENABLE_IMAGE_FILE_IO - break; - } - - case USBDBG_DESCRIPTOR_SAVE: { - #if defined(IMLIB_ENABLE_IMAGE_FILE_IO) \ - && defined(IMLIB_ENABLE_KEYPOINTS) - image_t image; - framebuffer_t *fb = framebuffer_get(0); - - framebuffer_init_image(fb, &image); - - size = MIN(128, size); - char buffer[size]; - read_callback(buffer, size); - buffer[size - 1] = 0; - - rectangle_t *roi = (rectangle_t *) buffer; - char *path = (char *) buffer + sizeof(rectangle_t); - - py_image_descriptor_from_roi(&image, path, roi); - #endif //IMLIB_ENABLE_IMAGE_FILE_IO && IMLIB_ENABLE_KEYPOINTS - cmd = USBDBG_NONE; - break; - } - - case USBDBG_ATTR_WRITE: { - #if MICROPY_PY_CSI - struct { - int32_t name; - int32_t value; - } attr; - - omv_csi_t *csi = omv_csi_get(-1); - - read_callback(&attr, sizeof(attr)); - - switch (attr.name) { - case OMV_CSI_ATTR_CONTRAST: - omv_csi_set_contrast(csi, attr.value); - break; - case OMV_CSI_ATTR_BRIGHTNESS: - omv_csi_set_brightness(csi, attr.value); - break; - case OMV_CSI_ATTR_SATURATION: - omv_csi_set_saturation(csi, attr.value); - break; - case OMV_CSI_ATTR_GAINCEILING: - omv_csi_set_gainceiling(csi, attr.value); - break; - default: - break; - } - #endif - cmd = USBDBG_NONE; - break; - } - - case USBDBG_SET_TIME: { - // TODO implement - uint8_t buffer[32]; - read_callback(&buffer, sizeof(buffer)); - cmd = USBDBG_NONE; - break; - } - - case USBDBG_TX_INPUT: { - // TODO implement - cmd = USBDBG_NONE; - break; - } default: /* error */ break; } @@ -413,29 +319,23 @@ void usbdbg_control(void *buffer, uint8_t request, uint32_t size) { cmd = (enum usbdbg_cmd) request; switch (cmd) { case USBDBG_FW_VERSION: - xfer_offs = 0; - xfer_size = size; - break; - case USBDBG_FRAME_SIZE: - xfer_offs = 0; - xfer_size = size; - break; - case USBDBG_FRAME_DUMP: - xfer_offs = 0; - xfer_size = size; - break; - case USBDBG_ARCH_STR: + case USBDBG_FB_ENABLE: + case USBDBG_TX_BUF: + case USBDBG_TX_BUF_LEN: + case USBDBG_SENSOR_ID: + case USBDBG_GET_STATE: xfer_offs = 0; xfer_size = size; break; + case USBDBG_SCRIPT_RUNNING: + vstr_reset(&script_buf); case USBDBG_SCRIPT_EXEC: xfer_offs = 0; xfer_size = size; - vstr_reset(&script_buf); break; case USBDBG_SCRIPT_STOP: @@ -449,28 +349,6 @@ void usbdbg_control(void *buffer, uint8_t request, uint32_t size) { cmd = USBDBG_NONE; break; - case USBDBG_SCRIPT_SAVE: - // TODO: save running script - cmd = USBDBG_NONE; - break; - - case USBDBG_SCRIPT_RUNNING: - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_TEMPLATE_SAVE: - case USBDBG_DESCRIPTOR_SAVE: - /* save template */ - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_ATTR_WRITE: - xfer_offs = 0; - xfer_size = size; - break; - case USBDBG_SYS_RESET: #if defined(OMV_BOARD_RESET) OMV_BOARD_RESET(); @@ -488,38 +366,6 @@ void usbdbg_control(void *buffer, uint8_t request, uint32_t size) { break; } - case USBDBG_FB_ENABLE: { - xfer_offs = 0; - xfer_size = size; - break; - } - - case USBDBG_TX_BUF: - case USBDBG_TX_BUF_LEN: - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_SENSOR_ID: - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_SET_TIME: - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_TX_INPUT: - xfer_offs = 0; - xfer_size = size; - break; - - case USBDBG_GET_STATE: - xfer_offs = 0; - xfer_size = size; - break; - default: /* error */ cmd = USBDBG_NONE; break; diff --git a/common/usbdbg.h b/common/usbdbg.h index f6644cc91..6d4fd325a 100644 --- a/common/usbdbg.h +++ b/common/usbdbg.h @@ -35,6 +35,7 @@ #define USBDBG_BAUDRATE_SLOW (921600) #define USBDBG_BAUDRATE_FAST (12000000) +#define USBDBG_HEADER_SIZE (6) /** * To add a new debugging command, increment the last command value used. @@ -52,20 +53,13 @@ enum usbdbg_cmd { USBDBG_ARCH_STR = 0x83, USBDBG_SCRIPT_EXEC = 0x05, USBDBG_SCRIPT_STOP = 0x06, - USBDBG_SCRIPT_SAVE = 0x07, USBDBG_SCRIPT_RUNNING = 0x87, - USBDBG_TEMPLATE_SAVE = 0x08, - USBDBG_DESCRIPTOR_SAVE = 0x09, - USBDBG_ATTR_READ = 0x8A, - USBDBG_ATTR_WRITE = 0x0B, USBDBG_SYS_RESET = 0x0C, USBDBG_SYS_RESET_TO_BL = 0x0E, USBDBG_FB_ENABLE = 0x0D, USBDBG_TX_BUF_LEN = 0x8E, USBDBG_TX_BUF = 0x8F, USBDBG_SENSOR_ID = 0x90, - USBDBG_TX_INPUT = 0x11, - USBDBG_SET_TIME = 0x12, USBDBG_GET_STATE = 0x93, };