Skip to content

Commit 648c1fe

Browse files
committed
pbdrv/bluetooth: Add POSIX btstack for virtualhub.
- Changes pbdrv_bluetooth_btstack_set_chipset to convey all necessary information to set the correct chipset both from the read local version information command as well as events from the USB subsystem. - Adds a POSIX implementation for pbdrv_bluetooth_btstack_set_chipset. This supports the most common Realtek and Broadcom chipsets, which comprise the vast majority of USB dongles. - Sets up the virtualhub platform to use this chipset. - Adjusts the runloop to check for readability and writability of file descriptors, which is required for the libusb transport.
1 parent c96c040 commit 648c1fe

14 files changed

Lines changed: 427 additions & 17 deletions

.vscode/c_cpp_properties.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,11 @@
386386
"${workspaceFolder}/bricks/virtualhub",
387387
"${workspaceFolder}/bricks/virtualhub/build",
388388
"${workspaceFolder}/bricks/virtualhub/build-debug",
389+
"${workspaceFolder}/lib/btstack/chipset/bcm",
390+
"${workspaceFolder}/lib/btstack/chipset/realtek",
391+
"${workspaceFolder}/lib/btstack/platform/libusb",
392+
"${workspaceFolder}/lib/btstack/platform/posix",
393+
"${workspaceFolder}/lib/btstack/src",
389394
"${workspaceFolder}/lib/lego",
390395
"${workspaceFolder}/lib/lwrb/src/include",
391396
"${workspaceFolder}/lib/pbio",

bricks/_common/common.mk

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,18 @@ endif
124124
ifneq ($(strip $(PB_LIB_BTSTACK)),)
125125
INC += -I$(PBTOP)/lib/btstack/chipset/cc256x
126126
INC += -I$(PBTOP)/lib/btstack/src
127+
ifeq ($(PBIO_PLATFORM),virtual_hub)
128+
INC += -I$(PBTOP)/lib/btstack/platform/posix
129+
INC += -I$(PBTOP)/lib/btstack/platform/embedded
130+
INC += -I$(PBTOP)/lib/btstack/3rd-party/tinydir
131+
INC += -I$(PBTOP)/lib/btstack/3rd-party/rijndael
132+
INC += -I$(PBTOP)/lib/btstack/3rd-party/micro-ecc
133+
INC += -I$(PBTOP)/lib/btstack/chipset/bcm
134+
INC += -I$(PBTOP)/lib/btstack/chipset/intel
135+
INC += -I$(PBTOP)/lib/btstack/chipset/realtek
136+
INC += -I$(PBTOP)/lib/btstack/chipset/zephyr
137+
INC += $(shell pkg-config libusb-1.0 --cflags)
138+
endif
127139
endif
128140
ifeq ($(PB_LIB_LSM6DS3TR_C),1)
129141
INC += -I$(PBTOP)/lib/lsm6ds3tr_c_STdC/driver
@@ -162,6 +174,9 @@ else ifeq ($(UNAME_S),Darwin)
162174
LDFLAGS += -Wl,-map,$@.map -Wl,-dead_strip
163175
endif
164176
LIBS = -lm
177+
ifeq ($(PB_LIB_BTSTACK),lowenergy)
178+
LIBS += $(shell pkg-config libusb-1.0 --libs)
179+
endif
165180
else # end native, begin embedded
166181
CROSS_COMPILE ?= arm-none-eabi-
167182
ifeq ($(PB_MCU_FAMILY),STM32)
@@ -395,6 +410,37 @@ BTSTACK_SRC_C += $(addprefix lib/btstack/chipset/cc256x/,\
395410
btstack_chipset_cc256x.c \
396411
)
397412

413+
# libusb-specific BTStack sources for virtual_hub
414+
ifeq ($(PBIO_PLATFORM),virtual_hub)
415+
BTSTACK_SRC_C += $(addprefix lib/btstack/platform/libusb/,\
416+
hci_transport_h2_libusb.c \
417+
)
418+
BTSTACK_SRC_C += $(addprefix lib/btstack/platform/posix/,\
419+
hci_dump_posix_stdout.c \
420+
)
421+
BTSTACK_SRC_C += $(addprefix lib/btstack/src/ble/,\
422+
le_device_db_tlv.c \
423+
)
424+
BTSTACK_SRC_C += $(addprefix lib/btstack/chipset/zephyr/,\
425+
btstack_chipset_zephyr.c \
426+
)
427+
BTSTACK_SRC_C += $(addprefix lib/btstack/chipset/realtek/,\
428+
btstack_chipset_realtek.c \
429+
)
430+
BTSTACK_SRC_C += $(addprefix lib/btstack/chipset/bcm/,\
431+
btstack_chipset_bcm.c \
432+
)
433+
BTSTACK_SRC_C += $(addprefix lib/btstack/chipset/intel/,\
434+
btstack_chipset_intel_firmware.c \
435+
)
436+
BTSTACK_SRC_C += $(addprefix lib/btstack/3rd-party/rijndael/,\
437+
rijndael.c \
438+
)
439+
BTSTACK_SRC_C += $(addprefix lib/btstack/3rd-party/micro-ecc/,\
440+
uECC.c \
441+
)
442+
endif
443+
398444
# STM32 HAL
399445

400446
COPT += -DUSE_FULL_LL_DRIVER
@@ -530,11 +576,13 @@ endif
530576

531577
ifeq ($(PB_LIB_BTSTACK),classic)
532578
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
579+
$(BUILD)/lib/btstack/%.o: CFLAGS += -Wno-error
533580
endif
534581

535582
ifeq ($(PB_LIB_BTSTACK),lowenergy)
536583
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_SRC_C:.c=.o))
537584
OBJ += $(addprefix $(BUILD)/, $(BTSTACK_BLE_SRC_C:.c=.o))
585+
$(BUILD)/lib/btstack/%.o: CFLAGS += -Wno-error
538586
endif
539587

540588
ifeq ($(PB_LIB_STM32_HAL),1)

bricks/_common/sources.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,10 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
114114
drv/block_device/block_device_test.c \
115115
drv/block_device/block_device_w25qxx_stm32.c \
116116
drv/bluetooth/bluetooth.c \
117-
drv/bluetooth/bluetooth_btstack_stm32_hal.c \
118117
drv/bluetooth/bluetooth_btstack.c \
119118
drv/bluetooth/bluetooth_btstack_ev3.c \
119+
drv/bluetooth/bluetooth_btstack_posix.c \
120+
drv/bluetooth/bluetooth_btstack_stm32_hal.c \
120121
drv/bluetooth/bluetooth_simulation.c \
121122
drv/bluetooth/bluetooth_stm32_bluenrg.c \
122123
drv/bluetooth/bluetooth_stm32_cc2640.c \

bricks/virtualhub/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ PB_MCU_FAMILY = native
66
PB_FROZEN_MODULES = 1
77
MICROPY_ROM_TEXT_COMPRESSION = 1
88
PB_LIB_UMM_MALLOC = 1
9+
PB_LIB_BTSTACK = lowenergy
910

1011
include ../_common/common.mk

lib/pbio/drv/bluetooth/bluetooth_btstack.c

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,23 @@
2929
#include "pybricks_service_server.h"
3030
#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE
3131

32+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX
33+
34+
#include <errno.h>
35+
#include <poll.h>
36+
37+
#endif
38+
3239
#ifdef PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND
3340
#define HUB_KIND PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND
3441
#else
3542
#error "PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND is required"
3643
#endif
3744

45+
#ifndef PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX
46+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX 0
47+
#endif
48+
3849
// location of product variant in bootloader flash memory of Technic Large hubs
3950
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_VARIANT_ADDR
4051
#define HUB_VARIANT (*(const uint16_t *)PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_VARIANT_ADDR)
@@ -222,23 +233,39 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
222233
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
223234
#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE
224235

236+
static pbdrv_bluetooth_btstack_device_discriminator device_info;
237+
225238
switch (hci_event_packet_get_type(packet)) {
239+
case HCI_EVENT_TRANSPORT_USB_INFO: {
240+
// Store USB vendor and product IDs for later use
241+
device_info.usb_vendor_id = hci_event_transport_usb_info_get_vendor_id(packet);
242+
device_info.usb_product_id = hci_event_transport_usb_info_get_product_id(packet);
243+
break;
244+
}
226245
case HCI_EVENT_COMMAND_COMPLETE: {
227246
const uint8_t *rp = hci_event_command_complete_get_return_parameters(packet);
228247
switch (hci_event_command_complete_get_command_opcode(packet)) {
229248
case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION: {
230-
uint16_t lmp_pal_subversion = pbio_get_uint16_le(&rp[7]);
231-
pbdrv_bluetooth_btstack_set_chipset(lmp_pal_subversion);
249+
device_info.hci_version = rp[0];
250+
device_info.hci_revision = pbio_get_uint16_le(&rp[1]);
251+
device_info.lmp_pal_version = rp[3];
252+
device_info.manufacturer = pbio_get_uint16_le(&rp[4]);
253+
device_info.lmp_pal_subversion = pbio_get_uint16_le(&rp[6]);
254+
pbdrv_bluetooth_btstack_set_chipset(&device_info);
232255

233256
#if DEBUG
234257
// Show version in ev3dev format.
258+
uint16_t lmp_pal_subversion = device_info.lmp_pal_subversion;
235259
uint16_t chip = (lmp_pal_subversion & 0x7C00) >> 10;
236260
uint16_t min_ver = (lmp_pal_subversion & 0x007F);
237261
uint16_t maj_ver = (lmp_pal_subversion & 0x0380) >> 7;
238262
if (lmp_pal_subversion & 0x8000) {
239263
maj_ver |= 0x0008;
240264
}
241265
DEBUG_PRINT("LMP %04x: TIInit_%d.%d.%d.bts\n", lmp_pal_subversion, chip, maj_ver, min_ver);
266+
(void)maj_ver; // In lib/pbio/test, this variable appears unused even though it's not.
267+
(void)min_ver;
268+
(void)chip;
242269
#endif
243270
break;
244271
}
@@ -1054,6 +1081,13 @@ static void bluetooth_btstack_run_loop_dump_timer(void) {
10541081
// not used
10551082
}
10561083

1084+
static bool do_poll_handler;
1085+
1086+
void pbdrv_bluetooth_btstack_run_loop_trigger(void) {
1087+
do_poll_handler = true;
1088+
pbio_os_request_poll();
1089+
}
1090+
10571091
static const btstack_run_loop_t bluetooth_btstack_run_loop = {
10581092
.init = bluetooth_btstack_run_loop_init,
10591093
.add_data_source = bluetooth_btstack_run_loop_add_data_source,
@@ -1066,14 +1100,10 @@ static const btstack_run_loop_t bluetooth_btstack_run_loop = {
10661100
.execute = bluetooth_btstack_run_loop_execute,
10671101
.dump_timer = bluetooth_btstack_run_loop_dump_timer,
10681102
.get_time_ms = pbdrv_clock_get_ms,
1103+
.poll_data_sources_from_irq = pbdrv_bluetooth_btstack_run_loop_trigger,
10691104
};
10701105

1071-
static bool do_poll_handler;
10721106

1073-
void pbdrv_bluetooth_btstack_run_loop_trigger(void) {
1074-
do_poll_handler = true;
1075-
pbio_os_request_poll();
1076-
}
10771107

10781108
static pbio_os_process_t pbdrv_bluetooth_hci_process;
10791109

@@ -1083,17 +1113,61 @@ static pbio_os_process_t pbdrv_bluetooth_hci_process;
10831113
*/
10841114
static pbio_error_t pbdrv_bluetooth_hci_process_thread(pbio_os_state_t *state, void *context) {
10851115

1086-
if (do_poll_handler) {
1116+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX
1117+
int nfds = btstack_linked_list_count(&data_sources);
1118+
struct pollfd fds[nfds];
1119+
#endif
1120+
1121+
if (do_poll_handler || PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX) {
10871122
do_poll_handler = false;
10881123

10891124
btstack_data_source_t *ds, *next;
1090-
for (ds = (void *)data_sources; ds != NULL; ds = next) {
1125+
int i;
1126+
for (i = 0, ds = (void *)data_sources; ds != NULL; ++i, ds = next) {
10911127
// cache pointer to next data_source to allow data source to remove itself
10921128
next = (void *)ds->item.next;
10931129
if (ds->flags & DATA_SOURCE_CALLBACK_POLL) {
10941130
ds->process(ds, DATA_SOURCE_CALLBACK_POLL);
10951131
}
1132+
1133+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX
1134+
// In POSIX mode we must additionally identify data source FDs that
1135+
// are ready for reading or writing.
1136+
struct pollfd *pfd = &fds[i];
1137+
pfd->fd = ds->source.fd;
1138+
pfd->events = 0;
1139+
if (ds->flags & DATA_SOURCE_CALLBACK_READ) {
1140+
pfd->events |= POLLIN;
1141+
}
1142+
if (ds->flags & DATA_SOURCE_CALLBACK_WRITE) {
1143+
pfd->events |= POLLOUT;
1144+
}
1145+
#endif
1146+
}
1147+
1148+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX
1149+
int err = poll(fds, nfds, 0);
1150+
if (err < 0) {
1151+
DEBUG_PRINT("btstack: poll() returned %d, ignoring\n", errno);
1152+
} else if (err > 0) {
1153+
// Some fd was ready.
1154+
btstack_linked_list_iterator_t it;
1155+
int i;
1156+
for (i = 0, btstack_linked_list_iterator_init(&it, &data_sources);
1157+
btstack_linked_list_iterator_has_next(&it); ++i) {
1158+
btstack_data_source_t *ds = (void *)btstack_linked_list_iterator_next(&it);
1159+
struct pollfd *pfd = &fds[i];
1160+
if (pfd->revents & POLLIN) {
1161+
ds->process(ds, DATA_SOURCE_CALLBACK_READ);
1162+
} else if (pfd->revents & POLLOUT) {
1163+
ds->process(ds, DATA_SOURCE_CALLBACK_WRITE);
1164+
} else if (pfd->revents & POLLERR) {
1165+
DEBUG_PRINT("btstack: poll() error on fd %d\n", pfd->fd);
1166+
}
1167+
}
1168+
10961169
}
1170+
#endif
10971171
}
10981172

10991173
static pbio_os_timer_t btstack_timer = {
@@ -1139,9 +1213,12 @@ void pbdrv_bluetooth_init_hci(void) {
11391213
btstack_run_loop_init(&bluetooth_btstack_run_loop);
11401214

11411215
hci_init(pdata->transport_instance(), pdata->transport_config());
1142-
hci_set_chipset(pdata->chipset_instance());
1216+
if (pdata->chipset_instance != NULL) {
1217+
hci_set_chipset(pdata->chipset_instance());
1218+
}
11431219
hci_set_control(pdata->control_instance());
11441220

1221+
11451222
// REVISIT: do we need to call btstack_chipset_cc256x_set_power() or btstack_chipset_cc256x_set_power_vector()?
11461223

11471224
hci_event_callback_registration.callback = &packet_handler;

lib/pbio/drv/bluetooth/bluetooth_btstack.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,29 @@ typedef struct {
2323

2424
void pbdrv_bluetooth_btstack_run_loop_trigger(void);
2525

26+
typedef struct {
27+
// Only set on POSIX -- these data come from the USB device descriptor.
28+
uint16_t usb_vendor_id;
29+
uint16_t usb_product_id;
30+
31+
// Set on all platforms -- these data come from the
32+
// HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION response.
33+
uint8_t hci_version;
34+
uint16_t hci_revision;
35+
uint8_t lmp_pal_version;
36+
uint16_t manufacturer;
37+
uint16_t lmp_pal_subversion;
38+
39+
} pbdrv_bluetooth_btstack_device_discriminator;
40+
2641
/**
2742
* Hook called when BTstack reads the local version information.
2843
*
2944
* This is called _after_ hci_set_chipset but _before_ the init script is sent
3045
* over the wire, so this can be used to dynamically select the init script.
3146
*/
32-
void pbdrv_bluetooth_btstack_set_chipset(uint16_t lmp_pal_subversion);
47+
void pbdrv_bluetooth_btstack_set_chipset(
48+
pbdrv_bluetooth_btstack_device_discriminator *device_info);
3349

3450
typedef struct {
3551
const hci_transport_t *(*transport_instance)(void);

lib/pbio/drv/bluetooth/bluetooth_btstack_ev3.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,13 @@ static const hci_dump_t bluetooth_btstack_classic_hci_dump = {
6262
.log_packet = pbdrv_hci_dump_log_packet,
6363
.log_message = pbdrv_hci_dump_log_message,
6464
};
65+
6566
#else
6667
#define DEBUG_PRINT(...)
6768
#endif
6869

69-
void pbdrv_bluetooth_btstack_set_chipset(uint16_t lmp_pal_subversion) {
70-
const pbdrv_bluetooth_btstack_chipset_info_t *info = lmp_pal_subversion == cc2560_info.lmp_version ?
70+
void pbdrv_bluetooth_btstack_set_chipset(pbdrv_bluetooth_btstack_device_discriminator *d) {
71+
const pbdrv_bluetooth_btstack_chipset_info_t *info = d->lmp_pal_subversion == cc2560_info.lmp_version ?
7172
&cc2560_info : &cc2560a_info;
7273
btstack_chipset_cc256x_set_init_script((uint8_t *)info->init_script, info->init_script_size);
7374

0 commit comments

Comments
 (0)