Skip to content

Commit

Permalink
pbio/drv/uart: Add debug module.
Browse files Browse the repository at this point in the history
Provides a non-blocking buffered write to the first UART port.

Now we may debug in peace.
  • Loading branch information
laurensvalk committed Jan 17, 2025
1 parent 88b967c commit 156c2ba
Show file tree
Hide file tree
Showing 16 changed files with 181 additions and 11 deletions.
1 change: 1 addition & 0 deletions bricks/_common/sources.mk
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
drv/resistor_ladder/resistor_ladder.c \
drv/sound/sound_nxt.c \
drv/sound/sound_stm32_hal_dac.c \
drv/uart/uart_debug_first_port.c \
drv/uart/uart_stm32f0.c \
drv/uart/uart_stm32f4_ll_irq.c \
drv/uart/uart_stm32l4_ll_dma.c \
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/drv/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "reset/reset.h"
#include "sound/sound.h"
#include "uart/uart.h"
#include "uart/uart_debug_first_port.h"
#include "usb/usb.h"
#include "watchdog/watchdog.h"

Expand Down Expand Up @@ -54,6 +55,7 @@ void pbdrv_init(void) {
pbdrv_reset_init();
pbdrv_sound_init();
pbdrv_uart_init();
pbdrv_uart_debug_init();
pbdrv_usb_init();
pbdrv_watchdog_init();

Expand Down
110 changes: 110 additions & 0 deletions lib/pbio/drv/uart/uart_debug_first_port.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2024-2025 The Pybricks Authors

#include "pbdrv/config.h"

#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT

#include <pbdrv/uart.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

PROCESS(pbdrv_uart_debug_process, "UART Debug");

#define BUF_SIZE (256)

static uint8_t ring_buf[BUF_SIZE];
static size_t ring_head = 0;
static size_t ring_tail = 0;

static pbdrv_uart_dev_t *debug_uart = NULL;

/**
* Formats and stores a string in the UART debug ring buffer.
*
* This function works similarly to printf, but instead of printing to the
* standard output. The formatted string will be written to the UART when the
* buffer is processed.
*
* @param format The format string, similar to printf.
* @param ... The variable arguments, similar to printf.
*/
void pbdrv_uart_debug_printf(const char *format, ...) {

if (!debug_uart) {
// Not initialized yet.
return;
}

char buf[BUF_SIZE];
va_list args;
va_start(args, format);
vsnprintf(buf, sizeof(ring_buf), format, args);
va_end(args);

size_t len = strlen(buf);
for (size_t i = 0; i < len; i++) {
ring_buf[ring_head] = buf[i];
ring_head = (ring_head + 1) % BUF_SIZE;
}

// Request print process to write out new data.
process_poll(&pbdrv_uart_debug_process);
}

void pbdrv_uart_debug_init(void) {
process_start(&pbdrv_uart_debug_process);
}

static void pbdrv_uart_debug_process_poll(void *port) {
// Ticks process along in between writing bytes.
process_poll(&pbdrv_uart_debug_process);
}

PROCESS_THREAD(pbdrv_uart_debug_process, ev, data) {

static struct pt child;
static pbio_error_t err;
static size_t write_size;

PROCESS_BEGIN();

PROCESS_WAIT_EVENT_UNTIL({
process_poll(&pbdrv_uart_debug_process);
pbdrv_uart_get(0, &debug_uart) == PBIO_SUCCESS;
});

pbdrv_uart_set_baud_rate(debug_uart, 115200);
pbdrv_uart_set_poll_callback(debug_uart, pbdrv_uart_debug_process_poll, NULL);

for (;;) {

PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL);
if (ring_head == ring_tail) {
continue;
}

// Write up to the end of the buffer without wrapping.
size_t end = ring_head > ring_tail ? ring_head: BUF_SIZE;
write_size = end - ring_tail;
PROCESS_PT_SPAWN(&child, pbdrv_uart_write(&child, debug_uart, &ring_buf[ring_tail], write_size, 100, &err));
ring_tail = (ring_tail + write_size) % BUF_SIZE;

// Reset on failure.
if (err != PBIO_SUCCESS) {
ring_head = 0;
ring_tail = 0;
continue;
}

// Poll to write again if not fully finished, i.e. when wrapping.
if (ring_head != ring_tail) {
process_poll(&pbdrv_uart_debug_process);
}
}

PROCESS_END();
}

#endif // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
23 changes: 23 additions & 0 deletions lib/pbio/drv/uart/uart_debug_first_port.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2018-2020 The Pybricks Authors

#ifndef _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_
#define _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_

#include <stdint.h>

#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT

void pbdrv_uart_debug_printf(const char *format, ...);

void pbdrv_uart_debug_init(void);

#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT

#define pbdrv_uart_debug_printf(...)

#define pbdrv_uart_debug_init()

#endif // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT

#endif // _INTERNAL_PBDRV_UART_DEBUG_FIRST_PORT_H_
1 change: 1 addition & 0 deletions lib/pbio/platform/city_hub/pbdrvconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (1)

#define PBDRV_CONFIG_UART (1)
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
#define PBDRV_CONFIG_UART_STM32F0 (1)
#define PBDRV_CONFIG_UART_STM32F0_NUM_UART (2)

Expand Down
4 changes: 4 additions & 0 deletions lib/pbio/platform/city_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = 1, // USART3
.uart_rx_alt_uart = 1, // USART3
},
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_UART,
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
#endif
},
{
.port_id = PBIO_PORT_ID_B,
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/essential_hub/pbdrvconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (0)

#define PBDRV_CONFIG_UART (1)
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ (1)
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ_NUM_UART (2)

Expand Down
6 changes: 5 additions & 1 deletion lib/pbio/platform/essential_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = GPIO_AF8_UART5,
.uart_rx_alt_uart = GPIO_AF8_UART5,
},
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_UART,
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
#endif
},
{
.port_id = PBIO_PORT_ID_B,
Expand All @@ -254,7 +258,7 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = GPIO_AF7_USART3,
.uart_rx_alt_uart = GPIO_AF7_USART3,
},
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
},
};

Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/move_hub/pbdrvconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (1)

#define PBDRV_CONFIG_UART (1)
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
#define PBDRV_CONFIG_UART_STM32F0 (1)
#define PBDRV_CONFIG_UART_STM32F0_NUM_UART (2)

Expand Down
4 changes: 4 additions & 0 deletions lib/pbio/platform/move_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = 0, // USART4
.uart_rx_alt_uart = 0, // USART4
},
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_UART,
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
#endif
},
{
.port_id = PBIO_PORT_ID_D,
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/prime_hub/pbdrvconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
#define PBDRV_CONFIG_SOUND_STM32_HAL_DAC (1)

#define PBDRV_CONFIG_UART (1)
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ (1)
#define PBDRV_CONFIG_UART_STM32F4_LL_IRQ_NUM_UART (6)

Expand Down
4 changes: 4 additions & 0 deletions lib/pbio/platform/prime_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = GPIO_AF8_UART7,
.uart_rx_alt_uart = GPIO_AF8_UART7,
},
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_UART,
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
#endif
},
{
.port_id = PBIO_PORT_ID_B,
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/technic_hub/pbdrvconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#define PBDRV_CONFIG_RESET_STM32_HAS_BLE_BOOTLOADER (1)

#define PBDRV_CONFIG_UART (1)
#define PBDRV_CONFIG_UART_DEBUG_FIRST_PORT (0)
#define PBDRV_CONFIG_UART_STM32L4_LL_DMA (1)
#define PBDRV_CONFIG_UART_STM32L4_LL_DMA_NUM_UART (4)

Expand Down
6 changes: 5 additions & 1 deletion lib/pbio/platform/technic_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = GPIO_AF7_USART1,
.uart_rx_alt_uart = GPIO_AF7_USART1,
},
#if PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_UART,
#else // PBDRV_CONFIG_UART_DEBUG_FIRST_PORT
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
#endif
},
{
.port_id = PBIO_PORT_ID_B,
Expand Down Expand Up @@ -313,7 +317,7 @@ const pbdrv_ioport_platform_data_t pbdrv_ioport_platform_data[PBDRV_CONFIG_IOPOR
.uart_tx_alt_uart = GPIO_AF8_LPUART1,
.uart_rx_alt_uart = GPIO_AF8_LPUART1,
},
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
.supported_modes = PBIO_PORT_MODE_LEGO_PUP | PBIO_PORT_MODE_UART,
},
};

Expand Down
22 changes: 16 additions & 6 deletions lib/pbio/src/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,10 @@ pbio_error_t pbio_port_p1p2_set_power(pbio_port_t *port, pbio_port_power_require

/**
* Initializes a port instance.
*
*
* NB: Errors from this init functions are not checked. This should only use
* static config information and not rely on runtime capability checks.
*
*
* @param [in] port The port instance.
*/
static void pbio_port_init_one_port(pbio_port_t *port) {
Expand All @@ -404,11 +404,11 @@ static void pbio_port_init_one_port(pbio_port_t *port) {
// checking for errors.
port->dcmotor = pbio_dcmotor_init_instance(port->pdata->motor_driver_index, motor_driver);
port->servo = pbio_servo_init_instance(port->pdata->motor_driver_index, port, port->dcmotor);
}
}

// Configure basic quadrature-only ports such as BOOST A&B or NXT A&B&C
// without device kind and type id detection.
if (port->pdata->supported_modes == PBIO_PORT_MODE_QUADRATURE_PASSIVE) {
if (port->pdata->supported_modes == PBIO_PORT_MODE_QUADRATURE_PASSIVE) {
port->device_info.kind = PBIO_PORT_DEVICE_KIND_QUADRATURE_MOTOR;
port->device_info.type_id = PBIO_CONFIG_PORT_DEFAULT_MOTOR;
pbio_port_set_mode(port, PBIO_PORT_MODE_QUADRATURE_PASSIVE);
Expand All @@ -425,6 +425,11 @@ static void pbio_port_init_one_port(pbio_port_t *port) {
pbio_port_set_mode(port, PBIO_PORT_MODE_LEGO_PUP);
return;
}

if (port->uart_dev && (port->pdata->supported_modes & PBIO_PORT_MODE_UART)) {
pbio_port_set_mode(port, PBIO_PORT_MODE_UART);
return;
}
}

void pbio_port_init(void) {
Expand Down Expand Up @@ -492,7 +497,7 @@ void pbio_port_process_poll(void *port) {
* ::PBIO_ERROR_INVALID_OP if the operation is not permitted in the current state.
*/
pbio_error_t pbio_port_set_mode(pbio_port_t *port, pbio_port_mode_t mode) {

// Nothing to do.
if (port->mode == mode) {
return PBIO_SUCCESS;
Expand All @@ -510,12 +515,17 @@ pbio_error_t pbio_port_set_mode(pbio_port_t *port, pbio_port_mode_t mode) {
case PBIO_PORT_MODE_LEGO_PUP:
// Physical modes for this mode will be set by the process so this
// is all we need to do here.
port->process.thread = process_thread_pbio_port_process_pup;
port->process.thread = process_thread_pbio_port_process_pup;

// Returning e-again allows user module to wait for the port to be
// ready after first entering LEGO mode, avoiding NODEV errors when
// switching from UART mode to LEGO mode.
return PBIO_ERROR_AGAIN;
case PBIO_PORT_MODE_UART:
// Enable UART on the port. No process needed here. User can
// access UART from their own event loop.
pbdrv_ioport_p5p6_set_mode(port->pdata->pins, port->uart_dev, PBDRV_IOPORT_P5P6_MODE_UART);
return PBIO_SUCCESS;
default:
return PBIO_ERROR_NOT_SUPPORTED;
}
Expand Down
5 changes: 2 additions & 3 deletions lib/pbio/src/port_lump.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
#if DEBUG
#include <stdio.h>
#include <inttypes.h>
#define debug_pr printf
#define debug_pr_str(str) printf((str))
#include <pbdrv/../../drv/uart/uart_debug_first_port.h>
#define debug_pr pbdrv_uart_debug_printf
#define DBG_ERR(expr) expr
#else
#define debug_pr(...)
#define debug_pr_str(...)
#define DBG_ERR(expr)
#endif

Expand Down

0 comments on commit 156c2ba

Please sign in to comment.