Skip to content

Commit 82fb761

Browse files
committed
Add PacketBuffer and MTU negotiation support.
PacketBuffer facilitates packet oriented BLE protocols such as BLE MIDI and the Apple Media Service. This also adds PHY, MTU and connection event extension negotiation to speed up data transfer when possible.
1 parent 776c9b0 commit 82fb761

File tree

14 files changed

+726
-23
lines changed

14 files changed

+726
-23
lines changed

ports/nrf/bluetooth/ble_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ nrf_nvic_state_t nrf_nvic_state = { 0 };
4646
volatile sd_flash_operation_status_t sd_flash_operation_status;
4747

4848
__attribute__((aligned(4)))
49-
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)];
49+
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATTS_VAR_ATTR_LEN_MAX)];
5050

5151
void ble_drv_reset() {
5252
// Linked list items will be gc'd.

ports/nrf/boards/common.template.ld

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ MEMORY
1616
FLASH_FATFS (r) : ORIGIN = ${CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR}, LENGTH = ${CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE}
1717
FLASH_BOOTLOADER (rx) : ORIGIN = ${BOOTLOADER_START_ADDR}, LENGTH = ${BOOTLOADER_SIZE}
1818
FLASH_BOOTLOADER_SETTINGS (r) : ORIGIN = ${BOOTLOADER_SETTINGS_START_ADDR}, LENGTH = ${BOOTLOADER_SETTINGS_SIZE}
19-
RAM (xrw) : ORIGIN = 0x20004000, LENGTH = 0x03C000 /* 240 KiB */
19+
20+
21+
/* 0x2000000 - RAM:ORIGIN is reserved for Softdevice */
22+
/* SoftDevice 6.1.0 takes 0x7b78 bytes (30.86 kb) minimum with high ATT MTU. */
23+
/* To measure the minimum required amount of memory for given configuration, set this number
24+
high enough to work and then check the mutation of the value done by sd_ble_enable. */
25+
RAM (xrw) : ORIGIN = 0x20000000 + 32K, LENGTH = 256K - 32K
2026
}
2127

2228
/* produce a link error if there is not this amount of RAM for these sections */

ports/nrf/common-hal/_bleio/Adapter.c

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) {
6767
reset_into_safe_mode(NORDIC_SOFT_DEVICE_ASSERT);
6868
}
6969

70-
bleio_connection_internal_t connections[BLEIO_TOTAL_CONNECTION_COUNT];
70+
bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];
7171

7272
// Linker script provided ram start.
7373
extern uint32_t _ram_start;
@@ -133,6 +133,15 @@ STATIC uint32_t ble_stack_enable(void) {
133133
return err_code;
134134
}
135135

136+
// Set ATT_MTU so that the maximum MTU we can negotiate is up to the full characteristic size.
137+
memset(&ble_conf, 0, sizeof(ble_conf));
138+
ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM;
139+
ble_conf.conn_cfg.params.gatt_conn_cfg.att_mtu = BLE_GATTS_VAR_ATTR_LEN_MAX;
140+
err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATT, &ble_conf, app_ram_start);
141+
if (err_code != NRF_SUCCESS) {
142+
return err_code;
143+
}
144+
136145
// Triple the GATT Server attribute size to accomodate both the CircuitPython built-in service
137146
// and anything the user does.
138147
memset(&ble_conf, 0, sizeof(ble_conf));
@@ -142,14 +151,29 @@ STATIC uint32_t ble_stack_enable(void) {
142151
return err_code;
143152
}
144153

145-
// TODO set ATT_MTU so that the maximum MTU we can negotiate is higher than the default.
154+
// Increase the number of vendor UUIDs supported. Apple uses a complete random number per
155+
// service and characteristic.
156+
memset(&ble_conf, 0, sizeof(ble_conf));
157+
ble_conf.common_cfg.vs_uuid_cfg.vs_uuid_count = 32; // Defaults to 10.
158+
err_code = sd_ble_cfg_set(BLE_COMMON_CFG_VS_UUID, &ble_conf, app_ram_start);
159+
if (err_code != NRF_SUCCESS) {
160+
return err_code;
161+
}
146162

147163
// This sets app_ram_start to the minimum value needed for the settings set above.
148164
err_code = sd_ble_enable(&app_ram_start);
149165
if (err_code != NRF_SUCCESS) {
150166
return err_code;
151167
}
152168

169+
// Turn on connection event extension so we can transmit for a longer period of time as needed.
170+
ble_opt_t opt;
171+
opt.common_opt.conn_evt_ext.enable = true;
172+
err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
173+
if (err_code != NRF_SUCCESS) {
174+
return err_code;
175+
}
176+
153177
ble_gap_conn_params_t gap_conn_params = {
154178
.min_conn_interval = BLE_MIN_CONN_INTERVAL,
155179
.max_conn_interval = BLE_MAX_CONN_INTERVAL,
@@ -177,7 +201,7 @@ STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
177201
// total connection limit.
178202
bleio_connection_internal_t *connection;
179203
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
180-
connection = &connections[i];
204+
connection = &bleio_connections[i];
181205
if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) {
182206
break;
183207
}
@@ -189,6 +213,7 @@ STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
189213
connection->conn_handle = ble_evt->evt.gap_evt.conn_handle;
190214
connection->connection_obj = mp_const_none;
191215
connection->pair_status = PAIR_NOT_PAIRED;
216+
connection->mtu = 0;
192217

193218
ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection);
194219
self->connection_objs = NULL;
@@ -216,7 +241,7 @@ STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
216241
// Find the connection that was disconnected.
217242
bleio_connection_internal_t *connection;
218243
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
219-
connection = &connections[i];
244+
connection = &bleio_connections[i];
220245
if (connection->conn_handle == ble_evt->evt.gap_evt.conn_handle) {
221246
break;
222247
}
@@ -293,7 +318,7 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
293318
// Add a handler for incoming peripheral connections.
294319
if (enabled) {
295320
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
296-
bleio_connection_internal_t *connection = &connections[i];
321+
bleio_connection_internal_t *connection = &bleio_connections[i];
297322
connection->conn_handle = BLE_CONN_HANDLE_INVALID;
298323
}
299324
bleio_adapter_reset_name(self);
@@ -497,14 +522,25 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre
497522

498523
ble_drv_remove_event_handler(connect_on_ble_evt, &event_info);
499524

500-
if (event_info.conn_handle == BLE_CONN_HANDLE_INVALID) {
525+
uint16_t conn_handle = event_info.conn_handle;
526+
if (conn_handle == BLE_CONN_HANDLE_INVALID) {
501527
mp_raise_bleio_BluetoothError(translate("Failed to connect: timeout"));
502528
}
503529

530+
// Negotiate for better PHY, larger MTU and data lengths since we are the central. These are
531+
// nice-to-haves so ignore any errors.
532+
ble_gap_phys_t const phys = {
533+
.rx_phys = BLE_GAP_PHY_AUTO,
534+
.tx_phys = BLE_GAP_PHY_AUTO,
535+
};
536+
sd_ble_gap_phy_update(conn_handle, &phys);
537+
sd_ble_gattc_exchange_mtu_request(conn_handle, BLE_GATTS_VAR_ATTR_LEN_MAX);
538+
sd_ble_gap_data_length_update(conn_handle, NULL, NULL);
539+
504540
// Make the connection object and return it.
505541
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
506-
bleio_connection_internal_t *connection = &connections[i];
507-
if (connection->conn_handle == event_info.conn_handle) {
542+
bleio_connection_internal_t *connection = &bleio_connections[i];
543+
if (connection->conn_handle == conn_handle) {
508544
return bleio_connection_new_from_internal(connection);
509545
}
510546
}
@@ -628,7 +664,7 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) {
628664

629665
bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) {
630666
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
631-
bleio_connection_internal_t *connection = &connections[i];
667+
bleio_connection_internal_t *connection = &bleio_connections[i];
632668
if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
633669
return true;
634670
}
@@ -643,7 +679,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
643679
size_t total_connected = 0;
644680
mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT];
645681
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
646-
bleio_connection_internal_t *connection = &connections[i];
682+
bleio_connection_internal_t *connection = &bleio_connections[i];
647683
if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
648684
if (connection->connection_obj == mp_const_none) {
649685
connection->connection_obj = bleio_connection_new_from_internal(connection);
@@ -658,15 +694,15 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
658694

659695
void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) {
660696
gc_collect_root((void**)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t));
661-
gc_collect_root((void**)connections, sizeof(connections) / sizeof(size_t));
697+
gc_collect_root((void**)bleio_connections, sizeof(bleio_connections) / sizeof(size_t));
662698
}
663699

664700
void bleio_adapter_reset(bleio_adapter_obj_t* adapter) {
665701
common_hal_bleio_adapter_stop_scan(adapter);
666702
common_hal_bleio_adapter_stop_advertising(adapter);
667703
adapter->connection_objs = NULL;
668704
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
669-
bleio_connection_internal_t *connection = &connections[i];
705+
bleio_connection_internal_t *connection = &bleio_connections[i];
670706
connection->connection_obj = mp_const_none;
671707
}
672708
}

ports/nrf/common-hal/_bleio/Adapter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
#define BLEIO_TOTAL_CONNECTION_COUNT 2
3939

40-
extern bleio_connection_internal_t connections[BLEIO_TOTAL_CONNECTION_COUNT];
40+
extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];
4141

4242
typedef struct {
4343
mp_obj_base_t base;

ports/nrf/common-hal/_bleio/Characteristic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self,
154154
common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo);
155155
// Check to see if we need to notify or indicate any active connections.
156156
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
157-
bleio_connection_internal_t *connection = &connections[i];
157+
bleio_connection_internal_t *connection = &bleio_connections[i];
158158
uint16_t conn_handle = connection->conn_handle;
159159
if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) {
160160
continue;

ports/nrf/common-hal/_bleio/Connection.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
8585
switch (ble_evt->header.evt_id) {
8686
case BLE_GAP_EVT_DISCONNECTED:
8787
break;
88+
8889
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
8990
ble_gap_phys_t const phys = {
9091
.rx_phys = BLE_GAP_PHY_AUTO,
@@ -94,20 +95,45 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
9495
break;
9596
}
9697

97-
case BLE_GAP_EVT_PHY_UPDATE: // 0x22
98+
case BLE_GAP_EVT_PHY_UPDATE: { // 0x22
9899
break;
100+
}
99101

100102
case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
101103
// SoftDevice will respond to a length update request.
102104
sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL);
103105
break;
104106

105-
case BLE_GAP_EVT_DATA_LENGTH_UPDATE: // 0x24
107+
case BLE_GAP_EVT_DATA_LENGTH_UPDATE: { // 0x24
106108
break;
109+
}
107110

108111
case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: {
109-
// We only handle MTU of size BLE_GATT_ATT_MTU_DEFAULT.
110-
sd_ble_gatts_exchange_mtu_reply(self->conn_handle, BLE_GATT_ATT_MTU_DEFAULT);
112+
ble_gatts_evt_exchange_mtu_request_t *request =
113+
&ble_evt->evt.gatts_evt.params.exchange_mtu_request;
114+
115+
uint16_t new_mtu = BLE_GATTS_VAR_ATTR_LEN_MAX;
116+
if (request->client_rx_mtu < new_mtu) {
117+
new_mtu = request->client_rx_mtu;
118+
}
119+
if (new_mtu < BLE_GATT_ATT_MTU_DEFAULT) {
120+
new_mtu = BLE_GATT_ATT_MTU_DEFAULT;
121+
}
122+
if (self->mtu > 0) {
123+
new_mtu = self->mtu;
124+
}
125+
126+
self->mtu = new_mtu;
127+
sd_ble_gatts_exchange_mtu_reply(self->conn_handle, new_mtu);
128+
break;
129+
}
130+
131+
132+
case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: {
133+
ble_gattc_evt_exchange_mtu_rsp_t *response =
134+
&ble_evt->evt.gattc_evt.params.exchange_mtu_rsp;
135+
136+
self->mtu = response->server_rx_mtu;
111137
break;
112138
}
113139

@@ -319,8 +345,11 @@ STATIC bool discover_next_services(bleio_connection_internal_t* connection, uint
319345
m_discovery_successful = false;
320346
m_discovery_in_process = true;
321347

322-
check_nrf_error(sd_ble_gattc_primary_services_discover(connection->conn_handle,
323-
start_handle, service_uuid));
348+
uint32_t nrf_err = NRF_ERROR_BUSY;
349+
while (nrf_err == NRF_ERROR_BUSY) {
350+
nrf_err = sd_ble_gattc_primary_services_discover(connection->conn_handle, start_handle, service_uuid);
351+
}
352+
check_nrf_error(nrf_err);
324353

325354
// Wait for a discovery event.
326355
while (m_discovery_in_process) {

ports/nrf/common-hal/_bleio/Connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ typedef struct {
6565
ble_drv_evt_handler_entry_t handler_entry;
6666
ble_gap_conn_params_t conn_params;
6767
volatile bool conn_params_updating;
68+
uint16_t mtu;
6869
} bleio_connection_internal_t;
6970

7071
typedef struct {

0 commit comments

Comments
 (0)