From 9f46367e0f7542a1a523cbde1532314737e4c31c Mon Sep 17 00:00:00 2001 From: James Aguilar Date: Thu, 11 Dec 2025 16:37:46 -0700 Subject: [PATCH] pbdrv/uart_debug_first_port: Log on panic. It's helpful when you crash to see what happens right before you crash. For example, if you add a log message "about to dereference sketchy pointer" and then you get a segfault, you'd love to know whether that message occurred. This change makes it so that at least on EV3, we will. This also adds "pb_log" as an alias for pbdrv_uart_debug_printf. Usually, platforms make it easy to log debug messages, and we should be no different. C.f. `ESP_LOGI`, Zephyr's `LOG_ERR`, glog's `LOG(WARNING)` etc. Tested by adding the following code to pbdrv_init. ``` pb_log("test\n"); lwrb_t* rb = (lwrb_t*)0x1281441490; pb_log("%p\n", lwrb_get_free(rb)); ``` Before this, the "test" would not appear before the panic. After, it does. If a panic occurs while some messages are pending in the uart send state, some bytes may be duplicated on the log. --- lib/pbio/drv/uart/uart_debug_first_port.c | 12 ++++++++++++ lib/pbio/drv/uart/uart_debug_first_port.h | 12 ++++++++++++ lib/pbio/platform/ev3/platform.c | 7 +++++++ 3 files changed, 31 insertions(+) diff --git a/lib/pbio/drv/uart/uart_debug_first_port.c b/lib/pbio/drv/uart/uart_debug_first_port.c index 95fc1562b..b2af38571 100644 --- a/lib/pbio/drv/uart/uart_debug_first_port.c +++ b/lib/pbio/drv/uart/uart_debug_first_port.c @@ -22,6 +22,18 @@ static lwrb_t ring_buffer; static pbdrv_uart_dev_t *debug_uart = NULL; +int pbdrv_uart_debug_next_char(void) { + if (!lwrb_is_ready(&ring_buffer)) { + return -1; + } + uint8_t c; + if (lwrb_read(&ring_buffer, &c, 1) == 1) { + return c; + } else { + return -1; + } +} + /** * Formats and stores a string in the UART debug ring buffer. * diff --git a/lib/pbio/drv/uart/uart_debug_first_port.h b/lib/pbio/drv/uart/uart_debug_first_port.h index 7e4d0701e..e251b7f75 100644 --- a/lib/pbio/drv/uart/uart_debug_first_port.h +++ b/lib/pbio/drv/uart/uart_debug_first_port.h @@ -19,6 +19,11 @@ bool pbdrv_uart_debug_is_done(void); void pbdrv_uart_debug_init(void); +// Returns the next character that should be sent to the UART, or -1 if there +// are not pending log messages. Used only by the panic handler to flush unsent +// data before reboot. +int pbdrv_uart_debug_next_char(void); + #else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT #define pbdrv_uart_debug_printf(...) @@ -28,6 +33,13 @@ void pbdrv_uart_debug_init(void); #define pbdrv_uart_debug_init() +static inline int pbdrv_uart_debug_next_char(void) { + return -1; +} + #endif // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT +// Convenient shorthand for pbdrv_uart_debug_printf. +#define pbdrv_dbg(...) pbdrv_uart_debug_printf(__VA_ARGS__) + #endif // _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_ diff --git a/lib/pbio/platform/ev3/platform.c b/lib/pbio/platform/ev3/platform.c index cf717fd43..3c64bebc7 100644 --- a/lib/pbio/platform/ev3/platform.c +++ b/lib/pbio/platform/ev3/platform.c @@ -81,6 +81,7 @@ #include "../../drv/pwm/pwm_ev3.h" #include "../../drv/reset/reset_ev3.h" #include "../../drv/uart/uart_ev3.h" +#include "../../drv/uart/uart_debug_first_port.h" enum { LED_DEV_0_STATUS, @@ -443,6 +444,12 @@ void ev3_panic_handler(int except_type, ev3_panic_ctx *except_data) { UARTConfigSetExpClk(SOC_UART_1_REGS, SOC_UART_1_MODULE_FREQ, 115200, UART_WORDL_8BITS, UART_OVER_SAMP_RATE_13); UARTFIFOEnable(SOC_UART_1_REGS); + // Drain whatever is still left in the UART debug FIFO. + int c; + while ((c = pbdrv_uart_debug_next_char()) != -1) { + UARTCharPut(SOC_UART_1_REGS, (uint8_t)c); + } + panic_puts("********************************************************************************\r\n"); panic_puts("* Pybricks on EV3 Panic *\r\n"); panic_puts("********************************************************************************\r\n");