Skip to content

Commit 156c2ba

Browse files
committed
pbio/drv/uart: Add debug module.
Provides a non-blocking buffered write to the first UART port. Now we may debug in peace.
1 parent 88b967c commit 156c2ba

File tree

16 files changed

+181
-11
lines changed

16 files changed

+181
-11
lines changed

bricks/_common/sources.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
174174
drv/resistor_ladder/resistor_ladder.c \
175175
drv/sound/sound_nxt.c \
176176
drv/sound/sound_stm32_hal_dac.c \
177+
drv/uart/uart_debug_first_port.c \
177178
drv/uart/uart_stm32f0.c \
178179
drv/uart/uart_stm32f4_ll_irq.c \
179180
drv/uart/uart_stm32l4_ll_dma.c \

lib/pbio/drv/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "reset/reset.h"
2525
#include "sound/sound.h"
2626
#include "uart/uart.h"
27+
#include "uart/uart_debug_first_port.h"
2728
#include "usb/usb.h"
2829
#include "watchdog/watchdog.h"
2930

@@ -54,6 +55,7 @@ void pbdrv_init(void) {
5455
pbdrv_reset_init();
5556
pbdrv_sound_init();
5657
pbdrv_uart_init();
58+
pbdrv_uart_debug_init();
5759
pbdrv_usb_init();
5860
pbdrv_watchdog_init();
5961

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2024-2025 The Pybricks Authors
3+
4+
#include "pbdrv/config.h"
5+
6+
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
7+
8+
#include <pbdrv/uart.h>
9+
#include <stdio.h>
10+
#include <stdarg.h>
11+
#include <string.h>
12+
13+
PROCESS(pbdrv_uart_debug_process, "UART Debug");
14+
15+
#define BUF_SIZE (256)
16+
17+
static uint8_t ring_buf[BUF_SIZE];
18+
static size_t ring_head = 0;
19+
static size_t ring_tail = 0;
20+
21+
static pbdrv_uart_dev_t *debug_uart = NULL;
22+
23+
/**
24+
* Formats and stores a string in the UART debug ring buffer.
25+
*
26+
* This function works similarly to printf, but instead of printing to the
27+
* standard output. The formatted string will be written to the UART when the
28+
* buffer is processed.
29+
*
30+
* @param format The format string, similar to printf.
31+
* @param ... The variable arguments, similar to printf.
32+
*/
33+
void pbdrv_uart_debug_printf(const char *format, ...) {
34+
35+
if (!debug_uart) {
36+
// Not initialized yet.
37+
return;
38+
}
39+
40+
char buf[BUF_SIZE];
41+
va_list args;
42+
va_start(args, format);
43+
vsnprintf(buf, sizeof(ring_buf), format, args);
44+
va_end(args);
45+
46+
size_t len = strlen(buf);
47+
for (size_t i = 0; i < len; i++) {
48+
ring_buf[ring_head] = buf[i];
49+
ring_head = (ring_head + 1) % BUF_SIZE;
50+
}
51+
52+
// Request print process to write out new data.
53+
process_poll(&pbdrv_uart_debug_process);
54+
}
55+
56+
void pbdrv_uart_debug_init(void) {
57+
process_start(&pbdrv_uart_debug_process);
58+
}
59+
60+
static void pbdrv_uart_debug_process_poll(void *port) {
61+
// Ticks process along in between writing bytes.
62+
process_poll(&pbdrv_uart_debug_process);
63+
}
64+
65+
PROCESS_THREAD(pbdrv_uart_debug_process, ev, data) {
66+
67+
static struct pt child;
68+
static pbio_error_t err;
69+
static size_t write_size;
70+
71+
PROCESS_BEGIN();
72+
73+
PROCESS_WAIT_EVENT_UNTIL({
74+
process_poll(&pbdrv_uart_debug_process);
75+
pbdrv_uart_get(0, &debug_uart) == PBIO_SUCCESS;
76+
});
77+
78+
pbdrv_uart_set_baud_rate(debug_uart, 115200);
79+
pbdrv_uart_set_poll_callback(debug_uart, pbdrv_uart_debug_process_poll, NULL);
80+
81+
for (;;) {
82+
83+
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL);
84+
if (ring_head == ring_tail) {
85+
continue;
86+
}
87+
88+
// Write up to the end of the buffer without wrapping.
89+
size_t end = ring_head > ring_tail ? ring_head: BUF_SIZE;
90+
write_size = end - ring_tail;
91+
PROCESS_PT_SPAWN(&child, pbdrv_uart_write(&child, debug_uart, &ring_buf[ring_tail], write_size, 100, &err));
92+
ring_tail = (ring_tail + write_size) % BUF_SIZE;
93+
94+
// Reset on failure.
95+
if (err != PBIO_SUCCESS) {
96+
ring_head = 0;
97+
ring_tail = 0;
98+
continue;
99+
}
100+
101+
// Poll to write again if not fully finished, i.e. when wrapping.
102+
if (ring_head != ring_tail) {
103+
process_poll(&pbdrv_uart_debug_process);
104+
}
105+
}
106+
107+
PROCESS_END();
108+
}
109+
110+
#endif // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2018-2020 The Pybricks Authors
3+
4+
#ifndef _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_
5+
#define _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_
6+
7+
#include <stdint.h>
8+
9+
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
10+
11+
void pbdrv_uart_debug_printf(const char *format, ...);
12+
13+
void pbdrv_uart_debug_init(void);
14+
15+
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
16+
17+
#define pbdrv_uart_debug_printf(...)
18+
19+
#define pbdrv_uart_debug_init()
20+
21+
#endif // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
22+
23+
#endif // _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_

lib/pbio/platform/city_hub/pbdrvconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (1)
6969

7070
#define PBDRV_CONFIG_UART (1)
71+
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
7172
#define PBDRV_CONFIG_UART_STM32F0 (1)
7273
#define PBDRV_CONFIG_UART_STM32F0_NUM_UART (2)
7374

lib/pbio/platform/city_hub/platform.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
180180
.uart_tx_alt_uart = 1, // USART3
181181
.uart_rx_alt_uart = 1, // USART3
182182
},
183+
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
184+
.supported_modes = PBIO_PORT_MODE_UART,
185+
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
183186
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
187+
#endif
184188
},
185189
{
186190
.port_id = PBIO_PORT_ID_B,

lib/pbio/platform/essential_hub/pbdrvconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (0)
9292

9393
#define PBDRV_CONFIG_UART (1)
94+
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
9495
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ (1)
9596
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ_NUM_UART (2)
9697

lib/pbio/platform/essential_hub/platform.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
239239
.uart_tx_alt_uart = GPIO_AF8_UART5,
240240
.uart_rx_alt_uart = GPIO_AF8_UART5,
241241
},
242+
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
243+
.supported_modes = PBIO_PORT_MODE_UART,
244+
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
242245
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
246+
#endif
243247
},
244248
{
245249
.port_id = PBIO_PORT_ID_B,
@@ -254,7 +258,7 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
254258
.uart_tx_alt_uart = GPIO_AF7_USART3,
255259
.uart_rx_alt_uart = GPIO_AF7_USART3,
256260
},
257-
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
261+
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
258262
},
259263
};
260264

lib/pbio/platform/move_hub/pbdrvconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (1)
6565

6666
#define PBDRV_CONFIG_UART (1)
67+
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
6768
#define PBDRV_CONFIG_UART_STM32F0 (1)
6869
#define PBDRV_CONFIG_UART_STM32F0_NUM_UART (2)
6970

lib/pbio/platform/move_hub/platform.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
100100
.uart_tx_alt_uart = 0, // USART4
101101
.uart_rx_alt_uart = 0, // USART4
102102
},
103+
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
104+
.supported_modes = PBIO_PORT_MODE_UART,
105+
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
103106
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
107+
#endif
104108
},
105109
{
106110
.port_id = PBIO_PORT_ID_D,

0 commit comments

Comments
 (0)