Support BLE pairing and bonding on ESP
This commit is contained in:
parent
7a27366182
commit
79ef1f73b3
3 changed files with 88 additions and 24 deletions
|
|
@ -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);
|
||||
|
||||
|
|
@ -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();
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue