Skip to content

Commit

Permalink
Merge pull request adafruit#9289 from tannewt/esp_ble_bonding
Browse files Browse the repository at this point in the history
Support BLE pairing and bonding on ESP
  • Loading branch information
dhalbert authored Jun 1, 2024
2 parents 7a27366 + 79ef1f7 commit f810f4d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 24 deletions.
41 changes: 31 additions & 10 deletions ports/espressif/common-hal/_bleio/Adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ static void _on_sync(void) {
xTaskNotifyGive(cp_task);
}

// All examples have this. It'd make sense in a header.
void ble_store_config_init(void);

void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) {
const bool is_enabled = common_hal_bleio_adapter_get_enabled(self);

Expand All @@ -93,6 +96,20 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
ble_hs_cfg.sync_cb = _on_sync;
// ble_hs_cfg.store_status_cb = ble_store_util_status_rr;

ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
ble_hs_cfg.sm_bonding = 1;
/* Enable the appropriate bit masks to make sure the keys
* that are needed are exchanged
*/
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;

ble_hs_cfg.sm_mitm = 1;
ble_hs_cfg.sm_sc = 1;
/* Stores the IRK */
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;

ble_svc_gap_init();
ble_svc_gatt_init();
ble_svc_ans_init();
Expand All @@ -115,6 +132,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
connection->conn_handle = BLEIO_HANDLE_INVALID;
}

ble_store_config_init();

cp_task = xTaskGetCurrentTaskHandle();

nimble_port_freertos_init(nimble_host_task);
Expand Down Expand Up @@ -277,10 +296,13 @@ static int _mtu_reply(uint16_t conn_handle,
const struct ble_gatt_error *error,
uint16_t mtu, void *arg) {
bleio_connection_internal_t *connection = (bleio_connection_internal_t *)arg;
if (conn_handle != connection->conn_handle || error->status != 0) {
if (conn_handle != connection->conn_handle) {
return 0;
}
connection->mtu = mtu;
if (error->status == 0) {
connection->mtu = mtu;
}
xTaskNotify(cp_task, conn_handle, eSetValueWithOverwrite);
return 0;
}

Expand Down Expand Up @@ -324,11 +346,11 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) {
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
if (event->connect.status == 0) {
// This triggers an MTU exchange. Its reply will unblock CP.
_new_connection(event->connect.conn_handle);
// Set connections objs back to NULL since we have a new
// connection and need a new tuple.
self->connection_objs = NULL;
xTaskNotify(cp_task, event->connect.conn_handle, eSetValueWithOverwrite);
} else {
xTaskNotify(cp_task, -event->connect.status, eSetValueWithOverwrite);
}
Expand Down Expand Up @@ -663,7 +685,7 @@ bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) {
bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) {
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
bleio_connection_internal_t *connection = &bleio_connections[i];
if (connection->conn_handle != BLEIO_HANDLE_INVALID) {
if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) {
return true;
}
}
Expand All @@ -678,7 +700,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT];
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
bleio_connection_internal_t *connection = &bleio_connections[i];
if (connection->conn_handle != BLEIO_HANDLE_INVALID) {
if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) {
if (connection->connection_obj == mp_const_none) {
connection->connection_obj = bleio_connection_new_from_internal(connection);
}
Expand All @@ -691,14 +713,13 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
}

void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) {
mp_raise_NotImplementedError(NULL);
// bonding_erase_storage();
ble_store_clear();
}

bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) {
mp_raise_NotImplementedError(NULL);
// return bonding_peripheral_bond_count() > 0;
return false;
int count;
ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count);
return count > 0;
}

void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) {
Expand Down
65 changes: 51 additions & 14 deletions ports/espressif/common-hal/_bleio/Connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,31 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in)
}

case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: {
#if CIRCUITPY_VERBOSE_BLE
mp_printf(&mp_plat_print, "TODO connection event: PHY update complete\n");
#endif
// Nothing to do here. CircuitPython doesn't tell the user what PHY
// we're on.
break;
}

case BLE_GAP_EVENT_CONN_UPDATE: {
#if CIRCUITPY_VERBOSE_BLE
mp_printf(&mp_plat_print, "TODO connection event: connection update\n");
#endif
struct ble_gap_conn_desc desc;
int rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
assert(rc == 0);
connection->conn_params_updating = false;
break;
}
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
#if CIRCUITPY_VERBOSE_BLE
mp_printf(&mp_plat_print, "TODO connection event: l2cap update request\n");
#endif
case BLE_GAP_EVENT_ENC_CHANGE: {
struct ble_gap_conn_desc desc;
ble_gap_conn_find(event->enc_change.conn_handle, &desc);
if (desc.sec_state.encrypted) {
connection->pair_status = PAIR_PAIRED;
}
break;
}
case BLE_GAP_EVENT_MTU: {
if (event->mtu.conn_handle != connection->conn_handle) {
return 0;
}
connection->mtu = event->mtu.value;
break;
}

Expand Down Expand Up @@ -113,15 +122,34 @@ void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) {
}

void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) {
// TODO: Implement this.
// We may already be trying to pair if we just reconnected to a peer we're
// bonded with.
while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
}
if (self->pair_status == PAIR_PAIRED) {
return;
}
self->pair_status = PAIR_WAITING;
CHECK_NIMBLE_ERROR(ble_gap_security_initiate(self->conn_handle));
while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
}
if (mp_hal_is_interrupted()) {
return;
}
}

mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) {
// TODO: Implement this.
while (self->conn_params_updating && !mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
}
return 0;
if (mp_hal_is_interrupted()) {
return 0;
}
struct ble_gap_conn_desc desc;
CHECK_NIMBLE_ERROR(ble_gap_conn_find(self->conn_handle, &desc));
return 1.25f * desc.conn_itvl;
}

// Return the current negotiated MTU length, minus overhead.
Expand All @@ -131,7 +159,16 @@ mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_inte

void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) {
self->conn_params_updating = true;
// TODO: Implement this.
struct ble_gap_conn_desc desc;
CHECK_NIMBLE_ERROR(ble_gap_conn_find(self->conn_handle, &desc));
uint16_t interval = new_interval / 1.25f;
struct ble_gap_upd_params updated = {
.itvl_min = interval,
.itvl_max = interval,
.latency = desc.conn_latency,
.supervision_timeout = desc.supervision_timeout
};
CHECK_NIMBLE_ERROR(ble_gap_update_params(self->conn_handle, &updated));
}

static volatile int _last_discovery_status;
Expand Down
6 changes: 6 additions & 0 deletions ports/espressif/common-hal/_bleio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ void check_ble_error(int error_code, const char *file, size_t line) {
return;
}
switch (error_code) {
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Insufficient authentication"));
return;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Insufficient encryption"));
return;
default:
#if CIRCUITPY_VERBOSE_BLE
if (file) {
Expand Down

0 comments on commit f810f4d

Please sign in to comment.