Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f039d01
pbdrv/uart: Use uint32_t for read/write length.
jaguilar Oct 21, 2025
a6fcf10
pbdrv/bluetooth: UART block for EV3.
jaguilar Oct 22, 2025
db6e51c
pbio/platform/ev3: Pins for ev3 bluetooth module.
jaguilar Oct 22, 2025
f0565c5
pbio/platform/ev3: Bluetooth platform_data defs.
jaguilar Oct 22, 2025
dfd7676
PR fixes.
jaguilar Oct 25, 2025
899bf13
pbio/platform/ev3: Add more Bluetooth pins.
jaguilar Oct 26, 2025
24695d8
pbdrv/platform/ev3: Format&comment fixup.
jaguilar Oct 26, 2025
670fe21
pbdrv/bluetooth: Rename fns in ev3 uart block.
jaguilar Oct 26, 2025
671033e
pbdrv/bluetooth: EV3 comment fixup for PR.
jaguilar Oct 26, 2025
5360a0d
pbdrv/bluetooth: Format fixup.
jaguilar Oct 26, 2025
28d9654
bricks: PB_LIB_BTSTACK as string variable
jaguilar Oct 26, 2025
b704379
pbdrv/uart_debug_first_port: fix bugs/va_list func
jaguilar Oct 29, 2025
580f3de
platform/ev3: Finish bluetooth configuration.
jaguilar Oct 30, 2025
6e2c634
pbdrv/bluetooth: UART block fixes for EV3.
jaguilar Oct 29, 2025
bb384be
pbdrv/bluetooth: Init scripts for cc2560x.
jaguilar Oct 30, 2025
98c13bf
pbdrv/bluetooth: Add classic runloop.
jaguilar Oct 29, 2025
cccb6ef
compile fix for le hubs
jaguilar Oct 30, 2025
66b55df
pbdrv/bluetooth: Add forgotten pbdrvconfig include.
jaguilar Nov 4, 2025
f68fc89
bricks: Restore accidentally removed cc2564C_1.4.c.
jaguilar Nov 4, 2025
0d83746
pbdrv/bluetooth: EV3 UART block return errors.
jaguilar Nov 5, 2025
0853e88
pbdrv/bluetooth: Refactor classic, add scan API.
jaguilar Nov 5, 2025
33cfa70
bricks/ev3: Add Bluetooth classic object.
jaguilar Nov 5, 2025
940d87f
pbdrv/bluetooth: Classic scan now reports name.
jaguilar Nov 5, 2025
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
11 changes: 8 additions & 3 deletions bricks/_common/arm_none_eabi.mk
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ $(error failed)
endif
endif
endif
ifeq ($(PB_LIB_BTSTACK),1)
ifeq ($(or $(PB_LIB_BTSTACK),$(PB_LIB_BTSTACK_CLASSIC)),1)
ifeq ("$(wildcard $(PBTOP)/lib/btstack/README.md)","")
$(info GIT cloning btstack submodule)
$(info $(shell cd $(PBTOP) && git submodule update --checkout --init lib/btstack))
Expand Down Expand Up @@ -124,7 +124,7 @@ endif
ifeq ($(PB_LIB_BLE5STACK),1)
INC += -I$(PBTOP)/lib/ble5stack/central
endif
ifeq ($(PB_LIB_BTSTACK),1)
ifeq ($(or $(PB_LIB_BTSTACK),$(PB_LIB_BTSTACK_CLASSIC)),1)
INC += -I$(PBTOP)/lib/btstack/chipset/cc256x
INC += -I$(PBTOP)/lib/btstack/src
endif
Expand Down Expand Up @@ -359,7 +359,7 @@ BTSTACK_SRC_C = $(addprefix lib/btstack/src/,\
l2cap.c \
)

BTSTACK_SRC_C += $(addprefix lib/btstack/src/ble/,\
BTSTACK_BLE_SRC_C += $(addprefix lib/btstack/src/ble/,\
att_db_util.c \
att_db.c \
att_dispatch.c \
Expand Down Expand Up @@ -509,8 +509,13 @@ ifeq ($(PB_LIB_BLE5STACK),1)
OBJ += $(addprefix $(BUILD)/, $(BLE5STACK_SRC_C:.c=.o))
endif

ifeq ($(PB_LIB_BTSTACK_CLASSIC),1)
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
endif

ifeq ($(PB_LIB_BTSTACK),1)
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_BLE_SRC_C:.c=.o))
endif

ifeq ($(PB_LIB_STM32_HAL),1)
Expand Down
1 change: 1 addition & 0 deletions bricks/_common/sources.mk
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
drv/block_device/block_device_w25qxx_stm32.c \
drv/bluetooth/bluetooth.c \
drv/bluetooth/bluetooth_btstack_control_gpio.c \
drv/bluetooth/bluetooth_btstack_uart_block_ev3.c \
drv/bluetooth/bluetooth_btstack_uart_block_stm32_hal.c \
drv/bluetooth/bluetooth_btstack.c \
drv/bluetooth/bluetooth_init_cc2564C_1.4.c \
Expand Down
1 change: 1 addition & 0 deletions bricks/ev3/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ PBIO_PLATFORM = ev3
PB_MCU_FAMILY = TIAM1808

PB_LIB_UMM_MALLOC = 1
PB_LIB_BTSTACK_CLASSIC = 1

include ../_common/arm_none_eabi.mk
33 changes: 33 additions & 0 deletions bricks/ev3/btstack_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors

// BlueKitchen BTStack config

#ifndef _PLATFORM_EV3_BTSTACK_CONFIG_H_
#define _PLATFORM_EV3_BTSTACK_CONFIG_H_

// BTstack features that can be enabled
#define ENABLE_CLASSIC
// #define ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
#define ENABLE_PRINTF_HEXDUMP

// Temporary, until I'm sure it's working.
#define ENABLE_LOG_DEBUG
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO

// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define MAX_ATT_DB_SIZE 512
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0
#define MAX_NR_HCI_CONNECTIONS 2 // CC2564C can have up to 10 connections
#define MAX_NR_HFP_CONNECTIONS 0
#define MAX_NR_L2CAP_CHANNELS 0
#define MAX_NR_L2CAP_SERVICES 0
#define MAX_NR_RFCOMM_CHANNELS 4
#define MAX_NR_RFCOMM_MULTIPLEXERS 0
#define MAX_NR_RFCOMM_SERVICES 0
#define MAX_NR_SERVICE_RECORD_ITEMS 0
#define MAX_NR_WHITELIST_ENTRIES 0

#endif // _PLATFORM_EV3_BTSTACK_CONFIG_H_
192 changes: 192 additions & 0 deletions lib/pbio/drv/bluetooth/bluetooth_btstack_uart_block_ev3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2025 The Pybricks Authors

// EV3 UART driver for BlueKitchen BTStack (stubs).

#include <pbdrv/config.h>

#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3_UART

#include <stdint.h>

#include <btstack.h>
#include <btstack_uart_block.h>
#include <pbdrv/uart.h>
#include <pbio/os.h>

#include "bluetooth_btstack_uart_block_ev3.h"

// If a read has been requested, a pointer to the buffer and its length, else
// null and zero.
static uint8_t *read_buf;
static int read_buf_len;

// If a write has been requested, a pointer to the buffer and its length, else
// null and zero.
static const uint8_t *write_buf;
static int write_buf_len;

// Should the reader and writer processes shut down?
static bool start_shutdown;

// How many threads have processes have exited since the request to shut down?
static int8_t threads_shutdown_complete;

// Called when a block finishes sending.
static void (*block_sent)(void);
// Called when a block finishes being received.
static void (*block_received)(void);

// Processes for reading and writing blocks.
static pbio_os_process_t reader_process;
static pbio_os_process_t writer_process;

static pbdrv_uart_dev_t *uart_device() {
const pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t *pdata =
&pbdrv_bluetooth_btstack_uart_block_ev3_platform_data;
pbdrv_uart_dev_t *uart;
pbio_error_t err = pbdrv_uart_get_instance(pdata->uart_id, &uart);
if (err != PBIO_SUCCESS) {
return NULL;
}
return uart;
}

static int btstack_uart_block_ev3_init(const btstack_uart_config_t *config) {
pbdrv_uart_set_baud_rate(uart_device(), config->baudrate);
// TODO: add parity, flow control APIs and obey them.

return 0;
}

static pbio_error_t do_read_process(pbio_os_state_t *state, void *context) {
pbdrv_uart_dev_t *const uart = uart_device();

pbio_os_state_t read_state;
PBIO_OS_ASYNC_BEGIN(state);

while (true) {
PBIO_OS_AWAIT_UNTIL(state, read_buf || start_shutdown);
if (start_shutdown) {
break;
}

PBIO_OS_AWAIT(state, &read_state,
pbdrv_uart_read(state, uart, read_buf, read_buf_len, /*timeout=*/ 0));
read_buf = NULL;
read_buf_len = 0;
if (block_received) {
block_received();
}
}

++threads_shutdown_complete;
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}

static pbio_error_t do_write_process(pbio_os_state_t *state, void *context) {
pbdrv_uart_dev_t *const uart = uart_device();

pbio_os_state_t write_state;

PBIO_OS_ASYNC_BEGIN(state);

while (true) {
PBIO_OS_AWAIT_UNTIL(state, write_buf || start_shutdown);
if (start_shutdown) {
break;
}

PBIO_OS_AWAIT(state, &write_state,
pbdrv_uart_write(&write_state, uart, (uint8_t *)write_buf, write_buf_len, /*timeout=*/ 0));
write_buf = NULL;
write_buf_len = 0;
if (block_sent) {
block_sent();
}
}

++threads_shutdown_complete;
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}


static int btstack_uart_block_ev3_open(void) {
write_buf = NULL;
write_buf_len = 0;
read_buf = NULL;
read_buf_len = 0;
start_shutdown = false;
threads_shutdown_complete = 0;
block_received = NULL;
block_sent = NULL;

pbio_os_process_start(&reader_process, do_read_process, NULL);
pbio_os_process_start(&writer_process, do_write_process, NULL);

return 0;
}

static int btstack_uart_block_ev3_close(void) {
start_shutdown = true;
while (threads_shutdown_complete < 2) {
pbio_os_run_processes_and_wait_for_event();
}

return 0;
}

static void btstack_uart_block_ev3_set_block_received(void (*handler)(void)) {
block_received = handler;
}

static void btstack_uart_block_ev3_set_block_sent(void (*handler)(void)) {
block_sent = handler;
}

static int btstack_uart_block_ev3_set_baudrate(uint32_t baud) {
pbdrv_uart_set_baud_rate(uart_device(), baud);
return 0;
}

static int btstack_uart_block_ev3_set_parity(int parity) {
// TODO: maybe implement the parity setting.
return 0;
}

static void btstack_uart_block_ev3_receive_block(uint8_t *buffer,
uint16_t len) {
read_buf = buffer;
read_buf_len = len;
pbio_os_request_poll();
}

static void btstack_uart_block_ev3_send_block(const uint8_t *data,
uint16_t size) {
write_buf = data;
write_buf_len = size;
pbio_os_request_poll();
}

static const btstack_uart_block_t btstack_uart_block_ev3 = {
.init = btstack_uart_block_ev3_init,
.open = btstack_uart_block_ev3_open,
.close = btstack_uart_block_ev3_close,
.set_block_received = btstack_uart_block_ev3_set_block_received,
.set_block_sent = btstack_uart_block_ev3_set_block_sent,
.set_baudrate = btstack_uart_block_ev3_set_baudrate,
.set_parity = btstack_uart_block_ev3_set_parity,
.set_flowcontrol = NULL,
.receive_block = btstack_uart_block_ev3_receive_block,
.send_block = btstack_uart_block_ev3_send_block,
.get_supported_sleep_modes = NULL,
.set_sleep = NULL,
.set_wakeup_handler = NULL,
};

const btstack_uart_block_t *pbdrv_bluetooth_btstack_uart_block_ev3_instance(
void) {
return &btstack_uart_block_ev3;
}

#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3_UART
25 changes: 25 additions & 0 deletions lib/pbio/drv/bluetooth/bluetooth_btstack_uart_block_ev3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2025 The Pybricks Authors

// EV3 UART driver for BlueKitchen BTStack (stubs).

#ifndef _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_
#define _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_

#include <btstack_uart_block.h>
#include <pbdrv/uart.h>
#include <stdint.h>

const btstack_uart_block_t *pbdrv_bluetooth_btstack_uart_block_ev3_instance(
void);

typedef struct {
// The uart device connected to the Bluetooth module.
uint8_t uart_id;
} pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t;

// To be defined in platform/ev3/platform.c
extern const pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t
pbdrv_bluetooth_btstack_uart_block_ev3_platform_data;

#endif // _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_
16 changes: 8 additions & 8 deletions lib/pbio/drv/uart/uart_ev3.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ struct _pbdrv_uart_dev_t {
/** The buffer passed to the read function. */
uint8_t *read_buf;
/** The length of read_buf in bytes. */
uint8_t read_length;
uint32_t read_length;
/** The current position in read_buf. */
uint8_t read_pos;
uint32_t read_pos;
/** The buffer passed to the write function. */
const uint8_t *write_buf;
/** The length of write_buf in bytes. */
uint8_t write_length;
uint32_t write_length;
/** The current position in write_buf. */
volatile uint8_t write_pos;
volatile uint32_t write_pos;
};

static pbdrv_uart_dev_t uart_devs[PBDRV_CONFIG_UART_EV3_NUM_UART];
Expand All @@ -89,7 +89,7 @@ int32_t pbdrv_uart_get_char(pbdrv_uart_dev_t *uart) {
return ringbuf_get(&uart->rx_buf);
}

pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uint8_t *msg, uint8_t length, uint32_t timeout) {
pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uint8_t *msg, uint32_t length, uint32_t timeout) {

PBIO_OS_ASYNC_BEGIN(state);

Expand Down Expand Up @@ -131,7 +131,7 @@ pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uin
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}

static pbio_error_t pbdrv_uart_write_pru(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint8_t length, uint32_t timeout) {
static pbio_error_t pbdrv_uart_write_pru(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint32_t length, uint32_t timeout) {

const pbdrv_uart_ev3_platform_data_t *pdata = uart->pdata;

Expand Down Expand Up @@ -178,7 +178,7 @@ static pbio_error_t pbdrv_uart_write_pru(pbio_os_state_t *state, pbdrv_uart_dev_
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}

pbio_error_t pbdrv_uart_write_hw(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint8_t length, uint32_t timeout) {
pbio_error_t pbdrv_uart_write_hw(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint32_t length, uint32_t timeout) {

const pbdrv_uart_ev3_platform_data_t *pdata = uart->pdata;

Expand Down Expand Up @@ -240,7 +240,7 @@ pbio_error_t pbdrv_uart_write_hw(pbio_os_state_t *state, pbdrv_uart_dev_t *uart,
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}

pbio_error_t pbdrv_uart_write(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint8_t length, uint32_t timeout) {
pbio_error_t pbdrv_uart_write(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint32_t length, uint32_t timeout) {
const pbdrv_uart_ev3_platform_data_t *pdata = uart->pdata;

if (pdata->uart_kind == EV3_UART_HW) {
Expand Down
12 changes: 6 additions & 6 deletions lib/pbio/drv/uart/uart_stm32f0.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ struct _pbdrv_uart_dev_t {
volatile uint8_t rx_ring_buf_head;
uint8_t rx_ring_buf_tail;
uint8_t *rx_buf;
uint8_t rx_buf_size;
uint8_t rx_buf_index;
uint32_t rx_buf_size;
uint32_t rx_buf_index;
const uint8_t *tx_buf;
uint8_t tx_buf_size;
uint8_t tx_buf_index;
uint32_t tx_buf_size;
uint32_t tx_buf_index;
pbio_os_timer_t rx_timer;
pbio_os_timer_t tx_timer;
uint8_t irq;
Expand All @@ -59,7 +59,7 @@ pbio_error_t pbdrv_uart_get_instance(uint8_t id, pbdrv_uart_dev_t **uart_dev) {
return PBIO_SUCCESS;
}

pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uint8_t *msg, uint8_t length, uint32_t timeout) {
pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uint8_t *msg, uint32_t length, uint32_t timeout) {

PBIO_OS_ASYNC_BEGIN(state);

Expand Down Expand Up @@ -102,7 +102,7 @@ pbio_error_t pbdrv_uart_read(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, uin
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
}

pbio_error_t pbdrv_uart_write(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint8_t length, uint32_t timeout) {
pbio_error_t pbdrv_uart_write(pbio_os_state_t *state, pbdrv_uart_dev_t *uart, const uint8_t *msg, uint32_t length, uint32_t timeout) {

PBIO_OS_ASYNC_BEGIN(state);

Expand Down
Loading