Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Serial UART Console Improvements #9964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -2315,6 +2315,7 @@ msgstr ""
#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h
#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h
#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h
#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h
msgid "You pressed button A at start up."
msgstr ""

Expand Down
13 changes: 9 additions & 4 deletions ports/raspberrypi/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,6 @@ safe_mode_t port_init(void) {
// Reset everything into a known state before board_init.
reset_port();

#ifdef CIRCUITPY_PSRAM_CHIP_SELECT
setup_psram();
#endif

// Initialize RTC
#if CIRCUITPY_RTC
common_hal_rtc_init();
Expand All @@ -339,6 +335,15 @@ safe_mode_t port_init(void) {
hardware_alarm_claim(0);
hardware_alarm_set_callback(0, _tick_callback);

// RP2 port-specific early serial initialization for psram debug.
// The RTC must already be initialized, otherwise the serial UART
// will hang.
serial_early_init();

#ifdef CIRCUITPY_PSRAM_CHIP_SELECT
setup_psram();
#endif

// Check brownout.

#if CIRCUITPY_CYW43
Expand Down
11 changes: 11 additions & 0 deletions py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,20 @@ typedef long mp_off_t;
#define CIRCUITPY_CONSOLE_UART (1)
#ifndef CIRCUITPY_CONSOLE_UART_BAUDRATE
#define CIRCUITPY_CONSOLE_UART_BAUDRATE (115200)
#if !defined(CIRCUITPY_CONSOLE_UART_PRINTF)
#define CIRCUITPY_CONSOLE_UART_PRINTF(...) mp_printf(&console_uart_print, __VA_ARGS__)
#endif
#if !defined(CIRCUITPY_CONSOLE_UART_HEXDUMP)
#define CIRCUITPY_CONSOLE_UART_HEXDUMP(pfx, buf, len) print_hexdump(&console_uart_print, pfx, (const uint8_t *)buf, len)
#endif
#if !defined(CIRCUITPY_CONSOLE_UART_TIMESTAMP)
#define CIRCUITPY_CONSOLE_UART_TIMESTAMP (0)
#endif
#endif
#else
#define CIRCUITPY_CONSOLE_UART (0)
#define CIRCUITPY_CONSOLE_UART_PRINTF(...) (void)0
#define CIRCUITPY_CONSOLE_UART_HEXDUMP(...) (void)0
#endif

// These CIRCUITPY_xxx values should all be defined in the *.mk files as being on or off.
Expand Down
176 changes: 149 additions & 27 deletions supervisor/shared/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "py/mpconfig.h"
#include "py/mphal.h"
#include "py/mpprint.h"

#include "supervisor/shared/cpu.h"
#include "supervisor/shared/display.h"
Expand All @@ -34,7 +35,6 @@
#endif

#if CIRCUITPY_CONSOLE_UART
#include "py/mpprint.h"
#include "shared-bindings/busio/UART.h"

busio_uart_obj_t console_uart;
Expand Down Expand Up @@ -63,33 +63,94 @@ static bool _serial_console_write_disabled;
// Set to true to temporarily discard writes to the display terminal only.
static bool _serial_display_write_disabled;

// Indicates that serial console has been early initialized.
static bool _serial_console_early_inited = false;

#if CIRCUITPY_CONSOLE_UART
static void console_uart_print_strn(void *env, const char *str, size_t len) {

// All output to the console uart comes through this inner write function. It ensures that all
// lines are terminated with a "cooked" '\r\n' sequence. Lines that are already cooked are sent
// on unchanged.
static void inner_console_uart_write_cb(void *env, const char *str, size_t len) {
(void)env;
int uart_errcode;
common_hal_busio_uart_write(&console_uart, (const uint8_t *)str, len, &uart_errcode);
bool last_cr = false;
while (len > 0) {
size_t i = 0;
if (str[0] == '\n' && !last_cr) {
common_hal_busio_uart_write(&console_uart, (const uint8_t *)"\r", 1, &uart_errcode);
i = 1;
}
// Lump all characters on the next line together.
while ((last_cr || str[i] != '\n') && i < len) {
last_cr = str[i] == '\r';
i++;
}
common_hal_busio_uart_write(&console_uart, (const uint8_t *)str, i, &uart_errcode);
str = &str[i];
len -= i;
}
}

const mp_print_t console_uart_print = {NULL, console_uart_print_strn};
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
static const mp_print_t inner_console_uart_write = {NULL, inner_console_uart_write_cb};
static uint32_t console_uart_write_prev_time = 0;
static bool console_uart_write_prev_nl = true;

static inline void console_uart_write_timestamp(void) {
uint32_t now = supervisor_ticks_ms32();
uint32_t delta = now - console_uart_write_prev_time;
console_uart_write_prev_time = now;
mp_printf(&inner_console_uart_write,
"%01lu.%03lu(%01lu.%03lu): ",
now / 1000, now % 1000, delta / 1000, delta % 1000);
}
#endif

int console_uart_printf(const char *fmt, ...) {
#if CIRCUITPY_CONSOLE_UART
// Skip prints that occur before console serial is started. It's better than
// crashing.
if (common_hal_busio_uart_deinited(&console_uart)) {
return 0;
static size_t console_uart_write(const char *str, size_t len) {
// Ignore writes if console uart is not yet initialized.
if (!_serial_console_early_inited) {
return len;
}
va_list ap;
va_start(ap, fmt);
int ret = mp_vprintf(&console_uart_print, fmt, ap);
va_end(ap);
return ret;
#else
return 0;
#endif

if (!_first_write_done) {
mp_hal_delay_ms(50);
_first_write_done = true;
}

// There may be multiple newlines in the string, split at newlines.
int remaining_len = len;
while (remaining_len > 0) {
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
if (console_uart_write_prev_nl) {
console_uart_write_timestamp();
console_uart_write_prev_nl = false;
}
#endif
int print_len = 0;
while (print_len < remaining_len) {
if (str[print_len++] == '\n') {
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
console_uart_write_prev_nl = true;
#endif
break;
}
}
inner_console_uart_write_cb(NULL, str, print_len);
str += print_len;
remaining_len -= print_len;
}
return len;
}

static void console_uart_write_cb(void *env, const char *str, size_t len) {
(void)env;
console_uart_write(str, len);
}

const mp_print_t console_uart_print = {NULL, console_uart_write_cb};
#endif

MP_WEAK void board_serial_early_init(void) {
}

Expand Down Expand Up @@ -137,9 +198,14 @@ MP_WEAK void port_serial_write_substring(const char *text, uint32_t length) {
}

void serial_early_init(void) {
// Set up console UART, if enabled.
// Ignore duplicate calls to initialize allowing port-specific code to
// call this function early.
if (_serial_console_early_inited) {
return;
}

#if CIRCUITPY_CONSOLE_UART
// Set up console UART, if enabled.
console_uart.base.type = &busio_uart_type;

const mcu_pin_obj_t *console_rx = MP_OBJ_TO_PTR(CIRCUITPY_CONSOLE_UART_RX);
Expand All @@ -150,12 +216,15 @@ void serial_early_init(void) {
console_uart_rx_buf, true);
common_hal_busio_uart_never_reset(&console_uart);

// Do an initial print so that we can confirm the serial output is working.
console_uart_printf("Serial console setup\r\n");
#endif

board_serial_early_init();
port_serial_early_init();

_serial_console_early_inited = true;

// Do an initial print so that we can confirm the serial output is working.
CIRCUITPY_CONSOLE_UART_PRINTF("Serial console setup\n");
}

void serial_init(void) {
Expand Down Expand Up @@ -347,12 +416,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) {
#endif

#if CIRCUITPY_CONSOLE_UART
if (!_first_write_done) {
mp_hal_delay_ms(50);
_first_write_done = true;
}
int uart_errcode;
length_sent = common_hal_busio_uart_write(&console_uart, (const uint8_t *)text, length, &uart_errcode);
length_sent = console_uart_write(text, length);
#endif

#if CIRCUITPY_SERIAL_BLE
Expand Down Expand Up @@ -409,3 +473,61 @@ bool serial_display_write_disable(bool disabled) {
_serial_display_write_disabled = disabled;
return now;
}

// A general purpose hex/ascii dump function for arbitrary area of memory.
void print_hexdump(const mp_print_t *printer, const char *prefix, const uint8_t *buf, size_t len) {
size_t i;
for (i = 0; i < len; ++i) {
// print hex digit
if (i % 32 == 0) {
mp_printf(printer, "%s0x%04x:", prefix, i);
}
if (i % 32 == 16) {
mp_printf(printer, " : ");
} else if (i % 4 == 0) {
mp_printf(printer, " ");
}
mp_printf(printer, "%02x", buf[i]);
// print ascii chars for this line
if (i % 32 == 31) {
size_t k = i - 31;
mp_printf(printer, " : ");
for (size_t j = 0; j < 32; ++j) {
if (j == 16) {
mp_printf(printer, " ");
}
if (buf[k + j] >= 32 && buf[k + j] < 127) {
mp_printf(printer, "%c", buf[k + j]);
} else {
mp_printf(printer, ".");
}
}
mp_printf(printer, "\n");
}
}
if (i % 32 != 0) {
// For a final line of less than 32 bytes, pad with spaces
i -= i % 32;
for (size_t j = len % 32; j < 32; ++j) {
if (j % 32 == 16) {
mp_printf(printer, " ");
} else if (j % 4 == 0) {
mp_printf(printer, " ");
}
mp_printf(printer, " ");
}
// Print ascii chars for the last line fragment
mp_printf(printer, " : ");
for (size_t j = 0; j < len % 32; ++j) {
if (j == 16) {
mp_printf(printer, " ");
}
if (buf[i + j] >= 32 && buf[i + j] < 127) {
mp_printf(printer, "%c", buf[i + j]);
} else {
mp_printf(printer, ".");
}
}
mp_printf(printer, "\n");
}
}
5 changes: 4 additions & 1 deletion supervisor/shared/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <stdio.h>

#include "py/mpconfig.h"
#include "py/mpprint.h"

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
#include "py/misc.h"
Expand Down Expand Up @@ -47,4 +48,6 @@ char board_serial_read(void);
uint32_t board_serial_bytes_available(void);
void board_serial_write_substring(const char *text, uint32_t length);

int console_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
extern const mp_print_t console_uart_print;

void print_hexdump(const mp_print_t *printer, const char *prefix, const uint8_t *buf, size_t len);