@@ -63,33 +63,94 @@ static bool _serial_console_write_disabled;
63
63
// Set to true to temporarily discard writes to the display terminal only.
64
64
static bool _serial_display_write_disabled ;
65
65
66
+ // Indicates that serial console has been early initialized.
67
+ static bool _serial_console_early_inited = false;
68
+
66
69
#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 ) {
68
75
(void )env ;
69
76
int uart_errcode ;
10000
code>
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
+ }
71
93
}
72
94
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
+ }
74
108
#endif
75
109
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 ;
82
114
}
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 );
91
149
}
92
150
151
+ const mp_print_t console_uart_print = {NULL , console_uart_write_cb };
152
+ #endif
153
+
93
154
MP_WEAK void board_serial_early_init (void ) {
94
155
}
95
156
@@ -137,9 +198,14 @@ MP_WEAK void port_serial_write_substring(const char *text, uint32_t length) {
137
198
}
138
199
139
200
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
+ }
141
206
142
207
#if CIRCUITPY_CONSOLE_UART
208
+ // Set up console UART, if enabled.
143
209
console_uart .base .type = & busio_uart_type ;
144
210
145
211
const mcu_pin_obj_t * console_rx = MP_OBJ_TO_PTR (CIRCUITPY_CONSOLE_UART_RX );
@@ -150,12 +216,15 @@ void serial_early_init(void) {
150
216
console_uart_rx_buf , true);
151
217
common_hal_busio_uart_never_reset (& console_uart );
152
218
153
- // Do an initial print so that we can confirm the serial output is working.
154
- console_uart_printf ("Serial console setup\r\n" );
155
219
#endif
156
220
157
221
board_serial_early_init ();
158
222
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" );
159
228
}
160
229
161
230
void serial_init (void ) {
@@ -347,12 +416,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) {
347
416
#endif
348
417
349
418
#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 );
356
420
#endif
357
421
358
422
#if CIRCUITPY_SERIAL_BLE
@@ -409,3 +473,61 @@ bool serial_display_write_disable(bool disabled) {
409
473
_serial_display_write_disabled = disabled ;
410
474
return now ;
411
475
}
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
+ }
0 commit comments