Skip to content

Commit a6fcf10

Browse files
committed
pbdrv/bluetooth: UART block for EV3.
This commit creates a UART block implementation for btstack on the EV3. This will allow us to communicate HCI commands from the btstack library to the EV3's bluetooth module. The commit also contains necessary changes to makefiles to allow compiling this module.
1 parent f039d01 commit a6fcf10

File tree

7 files changed

+262
-3
lines changed

7 files changed

+262
-3
lines changed

bricks/_common/arm_none_eabi.mk

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ $(error failed)
5252
endif
5353
endif
5454
endif
55-
ifeq ($(PB_LIB_BTSTACK),1)
55+
ifeq ($(or $(PB_LIB_BTSTACK),$(PB_LIB_BTSTACK_CLASSIC)),1)
5656
ifeq ("$(wildcard $(PBTOP)/lib/btstack/README.md)","")
5757
$(info GIT cloning btstack submodule)
5858
$(info $(shell cd $(PBTOP) && git submodule update --checkout --init lib/btstack))
@@ -124,7 +124,7 @@ endif
124124
ifeq ($(PB_LIB_BLE5STACK),1)
125125
INC += -I$(PBTOP)/lib/ble5stack/central
126126
endif
127-
ifeq ($(PB_LIB_BTSTACK),1)
127+
ifeq ($(or $(PB_LIB_BTSTACK),$(PB_LIB_BTSTACK_CLASSIC)),1)
128128
INC += -I$(PBTOP)/lib/btstack/chipset/cc256x
129129
INC += -I$(PBTOP)/lib/btstack/src
130130
endif
@@ -359,7 +359,7 @@ BTSTACK_SRC_C = $(addprefix lib/btstack/src/,\
359359
l2cap.c \
360360
)
361361

362-
BTSTACK_SRC_C += $(addprefix lib/btstack/src/ble/,\
362+
BTSTACK_BLE_SRC_C += $(addprefix lib/btstack/src/ble/,\
363363
att_db_util.c \
364364
att_db.c \
365365
att_dispatch.c \
@@ -509,8 +509,13 @@ ifeq ($(PB_LIB_BLE5STACK),1)
509509
OBJ += $(addprefix $(BUILD)/, $(BLE5STACK_SRC_C:.c=.o))
510510
endif
511511

512+
ifeq ($(PB_LIB_BTSTACK_CLASSIC),1)
513+
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
514+
endif
515+
512516
ifeq ($(PB_LIB_BTSTACK),1)
513517
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
518+
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_BLE_SRC_C:.c=.o))
514519
endif
515520

516521
ifeq ($(PB_LIB_STM32_HAL),1)

bricks/_common/sources.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
124124
drv/block_device/block_device_w25qxx_stm32.c \
125125
drv/bluetooth/bluetooth.c \
126126
drv/bluetooth/bluetooth_btstack_control_gpio.c \
127+
drv/bluetooth/bluetooth_btstack_uart_block_ev3.c \
127128
drv/bluetooth/bluetooth_btstack_uart_block_stm32_hal.c \
128129
drv/bluetooth/bluetooth_btstack.c \
129130
drv/bluetooth/bluetooth_init_cc2564C_1.4.c \

bricks/ev3/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ PBIO_PLATFORM = ev3
22
PB_MCU_FAMILY = TIAM1808
33

44
PB_LIB_UMM_MALLOC = 1
5+
PB_LIB_BTSTACK_CLASSIC = 1
56

67
include ../_common/arm_none_eabi.mk

bricks/ev3/btstack_config.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2020 The Pybricks Authors
3+
4+
// BlueKitchen BTStack config
5+
6+
#ifndef _PLATFORM_EV3_BTSTACK_CONFIG_H_
7+
#define _PLATFORM_EV3_BTSTACK_CONFIG_H_
8+
9+
// BTstack features that can be enabled
10+
#define ENABLE_CLASSIC
11+
// #define ENABLE_CC256X_BAUDRATE_CHANGE_FLOWCONTROL_BUG_WORKAROUND
12+
#define ENABLE_PRINTF_HEXDUMP
13+
14+
// Temporary, until I'm sure it's working.
15+
#define ENABLE_LOG_DEBUG
16+
#define ENABLE_LOG_ERROR
17+
#define ENABLE_LOG_INFO
18+
19+
// BTstack configuration. buffers, sizes, ...
20+
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
21+
#define MAX_ATT_DB_SIZE 512
22+
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0
23+
#define MAX_NR_HCI_CONNECTIONS 2 // CC2564C can have up to 10 connections
24+
#define MAX_NR_HFP_CONNECTIONS 0
25+
#define MAX_NR_L2CAP_CHANNELS 0
26+
#define MAX_NR_L2CAP_SERVICES 0
27+
#define MAX_NR_RFCOMM_CHANNELS 4
28+
#define MAX_NR_RFCOMM_MULTIPLEXERS 0
29+
#define MAX_NR_RFCOMM_SERVICES 0
30+
#define MAX_NR_SERVICE_RECORD_ITEMS 0
31+
#define MAX_NR_WHITELIST_ENTRIES 0
32+
33+
#endif // _PLATFORM_EV3_BTSTACK_CONFIG_H_
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
// EV3 UART driver for BlueKitchen BTStack (stubs).
5+
6+
#include <pbdrv/config.h>
7+
8+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3_UART
9+
10+
#include <stdint.h>
11+
12+
#include <btstack.h>
13+
#include <btstack_uart_block.h>
14+
#include <pbdrv/uart.h>
15+
#include <pbio/os.h>
16+
17+
#include "bluetooth_btstack_uart_block_ev3.h"
18+
19+
// If a read has been requested, a pointer to the buffer and its length, else
20+
// null and zero.
21+
static uint8_t *read_buf;
22+
static int read_buf_len;
23+
24+
// If a write has been requested, a pointer to the buffer and its length, else
25+
// null and zero.
26+
static const uint8_t *write_buf;
27+
static int write_buf_len;
28+
29+
// Should the reader and writer processes shut down?
30+
static bool start_shutdown;
31+
32+
// How many threads have processes have exited since the request to shut down?
33+
static int8_t threads_shutdown_complete;
34+
35+
// Called when a block finishes sending.
36+
static void (*block_sent)(void);
37+
// Called when a block finishes being received.
38+
static void (*block_received)(void);
39+
40+
// Processes for reading and writing blocks.
41+
static pbio_os_process_t reader_process;
42+
static pbio_os_process_t writer_process;
43+
44+
static pbdrv_uart_dev_t *uart_device() {
45+
const pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t *pdata =
46+
&pbdrv_bluetooth_btstack_uart_block_ev3_platform_data;
47+
pbdrv_uart_dev_t *uart;
48+
pbio_error_t err = pbdrv_uart_get_instance(pdata->uart_id, &uart);
49+
if (err != PBIO_SUCCESS) {
50+
return NULL;
51+
}
52+
return uart;
53+
}
54+
55+
static int btstack_uart_block_ev3_init(const btstack_uart_config_t *config) {
56+
pbdrv_uart_set_baud_rate(uart_device(), config->baudrate);
57+
// TODO: add parity, flow control APIs and obey them.
58+
59+
return 0;
60+
}
61+
62+
static pbio_error_t do_read_process(pbio_os_state_t *state, void *context) {
63+
pbdrv_uart_dev_t *const uart = uart_device();
64+
65+
pbio_os_state_t read_state;
66+
PBIO_OS_ASYNC_BEGIN(state);
67+
68+
while (true) {
69+
PBIO_OS_AWAIT_UNTIL(state, read_buf || start_shutdown);
70+
if (start_shutdown) {
71+
break;
72+
}
73+
74+
PBIO_OS_AWAIT(state, &read_state,
75+
pbdrv_uart_read(state, uart, read_buf, read_buf_len, /*timeout=*/ 0));
76+
read_buf = NULL;
77+
read_buf_len = 0;
78+
if (block_received) {
79+
block_received();
80+
}
81+
}
82+
83+
++threads_shutdown_complete;
84+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
85+
}
86+
87+
static pbio_error_t do_write_process(pbio_os_state_t *state, void *context) {
88+
pbdrv_uart_dev_t *const uart = uart_device();
89+
90+
pbio_os_state_t write_state;
91+
92+
PBIO_OS_ASYNC_BEGIN(state);
93+
94+
while (true) {
95+
PBIO_OS_AWAIT_UNTIL(state, write_buf || start_shutdown);
96+
if (start_shutdown) {
97+
break;
98+
}
99+
100+
PBIO_OS_AWAIT(state, &write_state,
101+
pbdrv_uart_write(&write_state, uart, (uint8_t *)write_buf, write_buf_len, /*timeout=*/ 0));
102+
write_buf = NULL;
103+
write_buf_len = 0;
104+
if (block_sent) {
105+
block_sent();
106+
}
107+
}
108+
109+
++threads_shutdown_complete;
110+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
111+
}
112+
113+
114+
static int btstack_uart_block_ev3_open(void) {
115+
write_buf = NULL;
116+
write_buf_len = 0;
117+
read_buf = NULL;
118+
read_buf_len = 0;
119+
start_shutdown = false;
120+
threads_shutdown_complete = 0;
121+
block_received = NULL;
122+
block_sent = NULL;
123+
124+
pbio_os_process_start(&reader_process, do_read_process, NULL);
125+
pbio_os_process_start(&writer_process, do_write_process, NULL);
126+
127+
return 0;
128+
}
129+
130+
static int btstack_uart_block_ev3_close(void) {
131+
start_shutdown = true;
132+
while (threads_shutdown_complete < 2) {
133+
pbio_os_run_processes_and_wait_for_event();
134+
}
135+
136+
return 0;
137+
}
138+
139+
static void btstack_uart_block_ev3_set_block_received(void (*handler)(void)) {
140+
block_received = handler;
141+
}
142+
143+
static void btstack_uart_block_ev3_set_block_sent(void (*handler)(void)) {
144+
block_sent = handler;
145+
}
146+
147+
static int btstack_uart_block_ev3_set_baudrate(uint32_t baud) {
148+
pbdrv_uart_set_baud_rate(uart_device(), baud);
149+
return 0;
150+
}
151+
152+
static int btstack_uart_block_ev3_set_parity(int parity) {
153+
// TODO: maybe implement the parity setting.
154+
return 0;
155+
}
156+
157+
static void btstack_uart_block_ev3_receive_block(uint8_t *buffer,
158+
uint16_t len) {
159+
read_buf = buffer;
160+
read_buf_len = len;
161+
pbio_os_request_poll();
162+
}
163+
164+
static void btstack_uart_block_ev3_send_block(const uint8_t *data,
165+
uint16_t size) {
166+
write_buf = data;
167+
write_buf_len = size;
168+
pbio_os_request_poll();
169+
}
170+
171+
static const btstack_uart_block_t btstack_uart_block_ev3 = {
172+
.init = btstack_uart_block_ev3_init,
173+
.open = btstack_uart_block_ev3_open,
174+
.close = btstack_uart_block_ev3_close,
175+
.set_block_received = btstack_uart_block_ev3_set_block_received,
176+
.set_block_sent = btstack_uart_block_ev3_set_block_sent,
177+
.set_baudrate = btstack_uart_block_ev3_set_baudrate,
178+
.set_parity = btstack_uart_block_ev3_set_parity,
179+
.set_flowcontrol = NULL,
180+
.receive_block = btstack_uart_block_ev3_receive_block,
181+
.send_block = btstack_uart_block_ev3_send_block,
182+
.get_supported_sleep_modes = NULL,
183+
.set_sleep = NULL,
184+
.set_wakeup_handler = NULL,
185+
};
186+
187+
const btstack_uart_block_t *pbdrv_bluetooth_btstack_uart_block_ev3_instance(
188+
void) {
189+
return &btstack_uart_block_ev3;
190+
}
191+
192+
#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3_UART
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
// EV3 UART driver for BlueKitchen BTStack (stubs).
5+
6+
#ifndef _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_
7+
#define _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_
8+
9+
#include <btstack_uart_block.h>
10+
#include <pbdrv/uart.h>
11+
#include <stdint.h>
12+
13+
const btstack_uart_block_t *pbdrv_bluetooth_btstack_uart_block_ev3_instance(
14+
void);
15+
16+
typedef struct {
17+
// The uart device connected to the Bluetooth module.
18+
uint8_t uart_id;
19+
} pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t;
20+
21+
// To be defined in platform/ev3/platform.c
22+
extern const pbdrv_bluetooth_btstack_uart_block_ev3_platform_data_t
23+
pbdrv_bluetooth_btstack_uart_block_ev3_platform_data;
24+
25+
#endif // _INTERNAL_PBDRV_BLUETOOTH_BTSTACK_UART_BLOCK_EV3_H_

lib/pbio/platform/ev3/pbdrvconfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,5 @@
107107

108108
#define PBDRV_CONFIG_WATCHDOG (1)
109109
#define PBDRV_CONFIG_WATCHDOG_EV3 (1)
110+
111+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3_UART (1)

0 commit comments

Comments
 (0)