Skip to content

Commit 857e2c8

Browse files
committed
extmod/modbluetooth: Implement MTU.
1 parent f271b96 commit 857e2c8

File tree

4 files changed

+116
-4
lines changed

4 files changed

+116
-4
lines changed

extmod/btstack/modbluetooth_btstack.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ STATIC void btstack_packet_handler_att_server(uint8_t packet_type, uint16_t chan
264264
uint16_t value_handle = att_event_handle_value_indication_complete_get_attribute_handle(packet);
265265
uint8_t status = att_event_handle_value_indication_complete_get_status(packet);
266266
mp_bluetooth_gatts_on_indicate_complete(conn_handle, value_handle, status);
267+
} else if (event_type == ATT_EVENT_MTU_EXCHANGE_COMPLETE) {
268+
// This is triggered in peripheral mode, when exchange initiated by us or remote.
269+
uint16_t conn_handle = att_event_mtu_exchange_complete_get_handle(packet);
270+
uint16_t mtu = att_event_mtu_exchange_complete_get_MTU(packet);
271+
mp_bluetooth_gatts_on_mtu_exchanged(conn_handle, mtu);
267272
} else if (event_type == HCI_EVENT_LE_META || event_type == HCI_EVENT_DISCONNECTION_COMPLETE) {
268273
// Ignore, duplicated by att_server.c.
269274
} else {
@@ -339,8 +344,6 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
339344
DEBUG_printf(" --> btstack # conns changed\n");
340345
} else if (event_type == HCI_EVENT_VENDOR_SPECIFIC) {
341346
DEBUG_printf(" --> hci vendor specific\n");
342-
} else if (event_type == GATT_EVENT_MTU) {
343-
DEBUG_printf(" --> hci MTU\n");
344347
} else if (event_type == HCI_EVENT_DISCONNECTION_COMPLETE) {
345348
DEBUG_printf(" --> hci disconnect complete\n");
346349
uint16_t conn_handle = hci_event_disconnection_complete_get_connection_handle(packet);
@@ -621,6 +624,9 @@ int mp_bluetooth_init(void) {
621624

622625
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
623626
gatt_client_init();
627+
628+
// We always require explicitly exchanging MTU with ble.gattc_exchange_mtu().
629+
gatt_client_mtu_enable_auto_negotiation(false);
624630
#endif
625631

626632
// Register for HCI events.
@@ -1042,6 +1048,24 @@ int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append
10421048
return mp_bluetooth_gatts_db_resize(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, len, append);
10431049
}
10441050

1051+
int mp_bluetooth_get_preferred_mtu(void) {
1052+
if (!mp_bluetooth_is_active()) {
1053+
mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
1054+
}
1055+
return l2cap_max_le_mtu();
1056+
}
1057+
1058+
int mp_bluetooth_set_preferred_mtu(uint16_t mtu) {
1059+
if (!mp_bluetooth_is_active()) {
1060+
return ERRNO_BLUETOOTH_NOT_ACTIVE;
1061+
}
1062+
l2cap_set_max_le_mtu(mtu);
1063+
if (l2cap_max_le_mtu() != mtu) {
1064+
return MP_EINVAL;
1065+
}
1066+
return 0;
1067+
}
1068+
10451069
int mp_bluetooth_gap_disconnect(uint16_t conn_handle) {
10461070
DEBUG_printf("mp_bluetooth_gap_disconnect\n");
10471071
gap_disconnect(conn_handle);
@@ -1204,6 +1228,14 @@ int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const
12041228

12051229
return btstack_error_to_errno(err);
12061230
}
1231+
1232+
int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) {
1233+
DEBUG_printf("mp_bluetooth_exchange_mtu: conn_handle=%d mtu=%d\n", conn_handle, l2cap_max_le_mtu());
1234+
1235+
gatt_client_send_mtu_negotiation(&btstack_packet_handler_att_server, conn_handle);
1236+
1237+
return 0;
1238+
}
12071239
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
12081240

12091241
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK

extmod/modbluetooth.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
316316
}
317317
case MP_QSTR_rxbuf:
318318
return mp_obj_new_int(self->ringbuf.size);
319+
case MP_QSTR_mtu:
320+
return mp_obj_new_int(mp_bluetooth_get_preferred_mtu());
319321
default:
320322
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
321323
}
@@ -368,6 +370,11 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
368370
m_del(uint8_t, old_irq_data_buf, old_irq_data_alloc);
369371
break;
370372
}
373+
case MP_QSTR_mtu: {
374+
mp_int_t mtu = mp_obj_get_int(e->value);
375+
bluetooth_handle_errno(mp_bluetooth_set_preferred_mtu(mtu));
376+
break;
377+
}
371378
case MP_QSTR_addr_mode: {
372379
mp_int_t addr_mode = mp_obj_get_int(e->value);
373380
mp_bluetooth_set_address_mode(addr_mode);
@@ -770,6 +777,13 @@ STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) {
770777
}
771778
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 5, bluetooth_ble_gattc_write);
772779

780+
STATIC mp_obj_t bluetooth_ble_gattc_exchange_mtu(mp_obj_t self_in, mp_obj_t conn_handle_in) {
781+
(void)self_in;
782+
uint16_t conn_handle = mp_obj_get_int(conn_handle_in);
783+
return bluetooth_handle_errno(mp_bluetooth_gattc_exchange_mtu(conn_handle));
784+
}
785+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gattc_exchange_mtu_obj, bluetooth_ble_gattc_exchange_mtu);
786+
773787
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
774788

775789
// ----------------------------------------------------------------------------
@@ -802,6 +816,7 @@ STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = {
802816
{ MP_ROM_QSTR(MP_QSTR_gattc_discover_descriptors), MP_ROM_PTR(&bluetooth_ble_gattc_discover_descriptors_obj) },
803817
{ MP_ROM_QSTR(MP_QSTR_gattc_read), MP_ROM_PTR(&bluetooth_ble_gattc_read_obj) },
804818
{ MP_ROM_QSTR(MP_QSTR_gattc_write), MP_ROM_PTR(&bluetooth_ble_gattc_write_obj) },
819+
{ MP_ROM_QSTR(MP_QSTR_gattc_exchange_mtu), MP_ROM_PTR(&bluetooth_ble_gattc_exchange_mtu_obj) },
805820
#endif
806821
};
807822
STATIC MP_DEFINE_CONST_DICT(bluetooth_ble_locals_dict, bluetooth_ble_locals_dict_table);
@@ -911,6 +926,9 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) {
911926
} else if (event == MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE) {
912927
// conn_handle, value_handle, status
913928
ringbuf_extract(&o->ringbuf, data_tuple, 2, 1, NULL, 0, NULL, NULL);
929+
} else if (event == MP_BLUETOOTH_IRQ_MTU_EXCHANGED) {
930+
// conn_handle, mtu
931+
ringbuf_extract(&o->ringbuf, data_tuple, 2, 0, NULL, 0, NULL, NULL);
914932
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
915933
} else if (event == MP_BLUETOOTH_IRQ_SCAN_RESULT) {
916934
// addr_type, addr, adv_type, rssi, adv_data
@@ -1184,6 +1202,16 @@ bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_han
11841202
}
11851203
#endif
11861204

1205+
void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
1206+
MICROPY_PY_BLUETOOTH_ENTER
1207+
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
1208+
if (enqueue_irq(o, 2 + 2, MP_BLUETOOTH_IRQ_MTU_EXCHANGED)) {
1209+
ringbuf_put16(&o->ringbuf, conn_handle);
1210+
ringbuf_put16(&o->ringbuf, value);
1211+
}
1212+
schedule_ringbuf(atomic_state);
1213+
}
1214+
11871215
void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len) {
11881216
mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
11891217
mp_bluetooth_gatts_db_entry_t *entry = m_new(mp_bluetooth_gatts_db_entry_t, 1);

extmod/modbluetooth.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#define MP_BLUETOOTH_IRQ_GATTC_NOTIFY (18)
101101
#define MP_BLUETOOTH_IRQ_GATTC_INDICATE (19)
102102
#define MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE (20)
103+
#define MP_BLUETOOTH_IRQ_MTU_EXCHANGED (21)
103104

104105
#define MP_BLUETOOTH_ADDRESS_MODE_PUBLIC (0)
105106
#define MP_BLUETOOTH_ADDRESS_MODE_RANDOM (1)
@@ -131,6 +132,7 @@ _IRQ_GATTC_WRITE_DONE = const(17)
131132
_IRQ_GATTC_NOTIFY = const(18)
132133
_IRQ_GATTC_INDICATE = const(19)
133134
_IRQ_GATTS_INDICATE_DONE = const(20)
135+
_IRQ_MTU_EXCHANGED = const(21)
134136
*/
135137

136138
// Common UUID type.
@@ -212,6 +214,10 @@ int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append
212214
// Disconnect from a central or peripheral.
213215
int mp_bluetooth_gap_disconnect(uint16_t conn_handle);
214216

217+
// Set/get the MTU that we will respond to a MTU exchange with.
218+
int mp_bluetooth_get_preferred_mtu(void);
219+
int mp_bluetooth_set_preferred_mtu(uint16_t mtu);
220+
215221
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
216222
// Start a discovery (scan). Set duration to zero to run continuously.
217223
int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us, bool active_scan);
@@ -236,6 +242,9 @@ int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle);
236242

237243
// Write the value to the remote peripheral.
238244
int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode);
245+
246+
// Initiate MTU exchange for a specific connection using the preferred MTU.
247+
int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle);
239248
#endif
240249

241250
/////////////////////////////////////////////////////////////////////////////
@@ -255,6 +264,9 @@ void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t valu
255264
bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle);
256265
#endif
257266

267+
// Call this when an MTU exchange completes.
268+
void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value);
269+
258270
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
259271
// Notify modbluetooth that scan has finished, either timeout, manually, or by some other action (e.g. connecting).
260272
void mp_bluetooth_gap_on_scan_complete(void);

extmod/nimble/modbluetooth_nimble.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,17 @@ STATIC int gap_event_cb(struct ble_gap_event *event, void *arg) {
288288
// Map "done/ack" to 0, otherwise pass the status directly.
289289
mp_bluetooth_gatts_on_indicate_complete(event->notify_tx.conn_handle, event->notify_tx.attr_handle, event->notify_tx.status == BLE_HS_EDONE ? 0 : event->notify_tx.status);
290290
}
291+
break;
291292
}
292-
}
293293

294+
case BLE_GAP_EVENT_MTU: {
295+
if (event->mtu.channel_id == BLE_L2CAP_CID_ATT) {
296+
DEBUG_printf("gap_event_cb: mtu update: conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
297+
mp_bluetooth_gatts_on_mtu_exchanged(event->mtu.conn_handle, event->mtu.value);
298+
}
299+
break;
300+
}
301+
}
294302
return 0;
295303
}
296304

@@ -637,7 +645,7 @@ int mp_bluetooth_gatts_register_service_begin(bool append) {
637645
return 0;
638646
}
639647

640-
int mp_bluetooth_gatts_register_service_end() {
648+
int mp_bluetooth_gatts_register_service_end(void) {
641649
int ret = ble_gatts_start();
642650
if (ret != 0) {
643651
return ble_hs_err_to_errno(ret);
@@ -769,6 +777,23 @@ int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append
769777
return mp_bluetooth_gatts_db_resize(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, len, append);
770778
}
771779

780+
int mp_bluetooth_get_preferred_mtu(void) {
781+
if (!mp_bluetooth_is_active()) {
782+
mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
783+
}
784+
return ble_att_preferred_mtu();
785+
}
786+
787+
int mp_bluetooth_set_preferred_mtu(uint16_t mtu) {
788+
if (!mp_bluetooth_is_active()) {
789+
return ERRNO_BLUETOOTH_NOT_ACTIVE;
790+
}
791+
if (ble_att_set_preferred_mtu(mtu)) {
792+
return MP_EINVAL;
793+
}
794+
return 0;
795+
}
796+
772797
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
773798

774799
STATIC void gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const struct os_mbuf *om) {
@@ -884,6 +909,14 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
884909
// TODO
885910
break;
886911

912+
case BLE_GAP_EVENT_MTU: {
913+
if (event->mtu.channel_id == BLE_L2CAP_CID_ATT) {
914+
DEBUG_printf("peripheral_gap_event_cb: mtu update: conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id, event->mtu.value);
915+
mp_bluetooth_gatts_on_mtu_exchanged(event->mtu.conn_handle, event->mtu.value);
916+
}
917+
break;
918+
}
919+
887920
default:
888921
break;
889922
}
@@ -1042,6 +1075,13 @@ int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const
10421075
return ble_hs_err_to_errno(err);
10431076
}
10441077

1078+
int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) {
1079+
DEBUG_printf("mp_bluetooth_exchange_mtu: conn_handle=%d mtu=%d\n", conn_handle, ble_att_preferred_mtu());
1080+
1081+
// Using NULL callback (we'll get notified in gap_event_cb instead).
1082+
return ble_hs_err_to_errno(ble_gattc_exchange_mtu(conn_handle, NULL, NULL));
1083+
}
1084+
10451085
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
10461086

10471087
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy