fix CCCD bonding store; avoid excessive bonding writes
This commit is contained in:
parent
346ce3b73b
commit
9e7f8743c2
|
@ -83,29 +83,6 @@ STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC bool characteristic_on_ble_evt(ble_evt_t *ble_evt, void *param) {
|
|
||||||
bleio_characteristic_obj_t *self = (bleio_characteristic_obj_t *) param;
|
|
||||||
switch (ble_evt->header.evt_id) {
|
|
||||||
case BLE_GATTS_EVT_WRITE: {
|
|
||||||
// A client wrote to this server characteristic.
|
|
||||||
// If we are bonded, stored the CCCD value.
|
|
||||||
if (self->service != MP_OBJ_NULL) {
|
|
||||||
bleio_connection_obj_t *connection = self->service->connection;
|
|
||||||
uint16_t conn_handle = bleio_connection_get_conn_handle(connection);
|
|
||||||
if (conn_handle != BLE_CONN_HANDLE_INVALID &&
|
|
||||||
common_hal_bleio_connection_get_paired(connection) &&
|
|
||||||
ble_evt->evt.gatts_evt.params.write.handle == self->cccd_handle) {
|
|
||||||
bonding_save_cccd_info(
|
|
||||||
connection->connection->is_central, conn_handle, connection->connection->ediv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) {
|
void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) {
|
||||||
self->service = service;
|
self->service = service;
|
||||||
self->uuid = uuid;
|
self->uuid = uuid;
|
||||||
|
@ -132,9 +109,6 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
|
||||||
if (initial_value_bufinfo != NULL) {
|
if (initial_value_bufinfo != NULL) {
|
||||||
common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo);
|
common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->handler_entry.next = NULL;
|
|
||||||
//////////////// ble_drv_add_event_handler_entry(&self->handler_entry, characteristic_on_ble_evt, self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) {
|
bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) {
|
||||||
|
@ -288,8 +262,3 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_bleio_characteristic_del(bleio_characteristic_obj_t *self) {
|
|
||||||
// Remove from event handler list, since the evt handler entry is built-in and not a heap object.
|
|
||||||
ble_drv_remove_event_handler(characteristic_on_ble_evt, self);
|
|
||||||
}
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ typedef struct _bleio_characteristic_obj {
|
||||||
bleio_attribute_security_mode_t read_perm;
|
bleio_attribute_security_mode_t read_perm;
|
||||||
bleio_attribute_security_mode_t write_perm;
|
bleio_attribute_security_mode_t write_perm;
|
||||||
bleio_descriptor_obj_t *descriptor_list;
|
bleio_descriptor_obj_t *descriptor_list;
|
||||||
ble_drv_evt_handler_entry_t handler_entry;
|
|
||||||
uint16_t user_desc_handle;
|
uint16_t user_desc_handle;
|
||||||
uint16_t cccd_handle;
|
uint16_t cccd_handle;
|
||||||
uint16_t sccd_handle;
|
uint16_t sccd_handle;
|
||||||
|
|
|
@ -123,6 +123,17 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BLE_GATTS_EVT_WRITE:
|
||||||
|
// A client wrote a value.
|
||||||
|
// If we are bonded and it's a CCCD (UUID 0x2902), store the CCCD value.
|
||||||
|
if (self->conn_handle != BLE_CONN_HANDLE_INVALID &&
|
||||||
|
self->pair_status == PAIR_PAIRED &&
|
||||||
|
ble_evt->evt.gatts_evt.params.write.uuid.type == BLE_UUID_TYPE_BLE &&
|
||||||
|
ble_evt->evt.gatts_evt.params.write.uuid.uuid == 0x2902) {
|
||||||
|
bonding_save_cccd_info(self->is_central, self->conn_handle, self->ediv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
|
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
|
||||||
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -223,7 +234,7 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||||
|
|
||||||
case BLE_GAP_EVT_AUTH_STATUS: { // 0x19
|
case BLE_GAP_EVT_AUTH_STATUS: { // 0x19
|
||||||
CONNECTION_DEBUG_PRINTF("BLE_GAP_EVT_AUTH_STATUS\n");
|
CONNECTION_DEBUG_PRINTF("BLE_GAP_EVT_AUTH_STATUS\n");
|
||||||
// Pairing process completed
|
// Key exchange completed.
|
||||||
ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status;
|
ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status;
|
||||||
self->sec_status = status->auth_status;
|
self->sec_status = status->auth_status;
|
||||||
if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||||
|
@ -264,8 +275,10 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a
|
case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a
|
||||||
CONNECTION_DEBUG_PRINTF("BLE_GAP_EVT_CONN_SEC_UPDATE\n");
|
// We get this both on first-time pairing and on subsequent pairings using stored keys.
|
||||||
ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec;
|
ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec;
|
||||||
|
CONNECTION_DEBUG_PRINTF("BLE_GAP_EVT_CONN_SEC_UPDATE, sm: %d, lv: %d\n",
|
||||||
|
conn_sec->sec_mode.sm, conn_sec->sec_mode.lv);
|
||||||
if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) {
|
if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) {
|
||||||
// Security setup did not succeed:
|
// Security setup did not succeed:
|
||||||
// mode 0, level 0 means no access
|
// mode 0, level 0 means no access
|
||||||
|
@ -282,6 +295,7 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||||
CONNECTION_DEBUG_PRINTF("bonding_load_cccd_info() failed\n");
|
CONNECTION_DEBUG_PRINTF("bonding_load_cccd_info() failed\n");
|
||||||
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
self->pair_status = PAIR_PAIRED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "shared-bindings/_bleio/__init__.h"
|
#include "shared-bindings/_bleio/__init__.h"
|
||||||
#include "shared-bindings/_bleio/Adapter.h"
|
#include "shared-bindings/_bleio/Adapter.h"
|
||||||
#include "shared-bindings/nvm/ByteArray.h"
|
#include "shared-bindings/nvm/ByteArray.h"
|
||||||
|
#include "supervisor/shared/tick.h"
|
||||||
|
|
||||||
#include "nrf_soc.h"
|
#include "nrf_soc.h"
|
||||||
#include "sd_mutex.h"
|
#include "sd_mutex.h"
|
||||||
|
@ -56,8 +57,8 @@ const uint32_t BONDING_FLAG = ('1' | '0' << 8 | 'D' << 16 | 'B' << 24);
|
||||||
// Save both system and user service info.
|
// Save both system and user service info.
|
||||||
#define SYS_ATTR_FLAGS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)
|
#define SYS_ATTR_FLAGS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)
|
||||||
|
|
||||||
STATIC bonding_block_t *bonding_unused_block = NULL;
|
STATIC nrf_mutex_t queued_bonding_block_entries_mutex;
|
||||||
nrf_mutex_t queued_bonding_block_entries_mutex;
|
STATIC uint64_t block_queued_at_ticks_ms = 0;
|
||||||
|
|
||||||
#if BONDING_DEBUG
|
#if BONDING_DEBUG
|
||||||
void bonding_print_block(bonding_block_t *block) {
|
void bonding_print_block(bonding_block_t *block) {
|
||||||
|
@ -79,6 +80,7 @@ STATIC size_t compute_block_size(uint16_t data_length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void bonding_erase_storage(void) {
|
void bonding_erase_storage(void) {
|
||||||
|
BONDING_DEBUG_PRINTF("bonding_erase_storage()\n");
|
||||||
// Erase all pages in the bonding area.
|
// Erase all pages in the bonding area.
|
||||||
for(uint32_t page_address = BONDING_PAGES_START_ADDR;
|
for(uint32_t page_address = BONDING_PAGES_START_ADDR;
|
||||||
page_address < BONDING_PAGES_END_ADDR;
|
page_address < BONDING_PAGES_END_ADDR;
|
||||||
|
@ -90,8 +92,6 @@ void bonding_erase_storage(void) {
|
||||||
uint32_t flag = BONDING_FLAG;
|
uint32_t flag = BONDING_FLAG;
|
||||||
sd_flash_write_sync((uint32_t *) BONDING_START_FLAG_ADDR, &flag, 1);
|
sd_flash_write_sync((uint32_t *) BONDING_START_FLAG_ADDR, &flag, 1);
|
||||||
sd_flash_write_sync((uint32_t *) BONDING_END_FLAG_ADDR, &flag, 1);
|
sd_flash_write_sync((uint32_t *) BONDING_END_FLAG_ADDR, &flag, 1);
|
||||||
// First unused block is at the beginning.
|
|
||||||
bonding_unused_block = (bonding_block_t *) BONDING_DATA_START_ADDR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given NULL to start or block address, return the address of the next valid block.
|
// Given NULL to start or block address, return the address of the next valid block.
|
||||||
|
@ -122,18 +122,16 @@ STATIC bonding_block_t *next_block(bonding_block_t *block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the block with given type and ediv value.
|
// Find the block with given is_central, type and ediv value.
|
||||||
// If type == BLOCK_UNUSED, ediv is ignored and the the sole unused block at the end is returned.
|
// If type == BLOCK_UNUSED, ediv is ignored and the the sole unused block at the end is returned.
|
||||||
// If not found, return NULL.
|
// If not found, return NULL.
|
||||||
STATIC bonding_block_t *find_block_with_keys(bool is_central, bonding_block_type_t type, uint16_t ediv) {
|
STATIC bonding_block_t *find_candidate_block(bool is_central, bonding_block_type_t type, uint16_t ediv) {
|
||||||
bonding_block_t *block = NULL;
|
bonding_block_t *block = NULL;
|
||||||
BONDING_DEBUG_PRINTF("find_block_with_keys(): looking through blocks:\n");
|
|
||||||
while (1) {
|
while (1) {
|
||||||
block = next_block(block);
|
block = next_block(block);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
BONDING_DEBUG_PRINT_BLOCK(block);
|
|
||||||
if (block->type == BLOCK_INVALID) {
|
if (block->type == BLOCK_INVALID) {
|
||||||
// Skip discarded blocks.
|
// Skip discarded blocks.
|
||||||
continue;
|
continue;
|
||||||
|
@ -149,11 +147,22 @@ STATIC bonding_block_t *find_block_with_keys(bool is_central, bonding_block_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get an empty block large enough to store data_length data.
|
||||||
|
STATIC bonding_block_t* find_unused_block(uint16_t data_length) {
|
||||||
|
bonding_block_t *unused_block = find_candidate_block(true, BLOCK_UNUSED, EDIV_INVALID);
|
||||||
|
// If no more room, erase all existing blocks and start over.
|
||||||
|
if (!unused_block ||
|
||||||
|
(uint8_t *) unused_block + compute_block_size(data_length) >= (uint8_t *) BONDING_DATA_END_ADDR) {
|
||||||
|
bonding_erase_storage();
|
||||||
|
unused_block = (bonding_block_t *) BONDING_DATA_START_ADDR;
|
||||||
|
}
|
||||||
|
return unused_block;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the header word to all 0's, to mark the block as invalid.
|
// Set the header word to all 0's, to mark the block as invalid.
|
||||||
// We don't change data_length, so we can still skip over this block.
|
// We don't change data_length, so we can still skip over this block.
|
||||||
STATIC void invalidate_block(bonding_block_t *block) {
|
STATIC void invalidate_block(bonding_block_t *block) {
|
||||||
BONDING_DEBUG_PRINTF("invalidate_block()\n");
|
BONDING_DEBUG_PRINTF("invalidate_block()\n");
|
||||||
BONDING_DEBUG_PRINT_BLOCK(block);
|
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
sd_flash_write_sync((uint32_t *) block, &zero, 1);
|
sd_flash_write_sync((uint32_t *) block, &zero, 1);
|
||||||
}
|
}
|
||||||
|
@ -164,6 +173,10 @@ STATIC void queue_write_block(bool is_central, bonding_block_type_t type, uint16
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No heap available, so never mind. This might be called between VM instantiations.
|
||||||
|
if (!gc_alloc_possible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
queued_bonding_block_entry_t* queued_entry =
|
queued_bonding_block_entry_t* queued_entry =
|
||||||
m_malloc_maybe(sizeof(queued_bonding_block_entry_t) + data_length, false);
|
m_malloc_maybe(sizeof(queued_bonding_block_entry_t) + data_length, false);
|
||||||
|
|
||||||
|
@ -181,31 +194,35 @@ STATIC void queue_write_block(bool is_central, bonding_block_type_t type, uint16
|
||||||
memcpy(&queued_entry->block.data, data, data_length);
|
memcpy(&queued_entry->block.data, data, data_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: blocks are added in LIFO order, for simplicity and speed.
|
||||||
|
// The assumption is that there won't be stale blocks on the
|
||||||
|
// list. The sys_attr blocks don't contain sys_attr data, just a
|
||||||
|
// request to store the latest value. The key blocks are assumed
|
||||||
|
// not to be superseded quickly. If this assumption becomes
|
||||||
|
// invalid, the queue should be changed to FIFO.
|
||||||
|
|
||||||
// Add this new element to the front of the list.
|
// Add this new element to the front of the list.
|
||||||
sd_mutex_acquire_wait(&queued_bonding_block_entries_mutex);
|
sd_mutex_acquire_wait(&queued_bonding_block_entries_mutex);
|
||||||
queued_entry->next = MP_STATE_VM(queued_bonding_block_entries);
|
queued_entry->next = MP_STATE_VM(queued_bonding_block_entries);
|
||||||
MP_STATE_VM(queued_bonding_block_entries) = queued_entry;
|
MP_STATE_VM(queued_bonding_block_entries) = queued_entry;
|
||||||
sd_mutex_release(&queued_bonding_block_entries_mutex);
|
sd_mutex_release(&queued_bonding_block_entries_mutex);
|
||||||
|
|
||||||
|
// Remember when we last queued a block, so we avoid excesive
|
||||||
|
// sys_attr writes.
|
||||||
|
block_queued_at_ticks_ms = supervisor_ticks_ms64();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write bonding block header.
|
// Write bonding block header.
|
||||||
STATIC void write_block_header(bonding_block_t *block) {
|
STATIC void write_block_header(bonding_block_t *dest_block, bonding_block_t *source_block_header) {
|
||||||
// If no more room, erase all existing blocks and start over.
|
sd_flash_write_sync((uint32_t *) dest_block, (uint32_t *) source_block_header, sizeof(bonding_block_t) / 4);
|
||||||
if (bonding_unused_block == NULL ||
|
|
||||||
(uint8_t *) bonding_unused_block + compute_block_size(block->data_length) >=
|
|
||||||
(uint8_t *)BONDING_DATA_END_ADDR) {
|
|
||||||
bonding_erase_storage();
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_flash_write_sync((uint32_t *) bonding_unused_block, (uint32_t *) block, sizeof(bonding_block_t) / 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write variable-length data at end of bonding block.
|
// Write variable-length data at end of bonding block.
|
||||||
STATIC void write_block_data(uint8_t *data, uint16_t data_length) {
|
STATIC void write_block_data(bonding_block_t *dest_block, uint8_t *data, uint16_t data_length) {
|
||||||
// Minimize the number of writes. Datasheet says no more than two writes per word before erasing again.
|
// Minimize the number of writes. Datasheet says no more than two writes per word before erasing again.
|
||||||
|
|
||||||
// Start writing after the current header.
|
// Start writing after the current header.
|
||||||
uint32_t *flash_word_p = (uint32_t *) ((uint8_t *) bonding_unused_block + sizeof(bonding_block_t));
|
uint32_t *flash_word_p = (uint32_t *) ((uint8_t *) dest_block + sizeof(bonding_block_t));
|
||||||
while (1) {
|
while (1) {
|
||||||
uint32_t word = 0xffffffff;
|
uint32_t word = 0xffffffff;
|
||||||
memcpy(&word, data, data_length >= 4 ? 4 : data_length);
|
memcpy(&word, data, data_length >= 4 ? 4 : data_length);
|
||||||
|
@ -218,43 +235,68 @@ STATIC void write_block_data(uint8_t *data, uint16_t data_length) {
|
||||||
// Increment by word size.
|
// Increment by word size.
|
||||||
flash_word_p++;
|
flash_word_p++;
|
||||||
}
|
}
|
||||||
bonding_unused_block = (bonding_block_t *) flash_word_p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC bool write_sys_attr_block(bonding_block_t *block) {
|
STATIC void write_sys_attr_block(bonding_block_t *block) {
|
||||||
BONDING_DEBUG_PRINTF("write_sys_attr_block()\n");
|
|
||||||
uint16_t length = 0;
|
uint16_t length = 0;
|
||||||
// First find out how big a buffer we need, then fetch the data.
|
// First find out how big a buffer we need, then fetch the data.
|
||||||
if(sd_ble_gatts_sys_attr_get(block->conn_handle, NULL, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) {
|
if(sd_ble_gatts_sys_attr_get(block->conn_handle, NULL, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sys_attr[length];
|
uint8_t sys_attr[length];
|
||||||
if(sd_ble_gatts_sys_attr_get(block->conn_handle, sys_attr, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) {
|
if(sd_ble_gatts_sys_attr_get(block->conn_handle, sys_attr, &length, SYS_ATTR_FLAGS) != NRF_SUCCESS) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we know the data size.
|
// Now we know the data size.
|
||||||
block->data_length = length;
|
block->data_length = length;
|
||||||
write_block_header(block);
|
|
||||||
write_block_data(sys_attr, length);
|
// Is there an existing sys_attr block that matches the current sys_attr data?
|
||||||
return true;
|
bonding_block_t *candidate_block = find_candidate_block(block->is_central, block->type, block->ediv);
|
||||||
|
if (candidate_block) {
|
||||||
|
if (length == candidate_block->data_length &&
|
||||||
|
memcmp(sys_attr, candidate_block->data, block->data_length) == 0) {
|
||||||
|
BONDING_DEBUG_PRINTF("Identical sys_attr block already stored.\n");
|
||||||
|
// Identical block found. No need to store again.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Data doesn't match. Invalidate block and store a new one.
|
||||||
|
invalidate_block(candidate_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
bonding_block_t *new_block = find_unused_block(length);
|
||||||
|
write_block_header(new_block, block);
|
||||||
|
write_block_data(new_block, sys_attr, length);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC bool write_keys_block(bonding_block_t *block) {
|
STATIC void write_keys_block(bonding_block_t *block) {
|
||||||
BONDING_DEBUG_PRINTF("write_keys_block()\n");
|
|
||||||
if (block->data_length != sizeof(bonding_keys_t)) {
|
if (block->data_length != sizeof(bonding_keys_t)) {
|
||||||
return false;
|
// Bad length.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there an existing keys block that matches?
|
||||||
|
bonding_block_t *candidate_block = find_candidate_block(block->is_central, block->type, block->ediv);
|
||||||
|
if (candidate_block) {
|
||||||
|
if (block->data_length == candidate_block->data_length &&
|
||||||
|
memcmp(block->data, candidate_block->data, block->data_length) == 0) {
|
||||||
|
BONDING_DEBUG_PRINTF("Identical keys block already stored.\n");
|
||||||
|
// Identical block found. No need to store again.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Data doesn't match. Invalidate block and store a new one.
|
||||||
|
invalidate_block(candidate_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
bonding_keys_t *bonding_keys = (bonding_keys_t *) block->data;
|
bonding_keys_t *bonding_keys = (bonding_keys_t *) block->data;
|
||||||
BONDING_DEBUG_PRINT_KEYS(bonding_keys);
|
|
||||||
block->ediv = block->is_central
|
block->ediv = block->is_central
|
||||||
? bonding_keys->peer_enc.master_id.ediv
|
? bonding_keys->peer_enc.master_id.ediv
|
||||||
: bonding_keys->own_enc.master_id.ediv;
|
: bonding_keys->own_enc.master_id.ediv;
|
||||||
write_block_header(block);
|
bonding_block_t *new_block = find_unused_block(sizeof(bonding_keys_t));
|
||||||
write_block_data((uint8_t *) bonding_keys, sizeof(bonding_keys_t));
|
write_block_header(new_block, block);
|
||||||
return true;
|
write_block_data(new_block, (uint8_t *) bonding_keys, sizeof(bonding_keys_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,8 +311,6 @@ void bonding_reset(void) {
|
||||||
if (BONDING_FLAG != *((uint32_t *) BONDING_START_FLAG_ADDR) ||
|
if (BONDING_FLAG != *((uint32_t *) BONDING_START_FLAG_ADDR) ||
|
||||||
BONDING_FLAG != *((uint32_t *) BONDING_END_FLAG_ADDR)) {
|
BONDING_FLAG != *((uint32_t *) BONDING_END_FLAG_ADDR)) {
|
||||||
bonding_erase_storage();
|
bonding_erase_storage();
|
||||||
} else {
|
|
||||||
bonding_unused_block = find_block_with_keys(true, BLOCK_UNUSED, EDIV_INVALID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +322,19 @@ void bonding_background(void) {
|
||||||
if (!sd_en) {
|
if (!sd_en) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block_queued_at_ticks_ms == 0) {
|
||||||
|
// No writes have been queued yet.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait at least one second before writing a block, to consolidate writes
|
||||||
|
// that will be duplicates.
|
||||||
|
uint64_t current_ticks_ms = supervisor_ticks_ms64();
|
||||||
|
if (current_ticks_ms - block_queued_at_ticks_ms < 1000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get block at front of list.
|
// Get block at front of list.
|
||||||
bonding_block_t *block = NULL;
|
bonding_block_t *block = NULL;
|
||||||
sd_mutex_acquire_wait(&queued_bonding_block_entries_mutex);
|
sd_mutex_acquire_wait(&queued_bonding_block_entries_mutex);
|
||||||
|
@ -292,27 +345,10 @@ void bonding_background(void) {
|
||||||
}
|
}
|
||||||
sd_mutex_release(&queued_bonding_block_entries_mutex);
|
sd_mutex_release(&queued_bonding_block_entries_mutex);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
|
// List is empty.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there an existing block whose keys match?
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_background(): processing queued block:\n");
|
|
||||||
BONDING_DEBUG_PRINT_BLOCK(block);
|
|
||||||
bonding_block_t *block_with_keys = find_block_with_keys(block->is_central, block->type, block->ediv);
|
|
||||||
if (block_with_keys) {
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_background(): block with same keys found:\n");
|
|
||||||
BONDING_DEBUG_PRINT_BLOCK(block_with_keys);
|
|
||||||
if (block->data_length == block_with_keys->data_length &&
|
|
||||||
memcmp(block->data, block_with_keys->data, block->data_length) == 0) {
|
|
||||||
// Identical block found. No need to store again.
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_background(): block is identical to block_with_keys\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Block keys match but data doesn't. Invalidate block and store a new one.
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_background(): invalidating block_with_keys\n");
|
|
||||||
invalidate_block(block_with_keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (block->type) {
|
switch (block->type) {
|
||||||
case BLOCK_SYS_ATTR:
|
case BLOCK_SYS_ATTR:
|
||||||
write_sys_attr_block(block);
|
write_sys_attr_block(block);
|
||||||
|
@ -323,27 +359,23 @@ void bonding_background(void) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BONDING_DEBUG_PRINTF("unknown block type: %x\n", block->type);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bonding_load_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv) {
|
bool bonding_load_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv) {
|
||||||
bonding_block_t *block = find_block_with_keys(is_central, BLOCK_SYS_ATTR, ediv);
|
bonding_block_t *block = find_candidate_block(is_central, BLOCK_SYS_ATTR, ediv);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
BONDING_DEBUG_PRINTF("bonding_load_cccd_info(): block not found, ediv: %04x\n", ediv);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_load_cccd_info(): block found, ediv: %04x\n", ediv);
|
|
||||||
return NRF_SUCCESS ==
|
return NRF_SUCCESS ==
|
||||||
sd_ble_gatts_sys_attr_set(conn_handle, block->data, block->data_length, SYS_ATTR_FLAGS);
|
sd_ble_gatts_sys_attr_set(conn_handle, block->data, block->data_length, SYS_ATTR_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bonding_load_keys(bool is_central, uint16_t ediv, bonding_keys_t *bonding_keys) {
|
bool bonding_load_keys(bool is_central, uint16_t ediv, bonding_keys_t *bonding_keys) {
|
||||||
bonding_block_t *block = find_block_with_keys(is_central, BLOCK_KEYS, ediv);
|
bonding_block_t *block = find_candidate_block(is_central, BLOCK_KEYS, ediv);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
BONDING_DEBUG_PRINTF("bonding_load_keys(): block not found, ediv: %04x\n", ediv);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sizeof(bonding_keys_t) != block->data_length) {
|
if (sizeof(bonding_keys_t) != block->data_length) {
|
||||||
|
@ -351,15 +383,12 @@ bool bonding_load_keys(bool is_central, uint16_t ediv, bonding_keys_t *bonding_k
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BONDING_DEBUG_PRINTF("bonding_load_keys(): block found, ediv: %04x\n", ediv);
|
|
||||||
memcpy(bonding_keys, block->data, block->data_length);
|
memcpy(bonding_keys, block->data, block->data_length);
|
||||||
BONDING_DEBUG_PRINT_KEYS(bonding_keys);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bonding_save_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv) {
|
void bonding_save_cccd_info(bool is_central, uint16_t conn_handle, uint16_t ediv) {
|
||||||
BONDING_DEBUG_PRINTF("bonding_save_cccd_info: is_central: %d, conn_handle: %04x, ediv: %04x\n",
|
BONDING_DEBUG_PRINTF("bonding_save_cccd_info()\n");
|
||||||
is_central, conn_handle, ediv);
|
|
||||||
queue_write_block(is_central, BLOCK_SYS_ATTR, ediv, conn_handle, NULL, 0);
|
queue_write_block(is_central, BLOCK_SYS_ATTR, ediv, conn_handle, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +396,5 @@ void bonding_save_keys(bool is_central, uint16_t conn_handle, bonding_keys_t *bo
|
||||||
uint16_t const ediv = is_central
|
uint16_t const ediv = is_central
|
||||||
? bonding_keys->peer_enc.master_id.ediv
|
? bonding_keys->peer_enc.master_id.ediv
|
||||||
: bonding_keys->own_enc.master_id.ediv;
|
: bonding_keys->own_enc.master_id.ediv;
|
||||||
BONDING_DEBUG_PRINTF("bonding_save_keys: is_central: %d, conn_handle: %04x, ediv: %04x\n",
|
|
||||||
is_central, conn_handle, ediv);
|
|
||||||
queue_write_block(is_central, BLOCK_KEYS, ediv, conn_handle, (uint8_t *) bonding_keys, sizeof(bonding_keys_t));
|
queue_write_block(is_central, BLOCK_KEYS, ediv, conn_handle, (uint8_t *) bonding_keys, sizeof(bonding_keys_t));
|
||||||
}
|
}
|
||||||
|
|
4
py/gc.c
4
py/gc.c
|
@ -464,6 +464,10 @@ void gc_info(gc_info_t *info) {
|
||||||
GC_EXIT();
|
GC_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gc_alloc_possible(void) {
|
||||||
|
return MP_STATE_MEM(gc_pool_start) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
// We place long lived objects at the end of the heap rather than the start. This reduces
|
// We place long lived objects at the end of the heap rather than the start. This reduces
|
||||||
// fragmentation by localizing the heap churn to one portion of memory (the start of the heap.)
|
// fragmentation by localizing the heap churn to one portion of memory (the start of the heap.)
|
||||||
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
|
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
|
||||||
|
|
2
py/gc.h
2
py/gc.h
|
@ -58,6 +58,8 @@ void gc_collect_ptr(void *ptr);
|
||||||
void gc_collect_root(void **ptrs, size_t len);
|
void gc_collect_root(void **ptrs, size_t len);
|
||||||
void gc_collect_end(void);
|
void gc_collect_end(void);
|
||||||
|
|
||||||
|
// Is the gc heap available?
|
||||||
|
bool gc_alloc_possible(void);
|
||||||
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived);
|
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived);
|
||||||
|
|
||||||
// Use this function to sweep the whole heap and run all finalisers
|
// Use this function to sweep the whole heap and run all finalisers
|
||||||
|
|
|
@ -128,8 +128,7 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_
|
||||||
}
|
}
|
||||||
mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ);
|
||||||
|
|
||||||
// There may be some cleanup needed when a characteristic is gc'd, so enable finaliser.
|
bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||||
bleio_characteristic_obj_t *characteristic = m_new_obj_with_finaliser(bleio_characteristic_obj_t);
|
|
||||||
characteristic->base.type = &bleio_characteristic_type;
|
characteristic->base.type = &bleio_characteristic_type;
|
||||||
|
|
||||||
// Range checking on max_length arg is done by the common_hal layer, because
|
// Range checking on max_length arg is done by the common_hal layer, because
|
||||||
|
@ -293,17 +292,7 @@ STATIC mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd);
|
||||||
|
|
||||||
// Cleanup on gc.
|
|
||||||
STATIC mp_obj_t bleio_characteristic_del(mp_obj_t self_in) {
|
|
||||||
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
|
||||||
common_hal_bleio_characteristic_del(self);
|
|
||||||
return mp_const_none;
|
|
||||||
}
|
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_del_obj, bleio_characteristic_del);
|
|
||||||
|
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&bleio_characteristic_del_obj) },
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_properties_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_properties_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) },
|
||||||
|
|
|
@ -45,6 +45,5 @@ extern bleio_descriptor_obj_t *common_hal_bleio_characteristic_get_descriptor_li
|
||||||
extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self);
|
extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self);
|
||||||
extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor);
|
extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor);
|
||||||
extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
|
extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
|
||||||
extern void common_hal_bleio_characteristic_del(bleio_characteristic_obj_t *self);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
|
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
|
||||||
|
|
Loading…
Reference in New Issue