10000 Serial UART console bug fixes and enhancements. · hathach/circuitpython@038c92a · GitHub
[go: up one dir, main page]

Skip to content

Commit 038c92a

Browse files
committed
Serial UART console bug fixes and enhancements.
1 parent db4f059 commit 038c92a

File tree

5 files changed

+175
-31
lines changed

5 files changed

+175
-31
lines changed

locale/circuitpython.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,10 @@ msgstr ""
975975
msgid "Failed to allocate %q buffer"
976976
msgstr ""
977977

978+
#: shared-bindings/ramlog/ramlog.c
979+
msgid "Failed to allocate RAM log buffer"
980+
msgstr ""
981+
978982
#: ports/espressif/common-hal/wifi/__init__.c
979983
msgid "Failed to allocate Wifi memory"
980984
msgstr ""

ports/raspberrypi/supervisor/port.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,6 @@ safe_mode_t port_init(void) {
326326
// Reset everything into a known state before board_init.
327327
reset_port();
328328

329-
#ifdef CIRCUITPY_PSRAM_CHIP_SELECT
330-
setup_psram();
331-
#endif
332-
333329
// Initialize RTC
334330
#if CIRCUITPY_RTC
335331
common_hal_rtc_init();
@@ -339,6 +335,15 @@ safe_mode_t port_init(void) {
339335
hardware_alarm_claim(0);
340336
hardware_alarm_set_callback(0, _tick_callback);
341337

338+
// RP2 port-specific early serial initialization for psram debug.
339+
// The RTC must already be initialized, otherwise the serial UART
340+
// will hang.
341+
serial_early_init();
342+
343+
#ifdef CIRCUITPY_PSRAM_CHIP_SELECT
344+
setup_psram();
345+
#endif
346+
342347
// Check brownout.
343348

344349
#if CIRCUITPY_CYW43

py/circuitpy_mpconfig.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,20 @@ typedef long mp_off_t;
328328
#define CIRCUITPY_CONSOLE_UART (1)
329329
#ifndef CIRCUITPY_CONSOLE_UART_BAUDRATE
330330
#define CIRCUITPY_CONSOLE_UART_BAUDRATE (115200)
331+
#if !defined(CIRCUITPY_CONSOLE_UART_PRINTF)
332+
#define CIRCUITPY_CONSOLE_UART_PRINTF(...) mp_printf(&console_uart_print, __VA_ARGS__)
333+
#endif
334+
#if !defined(CIRCUITPY_CONSOLE_UART_HEXDUMP)
335+
#define CIRCUITPY_CONSOLE_UART_HEXDUMP(pfx, buf, len) print_hexdump(&console_uart_print, pfx, (const uint8_t *)buf, len)
336+
#endif
337+
#if !defined(CIRCUITPY_CONSOLE_UART_TIMESTAMP)
338+
#define CIRCUITPY_CONSOLE_UART_TIMESTAMP (0)
339+
#endif
331340
#endif
332341
#else
333342
#define CIRCUITPY_CONSOLE_UART (0)
343+
#define CIRCUITPY_CONSOLE_UART_PRINTF(...) (void)0
344+
#define CIRCUITPY_CONSOLE_UART_HEXDUMP(...) (void)0
334345
#endif
335346

336347
// These CIRCUITPY_xxx values should all be defined in the *.mk files as being on or off.

supervisor/shared/serial.c

Lines changed: 148 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,33 +63,94 @@ static bool _serial_console_write_disabled;
6363
// Set to true to temporarily discard writes to the display terminal only.
6464
static bool _serial_display_write_disabled;
6565

66+
// Indicates that serial console has been early initialized.
67+
static bool _serial_console_early_inited = false;
68+
6669
#if CIRCUITPY_CONSOLE_UART
67-
static void console_uart_print_strn(void *env, const char *str, size_t len) {
70+
71+
// All output to the console uart comes through this inner write function. It ensures that all
72+
// lines are terminated with a "cooked" '\r\n' sequence. Lines that are already cooked are sent
73+
// on unchanged.
74+
static void inner_console_uart_write_cb(void *env, const char *str, size_t len) {
6875
(void)env;
6976
int uart_errcode;
70-
common_hal_busio_uart_write(&console_uart, (const uint8_t *)str, len, &uart_errcode);
77+
bool last_cr = false;
78+
while (len > 0) {
79+
size_t i = 0;
80+
if (str[0] == '\n' && !last_cr) {
81+
common_hal_busio_uart_write(&console_uart, (const uint8_t *)"\r", 1, &uart_errcode);
82+
i = 1;
83+
}
84+
// Lump all characters on the next line together.
85+
while ((last_cr || str[i] != '\n') && i < len) {
86+
last_cr = str[i] == '\r';
87+
i++;
88+
}
89+
common_hal_busio_uart_write(&console_uart, (const uint8_t *)str, i, &uart_errcode);
90+
str = &str[i];
91+
len -= i;
92+
}
7193
}
7294

73-
const mp_print_t console_uart_print = {NULL, console_uart_print_strn};
95+
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
96+
static const mp_print_t inner_console_uart_write = {NULL, inner_console_uart_write_cb};
97+
static uint32_t console_uart_write_prev_time = 0;
98+
static bool console_uart_write_prev_nl = true;
99+
100+
static inline void console_uart_write_timestamp(void) {
101+
uint32_t now = supervisor_ticks_ms32();
102+
uint32_t delta = now - console_uart_write_prev_time;
103+
console_uart_write_prev_time = now;
104+
mp_printf(&inner_console_uart_write,
105+
"%01lu.%03lu(%01lu.%03lu): ",
106+
now / 1000, now % 1000, delta / 1000, delta % 1000);
107+
}
74108
#endif
75109

76-
int console_uart_printf(const char *fmt, ...) {
77-
#if CIRCUITPY_CONSOLE_UART
78-
// Skip prints that occur before console serial is started. It's better than
79-
// crashing.
80-
if (common_hal_busio_uart_deinited(&console_uart)) {
81-
return 0;
110+
static size_t console_uart_write(const char *str, size_t len) {
111+
// Ignore writes if console uart is not yet initialized.
112+
if (!_serial_console_early_inited) {
113+
return len;
82114
}
83-
va_list ap;
84-
va_start(ap, fmt);
85-
int ret = mp_vprintf(&console_uart_print, fmt, ap);
86-
va_end(ap);
87-
return ret;
88-
#else
89-
return 0;
90-
#endif
115+
116+
if (!_first_write_done) {
117+
mp_hal_delay_ms(50);
118+
_first_write_done = true;
119+
}
120+
121+
// There may be multiple newlines in the string, split at newlines.
122+
int remaining_len = len;
123+
while (remaining_len > 0) {
124+
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
125+
if (console_uart_write_prev_nl) {
126+
console_uart_write_timestamp();
127+
console_uart_write_prev_nl = false;
128+
}
129+
#endif
130+
int print_len = 0;
131+
while (print_len < remaining_len) {
132+
if (str[print_len++] == '\n') {
133+
#if CIRCUITPY_CONSOLE_UART_TIMESTAMP
134+
console_uart_write_prev_nl = true;
135+
#endif
136+
break;
137+
}
138+
}
139+
inner_console_uart_write_cb(NULL, str, print_len);
140+
str += print_len;
141+
remaining_len -= print_len;
142+
}
143+
return len;
144+
}
145+
146+
static void console_uart_write_cb(void *env, const char *str, size_t len) {
147+
(void)env;
148+
console_uart_write(str, len);
91149
}
92150

151+
const mp_print_t console_uart_print = {NULL, console_uart_write_cb};
152+
#endif
153+
93154
MP_WEAK void board_serial_early_init(void) {
94155
}
95156

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

139200
void serial_early_init(void) {
140-
// Set up console UART, if enabled.
201+
// Ignore duplicate calls to initialize allowing port-specific code to
202+
// call this function early.
203+
if (_serial_console_early_inited) {
204+
return;
205+
}
141206

142207
#if CIRCUITPY_CONSOLE_UART
208+
// Set up console UART, if enabled.
143209
console_uart.base.type = &busio_uart_type;
144210

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

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

157221
board_serial_early_init();
158222
port_serial_early_init();
223+
224+
_serial_console_early_inited = true;
225+
226+
// Do an initial print so that we can confirm the serial output is working.
227+
CIRCUITPY_CONSOLE_UART_PRINTF("Serial console setup\n");
159228
}
160229

161230
void serial_init(void) {
@@ -347,12 +416,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) {
347416
#endif
348417

349418
#if CIRCUITPY_CONSOLE_UART
350-
if (!_first_write_done) {
351-
mp_hal_delay_ms(50);
352-
_first_write_done = true;
353-
}
354-
int uart_errcode;
355-
length_sent = common_hal_busio_uart_write(&console_uart, (const uint8_t *)text, length, &uart_errcode);
419+
length_sent = console_uart_write(text, length);
356420
#endif
357421

358422
#if CIRCUITPY_SERIAL_BLE
@@ -409,3 +473,61 @@ bool serial_display_write_disable(bool disabled) {
409473
_serial_display_write_disabled = disabled;
410474
return now;
411475
}
476+
477+
// A general purpose hex/ascii dump function for arbitrary area of memory.
478+
void print_hexdump(const mp_print_t *printer, const char *prefix, const uint8_t *buf, size_t len) {
479+
size_t i;
480+
for (i = 0; i < len; ++i) {
481+
// print hex digit
482+
if (i % 32 == 0) {
483+
mp_printf(printer, "%s0x%04x:", prefix, i);
484+
}
485+
if (i % 32 == 16) {
486+
mp_printf(printer, " : ");
487+
} else if (i % 4 == 0) {
488+
mp_printf(printer, " ");
489+
}
490+
mp_printf(printer, "%02x", buf[i]);
491+
// print ascii chars for this line
492+
if (i % 32 == 31) {
493+
size_t k = i - 31;
494+
mp_printf(printer, " : ");
495+
for (size_t j = 0; j < 32; ++j) {
496+
if (j == 16) {
497+
mp_printf(printer, " ");
498+
}
499+
if (buf[k + j] >= 32 && buf[k + j] < 127) {
500+
mp_printf(printer, "%c", buf[k + j]);
501+
} else {
502+
mp_printf(printer, ".");
503+
}
504+
}
10000 505+
mp_printf(printer, "\n");
506+
}
507+
}
508+
if (i % 32 != 0) {
509+
// For a final line of less than 32 bytes, pad with spaces
510+
i -= i % 32;
511+
for (size_t j = len % 32; j < 32; ++j) {
512+
if (j % 32 == 16) {
513+
mp_printf(printer, " ");
514+
} else if (j % 4 == 0) {
515+
mp_printf(printer, " ");
516+
}
517+
mp_printf(printer, " ");
518+
}
519+
// Print ascii chars for the last line fragment
520+
mp_printf(printer, " : ");
521+
for (size_t j = 0; j < len % 32; ++j) {
522+
if (j == 16) {
523+
mp_printf(printer, " ");
524+
}
525+
if (buf[i + j] >= 32 && buf[i + j] < 127) {
526+
mp_printf(printer, "%c", buf[i + j]);
527+
} else {
528+
mp_printf(printer, ".");
529+
}
530+
}
531+
mp_printf(printer, "\n");
532+
}
533+
}

supervisor/shared/serial.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ char board_serial_read(void);
4747
uint32_t board_serial_bytes_available(void);
4848
void board_serial_write_substring(const char *text, uint32_t length);
4949

50-
int console_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
50+
extern const mp_print_t console_uart_print;
51+
52+
void print_hexdump(const mp_print_t *printer, const char *prefix, const uint8_t *buf, size_t len);

0 commit comments

Comments
 (0)
0