ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode) { // use default and updated parameters as starting point // and modify structure based on security mode. ret_code_t rc; switch (securityMode) { case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK: /**< Require no protection, open link. */ securityParameters.bond = false; securityParameters.mitm = false; securityParameters.kdist_own.enc = 0; break; case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM: /**< Require encryption, but no MITM protection. */ securityParameters.bond = true; securityParameters.mitm = false; securityParameters.kdist_own.enc = 1; break; // not yet implemented security modes case SecurityManager::SECURITY_MODE_NO_ACCESS: case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM: /**< Require encryption and MITM protection. */ case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM: /**< Require signing or encryption, but no MITM protection. */ case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM: /**< Require signing or encryption, and MITM protection. */ default: return BLE_ERROR_NOT_IMPLEMENTED; } // update security settings for given connection rc = pm_sec_params_set(&securityParameters); if (rc == NRF_SUCCESS) { rc = pm_conn_secure(connectionHandle, false); } switch (rc) { case NRF_SUCCESS: initialized = true; return BLE_ERROR_NONE; case NRF_ERROR_INVALID_STATE: return BLE_ERROR_INVALID_STATE; case NRF_ERROR_INVALID_PARAM: return BLE_ERROR_INVALID_PARAM; default: return BLE_ERROR_UNSPECIFIED; } }
/**@brief Function for handling the Security Request timer timeout. * * @details This function will be called each time the Security Request timer expires. * * @param[in] p_context Pointer used for passing some arbitrary information (context) from the * app_start_timer() call to the timeout handler. */ static void sec_req_timeout_handler(void * p_context) { uint32_t err_code; if (m_conn_handle != BLE_CONN_HANDLE_INVALID) { // Initiate bonding. NRF_LOG_DEBUG("Start encryption\r\n"); err_code = pm_conn_secure(m_conn_handle, false); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } } }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch(p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: NRF_LOG_PRINTF("PM_EVT_BONDED_PEER_CONNECTED: peer_id=%d\n", p_evt->peer_id); err_code = pm_peer_rank_highest(p_evt->peer_id); NRF_LOG_PRINTF("peer_rank err_code: %d\r\n", err_code); break; case PM_EVT_CONN_SEC_START: NRF_LOG_PRINTF("PM_EVT_CONN_SEC_START: peer_id=%d\n", p_evt->peer_id); break; case PM_EVT_CONN_SEC_SUCCEEDED: NRF_LOG_PRINTF("PM_EVT_CONN_SEC_SUCCEEDED Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); err_code = pm_peer_rank_highest(p_evt->peer_id); NRF_LOG_PRINTF("peer_rank err_code: %d\r\n", err_code); break; case PM_EVT_CONN_SEC_FAILED: NRF_LOG_PRINTF("PM_EVT_CONN_SEC_FAILED: peer_id=%d, error=%d\n", p_evt->peer_id, p_evt->params.conn_sec_failed.error); switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; default: break; } break; case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } case PM_EVT_STORAGE_FULL: // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } break; case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break; case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: NRF_LOG_PRINTF("PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: peer_id=%d data_id=0x%x action=0x%x\n", p_evt->peer_id, p_evt->params.peer_data_update_succeeded.data_id, p_evt->params.peer_data_update_succeeded.action); break; case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break; case PM_EVT_PEER_DELETE_SUCCEEDED: break; case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break; case PM_EVT_PEERS_DELETE_SUCCEEDED: adv_scan_start(); break; case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break; case PM_EVT_LOCAL_DB_CACHE_APPLIED: break; case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break; case PM_EVT_SERVICE_CHANGED_IND_SENT: break; case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break; } } /**@brief Handles events coming from the Heart Rate central module. */ static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt) { switch (p_hrs_c_evt->evt_type) { case BLE_HRS_C_EVT_DISCOVERY_COMPLETE: { if (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID) { ret_code_t err_code; m_conn_handle_hrs_c = p_hrs_c_evt->conn_handle; NRF_LOG_PRINTF("HRS discovered on conn_handle 0x%x\r\n", m_conn_handle_hrs_c); err_code = ble_hrs_c_handles_assign(p_hrs_c, m_conn_handle_hrs_c, &p_hrs_c_evt->params.peer_db); APP_ERROR_CHECK(err_code); // Initiate bonding. err_code = pm_conn_secure(m_conn_handle_hrs_c, false); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } // Heart rate service discovered. Enable notification of Heart Rate Measurement. err_code = ble_hrs_c_hrm_notif_enable(p_hrs_c); APP_ERROR_CHECK(err_code); } } break; // BLE_HRS_C_EVT_DISCOVERY_COMPLETE case BLE_HRS_C_EVT_HRM_NOTIFICATION: { NRF_LOG_PRINTF("Heart Rate = %d\r\n", p_hrs_c_evt->params.hrm.hr_value); } break; // BLE_HRS_C_EVT_HRM_NOTIFICATION default: // No implementation needed. break; } } /**@brief Function for searching a given name in the advertisement packets. * * @details Use this function to parse received advertising data and to find a given * name in them either as 'complete_local_name' or as 'short_local_name'. * * @param[in] p_adv_report advertising data to parse. * @param[in] name_to_find name to search. * @return true if the given name was found, false otherwise. */ static bool find_adv_name(const ble_gap_evt_adv_report_t *p_adv_report, const char * name_to_find) { uint32_t err_code; data_t adv_data; data_t dev_name; // Initialize advertisement report for parsing adv_data.p_data = (uint8_t *)p_adv_report->data; adv_data.data_len = p_adv_report->dlen; //search for advertising names err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &adv_data, &dev_name); if (err_code == NRF_SUCCESS) { if(memcmp(name_to_find, dev_name.p_data, dev_name.data_len )== 0) { return true; } } else { // Look for the short local name if it was not found as complete err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, &adv_data, &dev_name); if (err_code != NRF_SUCCESS) { return false; } if(memcmp(m_target_periph_name, dev_name.p_data, dev_name.data_len )== 0) { return true; } } return false; }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_DEBUG("Connected to previously bonded device\r\n"); m_peer_id = p_evt->peer_id; err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break;//PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_DEBUG("Link secured. Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } if (p_evt->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING) { NRF_LOG_DEBUG("New Bond, add the peer to the whitelist if possible\r\n"); NRF_LOG_DEBUG("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d\r\n", m_whitelist_peer_cnt + 1, BLE_GAP_WHITELIST_ADDR_MAX_COUNT); if (m_whitelist_peer_cnt < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) { //bonded to a new peer, add it to the whitelist. m_whitelist_peers[m_whitelist_peer_cnt++] = m_peer_id; m_is_wl_changed = true; } } }break;//PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; default: break; } }break;//PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); }break;//PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } break;//PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // A likely fatal error occurred. Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break;//PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break;//PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error); break;//PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break;//PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break;//PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: break;//PM_EVT_PEERS_DELETE_SUCCEEDED case PM_EVT_PEERS_DELETE_FAILED: APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break;//PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break;//PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break;//PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break;//PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break;//PM_EVT_SERVICE_CHANGED_IND_CONFIRMED default: // No implementation needed. break; } } /**@brief Function for the Peer Manager initialization. * * @param[in] erase_bonds Indicates whether bonding information should be cleared from * persistent storage during initialization of the Peer Manager. */ static void peer_manager_init(bool erase_bonds) { ble_gap_sec_params_t sec_param; ret_code_t err_code; err_code = pm_init(); APP_ERROR_CHECK(err_code); if (erase_bonds) { err_code = pm_peers_delete(); APP_ERROR_CHECK(err_code); } memset(&sec_param, 0, sizeof(ble_gap_sec_params_t)); // Security parameters to be used for all security procedures. sec_param.bond = SEC_PARAM_BOND; sec_param.mitm = SEC_PARAM_MITM; sec_param.lesc = SEC_PARAM_LESC; sec_param.keypress = SEC_PARAM_KEYPRESS; sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES; sec_param.oob = SEC_PARAM_OOB; sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE; sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE; sec_param.kdist_own.enc = 1; sec_param.kdist_own.id = 1; sec_param.kdist_peer.enc = 1; sec_param.kdist_peer.id = 1; err_code = pm_sec_params_set(&sec_param); APP_ERROR_CHECK(err_code); err_code = pm_register(pm_evt_handler); APP_ERROR_CHECK(err_code); }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_DEBUG("Connected to previously bonded device\r\n"); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break; // PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_DEBUG("Link secured. Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; // PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING default: break; } } break; // PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; // PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break; // PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break; // PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break; // PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break; // PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break; // PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: advertising_start(); break; // PM_EVT_PEERS_DELETE_SUCCEEDED case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break; // PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break; // PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break; // PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break; // PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break; // PM_EVT_SERVICE_CHANGED_IND_SENT default: // No implementation needed. break; } } /**@brief Function for performing battery measurement and updating the Battery Level characteristic * in Battery Service. */ static void battery_level_update(void) { uint32_t err_code; uint8_t battery_level; battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg); err_code = ble_bas_battery_level_update(&m_bas, battery_level); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_NO_TX_PACKETS) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_HANDLER(err_code); } }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } break; // PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break; // PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_INFO("Link secured. Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break; // PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING default: break; } } break; // PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; // PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } } break; // PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break; // PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break; // PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break; // PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break; // PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break; // PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: advertising_start(); break; // PM_EVT_PEERS_DELETE_SUCCEEDED case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break; // PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break; // PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break; // PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break; // PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break; // PM_EVT_SERVICE_CHANGED_IND_CONFIRMED default: // No implementation needed. break; } } /**@brief Function for handling the security request timer time-out. * * @details This function is called each time the security request timer expires. * * @param[in] p_context Pointer used for passing context information from the * app_start_timer() call to the time-out handler. */ static void sec_req_timeout_handler(void * p_context) { uint32_t err_code; pm_conn_sec_status_t status; if (m_cur_conn_handle != BLE_CONN_HANDLE_INVALID) { err_code = pm_conn_sec_status_get(m_cur_conn_handle, &status); APP_ERROR_CHECK(err_code); // If the link is still not secured by the peer, initiate security procedure. if (!status.encrypted) { NRF_LOG_INFO("Start encryption\r\n"); err_code = pm_conn_secure(m_cur_conn_handle, false); APP_ERROR_CHECK(err_code); } } }
/**@brief Function for handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch(p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_PRINTF_DEBUG("Connected to previously bonded device\r\n"); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_BONDED_PEER_CONNECTED case PM_EVT_CONN_SEC_START: break;//PM_EVT_CONN_SEC_START case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_PRINTF("Link secured. Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); err_code = pm_peer_rank_highest(p_evt->peer_id); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_CONN_SEC_SUCCEEDED case PM_EVT_CONN_SEC_FAILED: { /** In some cases, when securing fails, it can be restarted directly. Sometimes it can * be restarted, but only after changing some Security Parameters. Sometimes, it cannot * be restarted until the link is disconnected and reconnected. Sometimes it is * impossible, to secure the link, or the peer device does not support it. How to * handle this error is highly application dependent. */ switch (p_evt->params.conn_sec_failed.error) { case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING: // Rebond if one party has lost its keys. err_code = pm_conn_secure(p_evt->conn_handle, true); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } break;//PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING default: break; } }break;//PM_EVT_CONN_SEC_FAILED case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); }break;//PM_EVT_CONN_SEC_CONFIG_REQ case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } }break;//PM_EVT_STORAGE_FULL case PM_EVT_ERROR_UNEXPECTED: // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); break;//PM_EVT_ERROR_UNEXPECTED case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: break;//PM_EVT_PEER_DATA_UPDATE_SUCCEEDED case PM_EVT_PEER_DATA_UPDATE_FAILED: // Assert. APP_ERROR_CHECK_BOOL(false); break;//PM_EVT_PEER_DATA_UPDATE_FAILED case PM_EVT_PEER_DELETE_SUCCEEDED: break;//PM_EVT_PEER_DELETE_SUCCEEDED case PM_EVT_PEER_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); break;//PM_EVT_PEER_DELETE_FAILED case PM_EVT_PEERS_DELETE_SUCCEEDED: adv_scan_start(); break;//PM_EVT_PEERS_DELETE_SUCCEEDED case PM_EVT_PEERS_DELETE_FAILED: // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); break;//PM_EVT_PEERS_DELETE_FAILED case PM_EVT_LOCAL_DB_CACHE_APPLIED: break;//PM_EVT_LOCAL_DB_CACHE_APPLIED case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); break;//PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED case PM_EVT_SERVICE_CHANGED_IND_SENT: break;//PM_EVT_SERVICE_CHANGED_IND_SENT case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: break;//PM_EVT_SERVICE_CHANGED_IND_CONFIRMED default: // No implementation needed. break; } } /**@brief Handles events coming from the Heart Rate central module. */ static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt) { switch (p_hrs_c_evt->evt_type) { case BLE_HRS_C_EVT_DISCOVERY_COMPLETE: { if (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID) { ret_code_t err_code; m_conn_handle_hrs_c = p_hrs_c_evt->conn_handle; NRF_LOG_PRINTF("HRS discovered on conn_handle 0x%x\r\n", m_conn_handle_hrs_c); err_code = ble_hrs_c_handles_assign(p_hrs_c, m_conn_handle_hrs_c, &p_hrs_c_evt->params.peer_db); APP_ERROR_CHECK(err_code); // Initiate bonding. err_code = pm_conn_secure(m_conn_handle_hrs_c, false); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } // Heart rate service discovered. Enable notification of Heart Rate Measurement. err_code = ble_hrs_c_hrm_notif_enable(p_hrs_c); APP_ERROR_CHECK(err_code); } } break; // BLE_HRS_C_EVT_DISCOVERY_COMPLETE case BLE_HRS_C_EVT_HRM_NOTIFICATION: { ret_code_t err_code; NRF_LOG_PRINTF("Heart Rate = %d\r\n", p_hrs_c_evt->params.hrm.hr_value); err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, p_hrs_c_evt->params.hrm.hr_value); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_NO_TX_PACKETS) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_HANDLER(err_code); } } break; // BLE_HRS_C_EVT_HRM_NOTIFICATION default: // No implementation needed. break; } } /**@brief Handles events coming from Running Speed and Cadence central module. */ static void rscs_c_evt_handler(ble_rscs_c_t * p_rscs_c, ble_rscs_c_evt_t * p_rscs_c_evt) { switch (p_rscs_c_evt->evt_type) { case BLE_RSCS_C_EVT_DISCOVERY_COMPLETE: { if (m_conn_handle_rscs_c == BLE_CONN_HANDLE_INVALID) { ret_code_t err_code; m_conn_handle_rscs_c = p_rscs_c_evt->conn_handle; NRF_LOG_PRINTF("Running Speed and Cadence service discovered on conn_handle 0x%x\r\n", m_conn_handle_rscs_c); err_code = ble_rscs_c_handles_assign(p_rscs_c, m_conn_handle_rscs_c, &p_rscs_c_evt->params.rscs_db); APP_ERROR_CHECK(err_code); // Initiate bonding. err_code = pm_conn_secure(m_conn_handle_rscs_c, false); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } // Running speed cadence service discovered. Enable notifications. err_code = ble_rscs_c_rsc_notif_enable(p_rscs_c); APP_ERROR_CHECK(err_code); } } break; // BLE_RSCS_C_EVT_DISCOVERY_COMPLETE: case BLE_RSCS_C_EVT_RSC_NOTIFICATION: { uint32_t err_code; ble_rscs_meas_t rscs_measurment; NRF_LOG_PRINTF("Speed = %d\r\n", p_rscs_c_evt->params.rsc.inst_speed); rscs_measurment.is_running = p_rscs_c_evt->params.rsc.is_running; rscs_measurment.is_inst_stride_len_present = p_rscs_c_evt->params.rsc.is_inst_stride_len_present; rscs_measurment.is_total_distance_present = p_rscs_c_evt->params.rsc.is_total_distance_present; rscs_measurment.inst_stride_length = p_rscs_c_evt->params.rsc.inst_stride_length; rscs_measurment.inst_cadence = p_rscs_c_evt->params.rsc.inst_cadence; rscs_measurment.inst_speed = p_rscs_c_evt->params.rsc.inst_speed; rscs_measurment.total_distance = p_rscs_c_evt->params.rsc.total_distance; err_code = ble_rscs_measurement_send(&m_rscs, &rscs_measurment); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_NO_TX_PACKETS) && (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) ) { APP_ERROR_HANDLER(err_code); } } break; // BLE_RSCS_C_EVT_RSC_NOTIFICATION default: // No implementation needed. break; } } /**@brief Function for searching a given name in the advertisement packets. * * @details Use this function to parse received advertising data and to find a given * name in them either as 'complete_local_name' or as 'short_local_name'. * * @param[in] p_adv_report advertising data to parse. * @param[in] name_to_find name to search. * @return true if the given name was found, false otherwise. */ static bool find_adv_name(const ble_gap_evt_adv_report_t *p_adv_report, const char * name_to_find) { uint32_t err_code; data_t adv_data; data_t dev_name; // Initialize advertisement report for parsing adv_data.p_data = (uint8_t *)p_adv_report->data; adv_data.data_len = p_adv_report->dlen; //search for advertising names err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &adv_data, &dev_name); if (err_code == NRF_SUCCESS) { if(memcmp(name_to_find, dev_name.p_data, dev_name.data_len )== 0) { return true; } } else { // Look for the short local name if it was not found as complete err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, &adv_data, &dev_name); if (err_code != NRF_SUCCESS) { return false; } if(memcmp(m_target_periph_name, dev_name.p_data, dev_name.data_len )== 0) { return true; } } return false; }