Skip to content

Commit 4002d26

Browse files
committed
pbio/drv/bluetooth_btstack: Allow multiple hosts.
This allows using a secondary device like a phone to monitor the connection.
1 parent 398b627 commit 4002d26

9 files changed

Lines changed: 150 additions & 60 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
- Reduced user stack size to `12 KB` on SPIKE Prime Hub to make it the same as
2020
SPIKE Essential Hub. This frees up some RAM for system resources, and we never
2121
use this much in practice.
22+
- Allow simultaneous USB and up to two Bluetooth connections to SPIKE Prime.
23+
Press the Bluetooth button to allow a connection when already connected.
2224

2325
### Fixed
2426
- Fixed `race=False` ignored in `pybricks.tools.multitask()` ([support#2468]).

lib/pbio/drv/bluetooth/bluetooth_btstack.c

Lines changed: 137 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,42 @@ char pbdrv_bluetooth_hub_name[16] = "Pybricks Hub";
105105

106106
static uint8_t *event_packet;
107107
static const pbdrv_bluetooth_btstack_platform_data_t *pdata = &pbdrv_bluetooth_btstack_platform_data;
108-
static hci_con_handle_t le_con_handle = HCI_CON_HANDLE_INVALID;
109-
static hci_con_handle_t pybricks_con_handle = HCI_CON_HANDLE_INVALID;
110-
static hci_con_handle_t uart_con_handle = HCI_CON_HANDLE_INVALID;
108+
109+
/**
110+
* State of a connected host (Pybricks Code or similar).
111+
*/
112+
typedef struct {
113+
/** Connection handle. */
114+
hci_con_handle_t con_handle;
115+
/** Pybricks service is configured. */
116+
bool pybricks_configured;
117+
/** UART service is configured. */
118+
bool uart_configured;
119+
/** Notification to send when ready. */
120+
btstack_context_callback_registration_t send_request;
121+
/** Notification to send. */
122+
const uint8_t *notification_data;
123+
/** Notification size to send. */
124+
uint16_t notification_size;
125+
/** Notification has been sent. */
126+
bool notification_done;
127+
} pbdrv_bluetooth_btstack_host_connection_t;
128+
129+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
130+
static pbdrv_bluetooth_btstack_host_connection_t host_connections[PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS];
131+
#endif
132+
133+
static pbdrv_bluetooth_btstack_host_connection_t *pbdrv_bluetooth_btstack_get_host_connection(hci_con_handle_t con_handle) {
134+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
135+
for (size_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
136+
pbdrv_bluetooth_btstack_host_connection_t *host = &host_connections[i];
137+
if (host->con_handle == con_handle) {
138+
return host;
139+
}
140+
}
141+
#endif
142+
return NULL;
143+
}
111144

112145
/**
113146
* Converts BTStack error to most appropriate PBIO error.
@@ -132,6 +165,7 @@ static pbio_error_t att_error_to_pbio_error(uint8_t status) {
132165
}
133166

134167
static pbio_pybricks_error_t pybricks_data_received(hci_con_handle_t tx_con_handle, const uint8_t *data, uint16_t size) {
168+
// Treating all incoming host data the same.
135169
if (pbdrv_bluetooth_receive_handler) {
136170
return pbdrv_bluetooth_receive_handler(data, size);
137171
}
@@ -140,7 +174,11 @@ static pbio_pybricks_error_t pybricks_data_received(hci_con_handle_t tx_con_hand
140174
}
141175

142176
static void pybricks_configured(hci_con_handle_t tx_con_handle, uint16_t value) {
143-
pybricks_con_handle = value ? tx_con_handle : HCI_CON_HANDLE_INVALID;
177+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(tx_con_handle);
178+
if (host == NULL) {
179+
return;
180+
}
181+
host->pybricks_configured = !!value;
144182
pbdrv_bluetooth_host_connection_changed();
145183
}
146184

@@ -213,7 +251,15 @@ bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri)
213251
}
214252

215253
bool pbdrv_bluetooth_host_is_connected(void) {
216-
return pybricks_con_handle != HCI_CON_HANDLE_INVALID;
254+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
255+
for (size_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
256+
pbdrv_bluetooth_btstack_host_connection_t *host = &host_connections[i];
257+
if (host->con_handle != HCI_CON_HANDLE_INVALID) {
258+
return true;
259+
}
260+
}
261+
#endif
262+
return false;
217263
}
218264

219265
bool pbdrv_bluetooth_hci_is_enabled(void) {
@@ -228,12 +274,22 @@ static void nordic_spp_packet_handler(uint8_t packet_type, uint16_t channel, uin
228274
}
229275

230276
switch (hci_event_gattservice_meta_get_subevent_code(packet)) {
231-
case GATTSERVICE_SUBEVENT_SPP_SERVICE_CONNECTED:
232-
uart_con_handle = gattservice_subevent_spp_service_connected_get_con_handle(packet);
277+
case GATTSERVICE_SUBEVENT_SPP_SERVICE_CONNECTED: {
278+
uint16_t handle = gattservice_subevent_spp_service_connected_get_con_handle(packet);
279+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(handle);
280+
if (host) {
281+
host->uart_configured = true;
282+
}
233283
break;
234-
case GATTSERVICE_SUBEVENT_SPP_SERVICE_DISCONNECTED:
235-
uart_con_handle = HCI_CON_HANDLE_INVALID;
284+
}
285+
case GATTSERVICE_SUBEVENT_SPP_SERVICE_DISCONNECTED: {
286+
uint16_t handle = gattservice_subevent_spp_service_disconnected_get_con_handle(packet);
287+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(handle);
288+
if (host) {
289+
host->uart_configured = false;
290+
}
236291
break;
292+
}
237293
default:
238294
break;
239295
}
@@ -338,32 +394,42 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
338394
// HCI_ROLE_SLAVE means the connecting device is the central and the hub is the peripheral
339395
// HCI_ROLE_MASTER means the connecting device is the peripheral and the hub is the central.
340396
if (hci_subevent_le_connection_complete_get_role(packet) == HCI_ROLE_SLAVE) {
341-
le_con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
397+
uint16_t handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
398+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(HCI_CON_HANDLE_INVALID);
399+
if (host == NULL) {
400+
DEBUG_PRINT("Warning: more than %d LE connections established.\n", PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS);
401+
break;
402+
}
403+
host->con_handle = handle;
342404

343405
// don't start advertising again on disconnect
344406
gap_advertisements_enable(false);
345407
pbdrv_bluetooth_advertising_state = PBDRV_BLUETOOTH_ADVERTISING_STATE_NONE;
346408
}
347409
break;
348-
case HCI_EVENT_DISCONNECTION_COMPLETE:
410+
case HCI_EVENT_DISCONNECTION_COMPLETE: {
349411
DEBUG_PRINT("HCI_EVENT_DISCONNECTION_COMPLETE\n");
350-
if (hci_event_disconnection_complete_get_connection_handle(packet) == le_con_handle) {
351-
le_con_handle = HCI_CON_HANDLE_INVALID;
352-
pybricks_con_handle = HCI_CON_HANDLE_INVALID;
353-
uart_con_handle = HCI_CON_HANDLE_INVALID;
412+
uint16_t handle = hci_event_disconnection_complete_get_connection_handle(packet);
413+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(handle);
414+
if (host) {
415+
host->con_handle = HCI_CON_HANDLE_INVALID;
416+
host->pybricks_configured = false;
417+
host->uart_configured = false;
354418
pbdrv_bluetooth_host_connection_changed();
419+
DEBUG_PRINT("Host with handle %u disconnected\n", handle);
355420
} else {
356421
for (uint8_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; i++) {
357422
pbdrv_bluetooth_peripheral_t *peri = pbdrv_bluetooth_peripheral_get_by_index(i);
358-
if (peri && hci_event_disconnection_complete_get_connection_handle(packet) == peri->con_handle) {
423+
if (peri && handle == peri->con_handle) {
359424
DEBUG_PRINT("Peripheral %u with handle %u disconnected\n", i, peri->con_handle);
360425
gatt_client_stop_listening_for_characteristic_value_updates(&peri->platform_state->notification);
361426
peri->con_handle = HCI_CON_HANDLE_INVALID;
427+
break;
362428
}
363429
}
364430
}
365431
break;
366-
432+
}
367433
case GAP_EVENT_ADVERTISING_REPORT: {
368434
uint8_t event_type = gap_event_advertising_report_get_advertising_event_type(packet);
369435
uint8_t data_length = gap_event_advertising_report_get_data_length(packet);
@@ -508,7 +574,7 @@ static void init_advertising_data(void) {
508574
}
509575

510576
pbio_error_t pbdrv_bluetooth_start_advertising_func(pbio_os_state_t *state, void *context) {
511-
#if !PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER
577+
#if !PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
512578
return PBIO_ERROR_NOT_SUPPORTED;
513579
#endif
514580

@@ -518,10 +584,10 @@ pbio_error_t pbdrv_bluetooth_start_advertising_func(pbio_os_state_t *state, void
518584

519585
PBIO_OS_ASYNC_BEGIN(state);
520586

521-
// Don't advertise if already connected. BTstack also protects against this,
522-
// but it means we never get the HCI event complete command because it is
523-
// never given.
524-
if (le_con_handle != HCI_CON_HANDLE_INVALID) {
587+
pbdrv_bluetooth_btstack_host_connection_t *host = pbdrv_bluetooth_btstack_get_host_connection(HCI_CON_HANDLE_INVALID);
588+
if (host == NULL) {
589+
// There should be at least one available host connection. Otherwise
590+
// we will never receive the advertise completion event below.
525591
return PBIO_ERROR_INVALID_OP;
526592
}
527593

@@ -551,43 +617,50 @@ pbio_error_t pbdrv_bluetooth_stop_advertising_func(pbio_os_state_t *state, void
551617
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
552618
}
553619

554-
typedef struct {
555-
const uint8_t *data;
556-
uint16_t size;
557-
bool done;
558-
} send_data_t;
559-
620+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
560621
static void pybricks_on_ready_to_send(void *context) {
561-
send_data_t *send = context;
562-
pybricks_service_server_send(pybricks_con_handle, send->data, send->size);
563-
send->done = true;
622+
pbdrv_bluetooth_btstack_host_connection_t *host = context;
623+
pybricks_service_server_send(host->con_handle, host->notification_data, host->notification_size);
624+
host->notification_done = true;
564625
pbio_os_request_poll();
565626
}
627+
#endif
566628

567629
pbio_error_t pbdrv_bluetooth_send_pybricks_value_notification(pbio_os_state_t *state, const uint8_t *data, uint16_t size) {
568-
#if !PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER
569-
return PBIO_ERROR_NOT_SUPPORTED;
570-
#endif
571-
572630
if (!pbdrv_bluetooth_btstack_ble_supported()) {
573631
return PBIO_ERROR_NOT_SUPPORTED;
574632
}
575633

576-
static send_data_t send_data;
634+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
635+
static size_t i;
636+
static pbdrv_bluetooth_btstack_host_connection_t *host;
577637

578-
static btstack_context_callback_registration_t send_request = {
579-
.callback = pybricks_on_ready_to_send,
580-
.context = &send_data,
581-
};
582638
PBIO_OS_ASYNC_BEGIN(state);
583639

584-
send_data.data = data;
585-
send_data.size = size;
586-
send_data.done = false;
587-
pybricks_service_server_request_can_send_now(&send_request, pybricks_con_handle);
588-
PBIO_OS_AWAIT_UNTIL(state, send_data.done);
640+
for (i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
641+
host = &host_connections[i];
642+
if (host->con_handle != HCI_CON_HANDLE_INVALID && host->pybricks_configured) {
643+
host->notification_data = data;
644+
host->notification_size = size;
645+
host->notification_done = false;
646+
pybricks_service_server_request_can_send_now(&host->send_request, host->con_handle);
647+
} else {
648+
// No connection or not configured, don't hold up wait loop below.
649+
host->notification_done = true;
650+
}
651+
}
652+
653+
// Wait for all notifications to be sent. BTstack handles sending
654+
// asynchronously. This loop completes when the slowest one is done.
655+
for (i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
656+
host = &host_connections[i];
657+
PBIO_OS_AWAIT_UNTIL(state, host->notification_done);
658+
}
589659

590660
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
661+
#else
662+
return PBIO_ERROR_NOT_SUPPORTED;
663+
#endif
591664
}
592665

593666
pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *state, void *context) {
@@ -1192,10 +1265,18 @@ pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_ti
11921265
PBIO_OS_ASYNC_BEGIN(state);
11931266

11941267
// Disconnect gracefully if connected to host.
1195-
if (le_con_handle != HCI_CON_HANDLE_INVALID) {
1196-
gap_disconnect(le_con_handle);
1197-
PBIO_OS_AWAIT_UNTIL(state, le_con_handle == HCI_CON_HANDLE_INVALID);
1268+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
1269+
static size_t i;
1270+
static pbdrv_bluetooth_btstack_host_connection_t *host;
1271+
for (i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
1272+
host = &host_connections[i];
1273+
if (host->con_handle == HCI_CON_HANDLE_INVALID) {
1274+
continue;
1275+
}
1276+
gap_disconnect(host->con_handle);
1277+
PBIO_OS_AWAIT_UNTIL(state, host->con_handle == HCI_CON_HANDLE_INVALID);
11981278
}
1279+
#endif
11991280

12001281
// Wait for power off.
12011282
PBIO_OS_AWAIT(state, &sub, bluetooth_btstack_handle_power_control(&sub, HCI_POWER_OFF, HCI_STATE_OFF));
@@ -1341,7 +1422,7 @@ void pbdrv_bluetooth_init_hci(void) {
13411422
// GATT Client setup
13421423
gatt_client_init();
13431424

1344-
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER
1425+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
13451426
// setup ATT server
13461427
att_server_init(profile_data, att_read_callback, NULL);
13471428

@@ -1352,6 +1433,13 @@ void pbdrv_bluetooth_init_hci(void) {
13521433

13531434
pybricks_service_server_init(pybricks_data_received, pybricks_configured);
13541435
nordic_spp_service_server_init(nordic_spp_packet_handler);
1436+
1437+
for (size_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS; i++) {
1438+
pbdrv_bluetooth_btstack_host_connection_t *host = &host_connections[i];
1439+
host->con_handle = HCI_CON_HANDLE_INVALID;
1440+
host->send_request.callback = pybricks_on_ready_to_send;
1441+
host->send_request.context = host;
1442+
}
13551443
#else
13561444
(void)pybricks_data_received;
13571445
(void)att_read_callback;

lib/pbio/drv/bluetooth/pybricks_service_server.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242

4343
#include <pbdrv/config.h>
4444

45-
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER
45+
#if PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS
4646

4747
#define BTSTACK_FILE__ "pybricks_service_server.c"
4848

@@ -168,4 +168,4 @@ int pybricks_service_server_send(hci_con_handle_t con_handle, const uint8_t *dat
168168
return att_server_notify(con_handle, pybricks_command_event_value_handle, data, size);
169169
}
170170

171-
#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER
171+
#endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS

lib/pbio/include/pbdrv/bluetooth.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,8 @@ const char *pbdrv_bluetooth_get_hub_name(void);
285285
const char *pbdrv_bluetooth_get_fw_version(void);
286286

287287
/**
288-
* Tests if a central is connected to the Bluetooth chip and subscribed to
289-
* Pybricks events.
288+
* Tests if at least one central is connected to the Bluetooth chip and
289+
* subscribed to Pybricks events.
290290
*
291291
* @param [in] connection The type of connection of interest.
292292
* @return True if Pybricks host connected, otherwise false.

lib/pbio/platform/essential_hub/pbdrvconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2)
3131
#define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515
3232
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1)
33-
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER (1)
33+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS (1)
3434
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_STM32 (1)
3535
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CC2564C (1)
3636
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND LWP3_HUB_KIND_TECHNIC_SMALL

lib/pbio/platform/ev3/pbdrvconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2)
5151
#define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515
5252
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1)
53-
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER (0)
53+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS (0)
5454
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CLASSIC (1)
5555
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_EV3 (1)
5656
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CC2560X (1)

lib/pbio/platform/prime_hub/pbdrvconfig.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2)
3131
#define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515
3232
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1)
33-
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER (1)
33+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS (2)
3434
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_STM32 (1)
3535
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CC2564C (1)
3636
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND LWP3_HUB_KIND_TECHNIC_LARGE
@@ -119,7 +119,7 @@
119119

120120
#define PBDRV_CONFIG_USB (1)
121121
#define PBDRV_CONFIG_USB_MAX_PACKET_SIZE (64)
122-
#define PBDRV_CONFIG_USB_NUM_BUFFERED_PACKETS (2)
122+
#define PBDRV_CONFIG_USB_NUM_BUFFERED_PACKETS (20)
123123
#define PBDRV_CONFIG_USB_VID LEGO_USB_VID
124124
#define PBDRV_CONFIG_USB_PID 0xFFFF
125125
#define PBDRV_CONFIG_USB_PID_0 LEGO_USB_PID_SPIKE_PRIME
@@ -128,7 +128,7 @@
128128
#define PBDRV_CONFIG_USB_PROD_STR LEGO_USB_PROD_STR_TECHNIC_LARGE_HUB " + Pybricks"
129129
#define PBDRV_CONFIG_USB_STM32F4 (1)
130130
#define PBDRV_CONFIG_USB_STM32F4_HUB_VARIANT_ADDR 0x08007d80
131-
#define PBDRV_CONFIG_USB_CHARGE_ONLY (1)
131+
#define PBDRV_CONFIG_USB_CHARGE_ONLY (0)
132132

133133
#define PBDRV_CONFIG_STACK (1)
134134
#define PBDRV_CONFIG_STACK_EMBEDDED (1)

lib/pbio/platform/test/pbdrvconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#define PBDRV_CONFIG_BLUETOOTH (1)
1111
#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1)
1212
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1)
13-
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE_SERVER (1)
13+
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_NUM_LE_HOSTS (1)
1414
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CC2564C (1)
1515
#define PBDRV_CONFIG_BLUETOOTH_BTSTACK_HUB_KIND 0xff
1616

0 commit comments

Comments
 (0)