uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t * new_params) { uint32_t err_code; m_preferred_conn_params = *new_params; // Set the connection params in stack err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params); if (err_code == NRF_SUCCESS) { if (!is_conn_params_ok(&m_current_conn_params)) { m_change_param = true; err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params); m_update_count = 1; } else { // Notify the application that the procedure has succeded if (m_conn_params_config.evt_handler != NULL) { ble_conn_params_evt_t evt; evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED; m_conn_params_config.evt_handler(&evt); } err_code = NRF_SUCCESS; } } return err_code; }
uint32_t conn_mw_ble_gap_conn_param_update(uint8_t const * const p_rx_buf, uint32_t rx_buf_len, uint8_t * const p_tx_buf, uint32_t * const p_tx_buf_len) { SER_ASSERT_NOT_NULL(p_rx_buf); SER_ASSERT_NOT_NULL(p_tx_buf); SER_ASSERT_NOT_NULL(p_tx_buf_len); uint16_t conn_handle; ble_gap_conn_params_t conn_params; ble_gap_conn_params_t * p_conn_params = &conn_params; uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; err_code = ble_gap_conn_param_update_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &p_conn_params); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_conn_param_update(conn_handle, p_conn_params); err_code = ble_gap_conn_param_update_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
/**@brief Function for decoding a command packet with RPC_SD_BLE_GAP_CONN_PARAM_UPDATE opcode. * * This function will decode the command, call the BLE Stack API, and also send command response * to the peer through the the transport layer. * * @param[in] p_command The encoded structure that needs to be decoded and passed on * to the BLE Stack API. * @param[in] command_len The length of the encoded command read from transport layer. * * @retval NRF_SUCCESS If the decoding of the command was successful, the SoftDevice * API was called, and the command response was sent to peer, * otherwise an error code. * @retval NRF_ERROR_INVALID_LENGTH If the content length of the packet is not conforming to the * codec specification. */ static uint32_t gap_conn_param_update_handle(const uint8_t * const p_command, uint32_t command_len) { uint16_t conn_handle; uint32_t err_code; ble_gap_conn_params_t conn_params; ble_gap_conn_params_t * p_conn_params = NULL; uint32_t index = 0; conn_handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_CONN_PARAM_UPDATE); // Check if the Connection Parameters field is present. if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { conn_params.min_conn_interval = uint16_decode(&p_command[index]); index += sizeof(uint16_t); conn_params.max_conn_interval = uint16_decode(&p_command[index]); index += sizeof(uint16_t); conn_params.slave_latency = uint16_decode(&p_command[index]); index += sizeof(uint16_t); conn_params.conn_sup_timeout = uint16_decode(&p_command[index]); p_conn_params = &conn_params; } RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_CONN_PARAM_UPDATE); err_code = sd_ble_gap_conn_param_update(conn_handle, p_conn_params); return ble_rpc_cmd_resp_send(SD_BLE_GAP_CONN_PARAM_UPDATE, err_code); }
/**@brief Function for handling BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: on_ble_gap_evt_adv_report(p_gap_evt); break; case BLE_GAP_EVT_CONNECTED: on_ble_gap_evt_connected(p_gap_evt); break; case BLE_GAP_EVT_DISCONNECTED: on_ble_gap_evt_disconnected(p_gap_evt); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Accept parameters requested by the peer. ble_gap_conn_params_t params; params = p_gap_evt->params.conn_param_update_request.conn_params; params.max_conn_interval = params.min_conn_interval; err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, ¶ms); APP_ERROR_CHECK(err_code); } break; case BLE_GATTS_EVT_SYS_ATTR_MISSING: { err_code = sd_ble_gatts_sys_attr_set(p_gap_evt->conn_handle, NULL, 0, 0); APP_ERROR_CHECK(err_code); } break; case BLE_GATTC_EVT_TIMEOUT: // Fallthrough. case BLE_GATTS_EVT_TIMEOUT: { NRF_LOG_DEBUG("GATT timeout, disconnecting.\r\n"); err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } break; case BLE_EVT_USER_MEM_REQUEST: { err_code = sd_ble_user_mem_reply(p_ble_evt->evt.common_evt.conn_handle, NULL); APP_ERROR_CHECK(err_code); } break; default: // No implementation needed. break; } }
ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams) { uint32_t rc; rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast<ble_gap_conn_params_t *>(const_cast<ConnectionParams_t*>(newParams))); if (rc == NRF_SUCCESS) { return BLE_ERROR_NONE; } else { return BLE_ERROR_PARAM_OUT_OF_RANGE; } }
static void update_timeout_handler(void * p_context) { UNUSED_PARAMETER(p_context); #else /* #if !USE_APP_TIMER */ static void update_timeout_handler(void) { m_conn_params_timer.detach(); /* this is supposed to be a single-shot timer callback */ #endif /* #if !USE_APP_TIMER */ if (m_conn_handle != BLE_CONN_HANDLE_INVALID) { // Check if we have reached the maximum number of attempts m_update_count++; if (m_update_count <= m_conn_params_config.max_conn_params_update_count) { uint32_t err_code; // Parameters are not ok, send connection parameters update request. err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params); if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL)) { m_conn_params_config.error_handler(err_code); } } else { m_update_count = 0; // Negotiation failed, disconnect automatically if this has been configured if (m_conn_params_config.disconnect_on_fail) { uint32_t err_code; err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE); if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL)) { m_conn_params_config.error_handler(err_code); } } // Notify the application that the procedure has failed if (m_conn_params_config.evt_handler != NULL) { ble_conn_params_evt_t evt; evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED; m_conn_params_config.evt_handler(&evt); } } } }
void ble_evt_user_handler (ble_evt_t* p_ble_evt) { ble_gap_conn_params_t conn_params; memset(&conn_params, 0, sizeof(conn_params)); conn_params.min_conn_interval = ble_config.min_conn_interval; conn_params.max_conn_interval = ble_config.max_conn_interval; conn_params.slave_latency = SLAVE_LATENCY; conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONN_PARAM_UPDATE: // just update them right now sd_ble_gap_conn_param_update(0, &conn_params); break; } }
/**@brief Function for handling the Application's BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: { data_t adv_data; data_t type_data; // Initialize advertisement report for parsing. adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data; adv_data.data_len = p_gap_evt->params.adv_report.dlen; err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, &adv_data, &type_data); if (err_code != NRF_SUCCESS) { // Compare short local name in case complete name does not match. err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, &adv_data, &type_data); } // Verify if short or complete name matches target. if (err_code == NRF_SUCCESS) { uint16_t extracted_uuid; // UUIDs found, look for matching UUID for (uint32_t u_index = 0; u_index < (type_data.data_len/UUID16_SIZE); u_index++) { UUID16_EXTRACT(&extracted_uuid,&type_data.p_data[u_index * UUID16_SIZE]); APPL_LOG("\t[APPL]: %x\r\n",extracted_uuid); if(extracted_uuid == TARGET_UUID) { // Stop scanning. err_code = sd_ble_gap_scan_stop(); if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Scan stop failed, reason %d\r\n", err_code); } err_code = bsp_indication_set(BSP_INDICATE_IDLE); APP_ERROR_CHECK(err_code); m_scan_param.selective = 0; // Initiate connection. err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, &m_scan_param, &m_connection_param); m_whitelist_temporarily_disabled = false; if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code); } break; } } } break; } case BLE_GAP_EVT_TIMEOUT: if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { APPL_LOG("[APPL]: Scan timed out.\r\n"); scan_start(); } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request timed out.\r\n"); } break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by peer. err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; default: break; } }
/**@brief Function for handling the Application's BLE Stack events. * * @details This function is responsible for managing possible quick connect->write->disconnect sequence. * It to write characteristic and switch the device in scan mode and getting advertising packets. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GATTC_EVT_WRITE_RSP: mb_send_write_rsp(); err_code = bt_disconnect(p_ble_evt->evt.gap_evt.conn_handle); if (err_code != NRF_SUCCESS) { bt_scan_start(); mb_set_ready_for_rq(); } break; case BLE_GAP_EVT_CONNECTED: nrf_gpio_pin_set(LED_CONNECTED); err_code = bt_write_to_device(p_ble_evt->evt.gap_evt.conn_handle); if (err_code != NRF_SUCCESS) { err_code = bt_disconnect(p_ble_evt->evt.gap_evt.conn_handle); if (err_code != NRF_SUCCESS) { bt_scan_start(); mb_set_ready_for_rq(); } } break; case BLE_GAP_EVT_DISCONNECTED: nrf_gpio_pin_clear(LED_CONNECTED); bt_scan_start(); break; case BLE_GAP_EVT_ADV_REPORT: { uint8_array_t adv_data; ble_gap_addr_t address; // Initialize advertisement report for parsing. adv_data.p_data = (uint8_t *)(p_gap_evt->params.adv_report.data); adv_data.size = p_gap_evt->params.adv_report.dlen; address = p_gap_evt->params.adv_report.peer_addr; bt_handle_temp_sensor(&address, &adv_data); bt_handle_led_driver(&address, &adv_data); break; } case BLE_GAP_EVT_TIMEOUT: nrf_gpio_pin_clear(LED_CONNECTED); bt_scan_start(); mb_set_ready_for_rq(); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by peer. err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; default: break; } }
/**@brief Function for handling BLE Stack events concerning central applications. * * @details This function keeps the connection handles of central applications up-to-date. It * parses scanning reports, initiating a connection attempt to peripherals when a * target UUID is found, and manages connection parameter update requests. Additionally, * it updates the status of LEDs used to report central applications activity. * * @note Since this function updates connection handles, @ref BLE_GAP_EVT_DISCONNECTED events * should be dispatched to the target application before invoking this function. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(const ble_evt_t * const p_ble_evt) { // For readability. const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { // Upon connection, check which peripheral has connected, initiate DB // discovery, update LEDs status and resume scanning if necessary. case BLE_GAP_EVT_CONNECTED: { uint32_t err_code; NRF_LOG_PRINTF("[APP]: link 0x%x established, start discovery on it\r\n", p_gap_evt->conn_handle); APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < TOTAL_LINK_COUNT); err_code = ble_lbs_c_handles_assign(&m_ble_lbs_c[p_gap_evt->conn_handle], p_gap_evt->conn_handle, NULL); APP_ERROR_CHECK(err_code); err_code = ble_db_discovery_start(&m_ble_db_discovery[p_gap_evt->conn_handle], p_gap_evt->conn_handle); if (err_code != NRF_ERROR_BUSY) { APP_ERROR_CHECK(err_code); } // Update LEDs status, and check if we should be looking for more // peripherals to connect to. LEDS_ON(CENTRAL_CONNECTED_LED); if (ble_conn_state_n_centrals() == CENTRAL_LINK_COUNT) { LEDS_OFF(CENTRAL_SCANNING_LED); } else { // Resume scanning. LEDS_ON(CENTRAL_SCANNING_LED); scan_start(); } } break; // BLE_GAP_EVT_CONNECTED // Upon disconnection, reset the connection handle of the peer which disconnected, update // the LEDs status and start scanning again. case BLE_GAP_EVT_DISCONNECTED: { uint32_t central_link_cnt; // Number of central links. NRF_LOG_PRINTF("LBS central link 0x%x disconnected (reason: %d)\r\n", p_gap_evt->conn_handle, p_gap_evt->params.disconnected.reason); uint32_t err_code = app_button_disable(); APP_ERROR_CHECK(err_code); // Start scanning scan_start(); // Update LEDs status. LEDS_ON(CENTRAL_SCANNING_LED); central_link_cnt = ble_conn_state_n_centrals(); if (central_link_cnt == 0) { LEDS_OFF(CENTRAL_CONNECTED_LED); } } break; // BLE_GAP_EVT_DISCONNECTED case BLE_GAP_EVT_ADV_REPORT: on_adv_report(p_ble_evt); break; // BLE_GAP_ADV_REPORT case BLE_GAP_EVT_TIMEOUT: { // We have not specified a timeout for scanning, so only connection attemps can timeout. if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request timed out.\r\n"); } } break; // BLE_GAP_EVT_TIMEOUT case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Accept parameters requested by peer. ret_code_t err_code; err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); } break; // BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST default: // No implementation needed. break; } }
/**@brief AMT Service Handler. */ static void amts_evt_handler(nrf_ble_amts_evt_t evt) { ret_code_t err_code; switch (evt.evt_type) { case SERVICE_EVT_NOTIF_ENABLED: { NRF_LOG_INFO("Notifications enabled.\r\n"); bsp_board_led_on(LED_READY); m_notif_enabled = true; if (m_board_role != BOARD_TESTER) { return; } if (m_gap_role == BLE_GAP_ROLE_PERIPH) { m_conn_interval_configured = false; m_conn_param.min_conn_interval = m_test_params.conn_interval; m_conn_param.max_conn_interval = m_test_params.conn_interval + 1; err_code = ble_conn_params_change_conn_params(&m_conn_param); if (err_code != NRF_SUCCESS) { NRF_LOG_ERROR("ble_conn_params_change_conn_params() failed: 0x%x.\r\n", err_code); } } if (m_gap_role == BLE_GAP_ROLE_CENTRAL) { m_conn_interval_configured = true; m_conn_param.min_conn_interval = m_test_params.conn_interval; m_conn_param.max_conn_interval = m_test_params.conn_interval; err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_conn_param); if (err_code != NRF_SUCCESS) { NRF_LOG_ERROR("sd_ble_gap_conn_param_update() failed: 0x%x.\r\n", err_code); } } } break; case SERVICE_EVT_NOTIF_DISABLED: { NRF_LOG_INFO("Notifications disabled.\r\n"); bsp_board_led_off(LED_READY); } break; case SERVICE_EVT_TRANSFER_1KB: { NRF_LOG_INFO("Sent %u KBytes\r\n", (evt.bytes_transfered_cnt / 1024)); bsp_board_led_invert(LED_PROGRESS); } break; case SERVICE_EVT_TRANSFER_FINISHED: { // Stop counter as soon as possible. counter_stop(); bsp_board_led_off(LED_PROGRESS); bsp_board_led_on(LED_FINISHED); uint32_t time_ms = counter_get(); uint32_t bit_count = (evt.bytes_transfered_cnt * 8); float throughput = (((float)(bit_count * 100) / time_ms) / 1024); NRF_LOG_INFO("Done.\r\n\r\n"); NRF_LOG_INFO("=============================\r\n"); NRF_LOG_INFO("Time: %u.%.2u seconds elapsed.\r\n", (counter_get() / 100), (counter_get() % 100)); NRF_LOG_INFO("Throughput: " NRF_LOG_FLOAT_MARKER " Kbits/s.\r\n", NRF_LOG_FLOAT(throughput)); NRF_LOG_INFO("=============================\r\n"); NRF_LOG_INFO("Sent %u bytes of ATT payload.\r\n", evt.bytes_transfered_cnt); NRF_LOG_INFO("Retrieving amount of bytes received from peer...\r\n"); err_code = nrf_ble_amtc_rcb_read(&m_amtc); if (err_code != NRF_SUCCESS) { NRF_LOG_ERROR("nrf_ble_amtc_rcb_read() failed: 0x%x.\r\n", err_code); test_terminate(); } } break; } }
/**@brief Function for handling BLE Stack events concerning central applications. * * @details This function keeps the connection handles of central applications up-to-date. It * parses scanning reports, initiating a connection attempt to peripherals when a target UUID * is found, and manages connection parameter update requests. Additionally, it updates the status * of LEDs used to report central applications activity. * * @note Since this function updates connection handles, @ref BLE_GAP_EVT_DISCONNECTED events * should be dispatched to the target application before invoking this function. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_central_evt(const ble_evt_t * const p_ble_evt) { // The addresses of peers we attempted to connect to. static ble_gap_addr_t periph_addr_hrs; static ble_gap_addr_t periph_addr_rsc; // For readability. const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { /** Upon connection, check which peripheral has connected (HR or RSC), initiate DB * discovery, update LEDs status and resume scanning if necessary. */ case BLE_GAP_EVT_CONNECTED: { uint32_t err_code; // For readability. const ble_gap_addr_t * const peer_addr = &p_gap_evt->params.connected.peer_addr; /** Check which peer has connected, save the connection handle and initiate DB discovery. * DB discovery will invoke a callback (hrs_c_evt_handler and rscs_c_evt_handler) * upon completion, which is used to enable notifications from the peer. */ if(memcmp(&periph_addr_hrs, peer_addr, sizeof(ble_gap_addr_t)) == 0) { NRF_LOG_PRINTF("HRS central connected\r\n"); // Reset the peer address we had saved. memset(&periph_addr_hrs, 0, sizeof(ble_gap_addr_t)); m_conn_handle_hrs_c = p_gap_evt->conn_handle; NRF_LOG_PRINTF("Starting DB discovery for HRS\r\n"); err_code = ble_db_discovery_start(&m_ble_db_discovery_hrs, p_gap_evt->conn_handle); APP_ERROR_CHECK(err_code); } else if(memcmp(&periph_addr_rsc, peer_addr, sizeof(ble_gap_addr_t)) == 0) { NRF_LOG_PRINTF("RSC central connected\r\n"); // Reset the peer address we had saved. memset(&periph_addr_rsc, 0, sizeof(ble_gap_addr_t)); m_conn_handle_rscs_c = p_gap_evt->conn_handle; NRF_LOG_PRINTF("Starting DB discovery for RSCS\r\n"); err_code = ble_db_discovery_start(&m_ble_db_discovery_rsc, p_gap_evt->conn_handle); APP_ERROR_CHECK(err_code); } /** Update LEDs status, and check if we should be looking for more * peripherals to connect to. */ LEDS_ON(CENTRAL_CONNECTED_LED); if (ble_conn_state_n_centrals() == MAX_CONNECTED_CENTRALS) { LEDS_OFF(CENTRAL_SCANNING_LED); } else { // Resume scanning. LEDS_ON(CENTRAL_SCANNING_LED); scan_start(); } } break; // BLE_GAP_EVT_CONNECTED /** Upon disconnection, reset the connection handle of the peer which disconnected, update * the LEDs status and start scanning again. */ case BLE_GAP_EVT_DISCONNECTED: { uint8_t n_centrals; if (p_gap_evt->conn_handle == m_conn_handle_hrs_c) { NRF_LOG_PRINTF("HRS central disconnected (reason: %d)\r\n", p_gap_evt->params.disconnected.reason); m_conn_handle_hrs_c = BLE_CONN_HANDLE_INVALID; } else if(p_gap_evt->conn_handle == m_conn_handle_rscs_c) { NRF_LOG_PRINTF("RSC central disconnected (reason: %d)\r\n", p_gap_evt->params.disconnected.reason); m_conn_handle_rscs_c = BLE_CONN_HANDLE_INVALID; } // Start scanning // scan_start(); // Update LEDs status. LEDS_ON(CENTRAL_SCANNING_LED); n_centrals = ble_conn_state_n_centrals(); if (n_centrals == 0) { LEDS_OFF(CENTRAL_CONNECTED_LED); } } break; // BLE_GAP_EVT_DISCONNECTED case BLE_GAP_EVT_ADV_REPORT: { uint32_t err_code; data_t adv_data; data_t type_data; // For readibility. const ble_gap_addr_t * const peer_addr = &p_gap_evt->params.adv_report.peer_addr; // Initialize advertisement report for parsing. adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data; adv_data.data_len = p_gap_evt->params.adv_report.dlen; err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, &adv_data, &type_data); if (err_code != NRF_SUCCESS) { // Look for the services in 'complete' if it was not found in 'more available'. err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, &adv_data, &type_data); if (err_code != NRF_SUCCESS) { // If we can't parse the data, then exit. break; } } // Verify if any UUID match the Heart rate or Running speed and cadence services. for (uint32_t u_index = 0; u_index < (type_data.data_len / UUID16_SIZE); u_index++) { bool do_connect = false; uint16_t extracted_uuid; UUID16_EXTRACT(&extracted_uuid, &type_data.p_data[u_index * UUID16_SIZE]); /** We do not want to connect to two peripherals offering the same service, so when * a UUID is matched, we check that we are not already connected to a peer which * offers the same service. We then save the peer address, so that upon connection * we can tell which peer has connected and update its respective connection * handle. */ if ((extracted_uuid == BLE_UUID_HEART_RATE_SERVICE) && (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID)) { do_connect = true; memcpy(&periph_addr_hrs, peer_addr, sizeof(ble_gap_addr_t)); } else if ((extracted_uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE) && (m_conn_handle_rscs_c == BLE_CONN_HANDLE_INVALID)) { do_connect = true; memcpy(&periph_addr_rsc, peer_addr, sizeof(ble_gap_addr_t)); } if (do_connect) { // Initiate connection. err_code = sd_ble_gap_connect(peer_addr, &m_scan_param, &m_connection_param); if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code); } } } } break; // BLE_GAP_ADV_REPORT case BLE_GAP_EVT_TIMEOUT: { // We have not specified a timeout for scanning, so only connection attemps can timeout. if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request timed out.\r\n"); } } break; // BLE_GAP_EVT_TIMEOUT case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Accept parameters requested by peer. ret_code_t err_code; err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); } break; // BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST default: // No implementation needed. break; } }
/**@brief Function for handling the Application's BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: // continue advertising nonconnectably app.conn_handle = p_ble_evt->evt.gap_evt.conn_handle; m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; advertising_start(); break; case BLE_GAP_EVT_DISCONNECTED: app.conn_handle = BLE_CONN_HANDLE_INVALID; // advertise connectivity advertising_stop(); m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; advertising_start(); break; case BLE_GATTS_EVT_WRITE: { ble_gatts_evt_write_t* write_data = &(p_ble_evt->evt.gatts_evt.params.write); if (write_data->context.char_uuid.uuid == test_char_uuid16) { if (write_data->data[0] == 0x42) { //led_on(BLEES_LED_PIN); // enable higher connection interval. Only lasts for this connection ble_gap_conn_params_t gap_conn_params; memset(&gap_conn_params, 0, sizeof(gap_conn_params)); gap_conn_params.min_conn_interval = 0x06; // 7.5 ms gap_conn_params.max_conn_interval = MSEC_TO_UNITS(30, UNIT_1_25_MS); gap_conn_params.slave_latency = 0; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; err_code = sd_ble_gap_conn_param_update(app.conn_handle, &gap_conn_params); APP_ERROR_CHECK(err_code); } } } break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: err_code = sd_ble_gap_sec_params_reply(app.conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &m_sec_params, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_SYS_ATTR_MISSING: err_code = sd_ble_gatts_sys_attr_set(app.conn_handle, NULL, 0, 0); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_AUTH_STATUS: break; case BLE_GAP_EVT_SEC_INFO_REQUEST: // No keys found for this device. err_code = sd_ble_gap_sec_info_reply(app.conn_handle, NULL, NULL, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_TIMEOUT: if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING) { err_code = sd_power_system_off(); APP_ERROR_CHECK(err_code); } break; default: break; } }
/**@brief Function for handling the Application's BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_central_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: { data_t adv_data; data_t type_data; // Initialize advertisement report for parsing. adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data; adv_data.data_len = p_gap_evt->params.adv_report.dlen; err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, &adv_data, &type_data); if (err_code != NRF_SUCCESS) { // Look for the services in 'complete' if it was not found in 'more available'. err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, &adv_data, &type_data); } // Verify if short or complete name matches target. if (err_code == NRF_SUCCESS) { uint16_t extracted_uuid; // UUIDs found, look for matching UUID for (uint32_t u_index = 0; u_index < (type_data.data_len/UUID16_SIZE); u_index++) { UUID16_EXTRACT(&extracted_uuid,&type_data.p_data[u_index * UUID16_SIZE]); APPL_LOG("\t[APPL]: %x\r\n",extracted_uuid); if(extracted_uuid == BLE_UUID_HEART_RATE_SERVICE || extracted_uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE) { if(extracted_uuid == BLE_UUID_HEART_RATE_SERVICE) { printf("HRS found\n\r"); memcpy(&m_hrs_peripheral_address, &p_gap_evt->params.adv_report.peer_addr,sizeof(ble_gap_addr_t)); } if(extracted_uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE) { printf("RSC found\n\r"); memcpy(&m_rscs_peripheral_address, &p_gap_evt->params.adv_report.peer_addr,sizeof(ble_gap_addr_t)); } m_scan_param.selective = 0; // Initiate connection. err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, &m_scan_param, &m_connection_param); m_whitelist_temporarily_disabled = false; if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code); } break; } } } break; } case BLE_GAP_EVT_TIMEOUT: if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { APPL_LOG("[APPL]: Scan timed out.\r\n"); scan_start(); } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request timed out.\r\n"); } break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by peer. err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; case BLE_GAP_EVT_DISCONNECTED: /* if(p_gap_evt->conn_handle == m_conn_handle_central_hrs) { m_conn_handle_central_hrs = BLE_CONN_HANDLE_INVALID; } else if(p_gap_evt->conn_handle == m_conn_handle_central_rsc) { m_conn_handle_central_rsc = BLE_CONN_HANDLE_INVALID; } if((m_conn_handle_central_rsc == BLE_CONN_HANDLE_INVALID) && (m_conn_handle_central_hrs == BLE_CONN_HANDLE_INVALID)) { LEDS_OFF(CENTRAL_CONNECTED_LED); } */ break; default: break; } }
/* Function for handling the Application's BLE Stack events. Parameters: p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; uint8_t index = 0; const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: { const ble_gap_evt_adv_report_t *p_adv_report = &p_gap_evt->params.adv_report; index = get_devices_list_id(p_adv_report->peer_addr); /* id device has been already found or list is full */ if( index != 0xFF) { /* device already found */ /* new adv update */ target_name_if_present(p_adv_report, found_devices[index].name, &found_devices[index].name_length); } else { /* if UUID is present */ if (is_uuid_present(&m_nus_uuid, p_adv_report)) { /* get last free index */ index = devices_list_index; /* increment last free index */ devices_list_index++; /* insert the new device into the list: copy address */ strncpy((char *)(found_devices[index].gap_addr.addr), (char *)(p_adv_report->peer_addr.addr), (size_t)6); /* copy address type */ found_devices[index].gap_addr.addr_type = p_adv_report->peer_addr.addr_type; } } break; } case BLE_GAP_EVT_CONNECTED: { /* if pending connection index of central role is valid */ if(pending_nus_conn_index < NUM_OF_CONNECTIONS) { /* store related connection handle */ active_conn_handles[pending_nus_conn_index] = p_ble_evt->evt.gap_evt.conn_handle; /* set current handle as this one */ m_ble_nus_c.conn_handle = p_ble_evt->evt.gap_evt.conn_handle; /* reset pending NUS connection index */ pending_nus_conn_index = 0xFF; /* reset uart */ uart_reset(); /* set "connection" pin as connected */ nrf_gpio_pin_write(CONN_PIN_NUMBER, CONNECTED_PIN_STATE); /* send confirmation string */ uart_send_string((uint8_t *)"OK.", 3); /* start discovery of services. The NUS Client waits for a discovery result */ err_code = ble_db_discovery_start(&m_ble_db_discovery, p_ble_evt->evt.gap_evt.conn_handle); APP_ERROR_CHECK(err_code); } else { /* internal error: do nothing */ } break; } case BLE_GAP_EVT_DISCONNECTED: { /* it should not pass here */ break; } case BLE_GAP_EVT_TIMEOUT: { if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { /* scan timed out */ uart_send_string((uint8_t *)"TIMEOUT.", 8); } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { /* connection request timed out: do nothing */ } else { /* do nothing */ } break; } case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { /* ATTENTION: Pairing not supported at the moment */ err_code = sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); APP_ERROR_CHECK(err_code); break; } case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { /* Accepting parameters requested by peer. */ err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; } default: break; } }
void nRF51822::poll() { uint32_t evtBuf[BLE_STACK_EVT_MSG_BUF_SIZE] __attribute__ ((__aligned__(BLE_EVTS_PTR_ALIGNMENT))); uint16_t evtLen = sizeof(evtBuf); ble_evt_t* bleEvt = (ble_evt_t*)evtBuf; if (sd_ble_evt_get((uint8_t*)evtBuf, &evtLen) == NRF_SUCCESS) { switch (bleEvt->header.evt_id) { case BLE_EVT_TX_COMPLETE: #ifdef NRF_51822_DEBUG Serial.print(F("Evt TX complete ")); Serial.println(bleEvt->evt.common_evt.params.tx_complete.count); #endif this->_txBufferCount++; break; case BLE_GAP_EVT_CONNECTED: #ifdef NRF_51822_DEBUG char address[18]; BLEUtil::addressToString(bleEvt->evt.gap_evt.params.connected.peer_addr.addr, address); Serial.print(F("Evt Connected ")); Serial.println(address); #endif this->_connectionHandle = bleEvt->evt.gap_evt.conn_handle; sd_ble_tx_buffer_count_get(&this->_txBufferCount); if (this->_eventListener) { this->_eventListener->BLEDeviceConnected(*this, bleEvt->evt.gap_evt.params.connected.peer_addr.addr); } if (this->_minimumConnectionInterval >= BLE_GAP_CP_MIN_CONN_INTVL_MIN && this->_maximumConnectionInterval <= BLE_GAP_CP_MAX_CONN_INTVL_MAX) { ble_gap_conn_params_t gap_conn_params; gap_conn_params.min_conn_interval = this->_minimumConnectionInterval; // in 1.25ms units gap_conn_params.max_conn_interval = this->_maximumConnectionInterval; // in 1.25ms unit gap_conn_params.slave_latency = 0; gap_conn_params.conn_sup_timeout = 4000 / 10; // in 10ms unit sd_ble_gap_conn_param_update(this->_connectionHandle, &gap_conn_params); } if (this->_numRemoteServices > 0) { sd_ble_gattc_primary_services_discover(this->_connectionHandle, 1, NULL); } break; case BLE_GAP_EVT_DISCONNECTED: #ifdef NRF_51822_DEBUG Serial.println(F("Evt Disconnected")); #endif this->_connectionHandle = BLE_CONN_HANDLE_INVALID; this->_txBufferCount = 0; for (int i = 0; i < this->_numLocalCharacteristics; i++) { struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i]; localCharacteristicInfo->notifySubscribed = false; localCharacteristicInfo->indicateSubscribed = false; if (localCharacteristicInfo->characteristic->subscribed()) { if (this->_eventListener) { this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localCharacteristicInfo->characteristic, false); } } } if (this->_eventListener) { this->_eventListener->BLEDeviceDisconnected(*this); } // clear remote handle info for (int i = 0; i < this->_numRemoteServices; i++) { memset(&this->_remoteServiceInfo[i].handlesRange, 0, sizeof(this->_remoteServiceInfo[i].handlesRange)); } for (int i = 0; i < this->_numRemoteCharacteristics; i++) { memset(&this->_remoteCharacteristicInfo[i].properties, 0, sizeof(this->_remoteCharacteristicInfo[i].properties)); this->_remoteCharacteristicInfo[i].valueHandle = 0; } this->_remoteRequestInProgress = false; this->startAdvertising(); break; case BLE_GAP_EVT_CONN_PARAM_UPDATE: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Conn Param Update 0x")); Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval, HEX); Serial.print(F(" 0x")); Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval, HEX); Serial.print(F(" 0x")); Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency, HEX); Serial.print(F(" 0x")); Serial.print(bleEvt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout, HEX); Serial.println(); #endif break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Sec Params Request ")); #ifndef NRF51_S130 Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.timeout); Serial.print(F(" ")); #endif Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.bond); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.mitm); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.io_caps); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.oob); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.min_key_size); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_params_request.peer_params.max_key_size); Serial.println(); #endif if (this->_bondStore && !this->_bondStore->hasData()) { // only allow bonding if bond store exists and there is no data ble_gap_sec_params_t gapSecParams; #ifdef NRF51_S130 gapSecParams.kdist_periph.enc = 1; #else gapSecParams.timeout = 30; // must be 30s #endif gapSecParams.bond = true; gapSecParams.mitm = false; gapSecParams.io_caps = BLE_GAP_IO_CAPS_NONE; gapSecParams.oob = false; gapSecParams.min_key_size = 7; gapSecParams.max_key_size = 16; #ifdef NRF51_S130 ble_gap_sec_keyset_t keyset; keyset.keys_central.p_enc_key = NULL; keyset.keys_central.p_id_key = NULL; keyset.keys_central.p_sign_key = NULL; keyset.keys_periph.p_enc_key = this->_encKey; keyset.keys_periph.p_id_key = NULL; keyset.keys_periph.p_sign_key = NULL; sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_SUCCESS, &gapSecParams, &keyset); #else sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_SUCCESS, &gapSecParams); #endif } else { #ifdef NRF51_S130 sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); #else sd_ble_gap_sec_params_reply(this->_connectionHandle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL); #endif } break; case BLE_GAP_EVT_SEC_INFO_REQUEST: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Sec Info Request ")); // Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.peer_addr); // Serial.print(F(" ")); #ifdef NRF51_S130 Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.master_id.ediv); #else Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.div); #endif Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.enc_info); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.id_info); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.sec_info_request.sign_info); Serial.println(); #endif #ifdef NRF51_S130 if (this->_encKey->master_id.ediv == bleEvt->evt.gap_evt.params.sec_info_request.master_id.ediv) { sd_ble_gap_sec_info_reply(this->_connectionHandle, &this->_encKey->enc_info, NULL, NULL); } else { sd_ble_gap_sec_info_reply(this->_connectionHandle, NULL, NULL, NULL); } #else if (this->_authStatus->periph_keys.enc_info.div == bleEvt->evt.gap_evt.params.sec_info_request.div) { sd_ble_gap_sec_info_reply(this->_connectionHandle, &this->_authStatus->periph_keys.enc_info, NULL); } else { sd_ble_gap_sec_info_reply(this->_connectionHandle, NULL, NULL); } #endif break; case BLE_GAP_EVT_AUTH_STATUS: #ifdef NRF_51822_DEBUG Serial.println(F("Evt Auth Status")); Serial.println(bleEvt->evt.gap_evt.params.auth_status.auth_status); #endif if (BLE_GAP_SEC_STATUS_SUCCESS == bleEvt->evt.gap_evt.params.auth_status.auth_status) { #ifndef NRF51_S130 *this->_authStatus = bleEvt->evt.gap_evt.params.auth_status; #endif if (this->_bondStore) { #ifdef NRF_51822_DEBUG Serial.println(F("Storing bond data")); #endif #ifdef NRF51_S130 this->_bondStore->putData(this->_bondData, 0, sizeof(this->_bondData)); #else this->_bondStore->putData(this->_authStatusBuffer, 0, sizeof(this->_authStatusBuffer)); #endif } if (this->_eventListener) { this->_eventListener->BLEDeviceBonded(*this); } } break; case BLE_GAP_EVT_CONN_SEC_UPDATE: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Conn Sec Update ")); Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.sm); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv); Serial.print(F(" ")); Serial.print(bleEvt->evt.gap_evt.params.conn_sec_update.conn_sec.encr_key_size); Serial.println(); #endif break; case BLE_GATTS_EVT_WRITE: { #ifdef NRF_51822_DEBUG Serial.print(F("Evt Write, handle = ")); Serial.println(bleEvt->evt.gatts_evt.params.write.handle, DEC); BLEUtil::printBuffer(bleEvt->evt.gatts_evt.params.write.data, bleEvt->evt.gatts_evt.params.write.len); #endif uint16_t handle = bleEvt->evt.gatts_evt.params.write.handle; for (int i = 0; i < this->_numLocalCharacteristics; i++) { struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i]; if (localCharacteristicInfo->handles.value_handle == handle) { if (this->_eventListener) { this->_eventListener->BLEDeviceCharacteristicValueChanged(*this, *localCharacteristicInfo->characteristic, bleEvt->evt.gatts_evt.params.write.data, bleEvt->evt.gatts_evt.params.write.len); } break; } else if (localCharacteristicInfo->handles.cccd_handle == handle) { uint16_t value = bleEvt->evt.gatts_evt.params.write.data[0] | (bleEvt->evt.gatts_evt.params.write.data[1] << 8); localCharacteristicInfo->notifySubscribed = (value & 0x0001); localCharacteristicInfo->indicateSubscribed = (value & 0x0002); bool subscribed = (localCharacteristicInfo->notifySubscribed || localCharacteristicInfo->indicateSubscribed); if (subscribed != localCharacteristicInfo->characteristic->subscribed()) { if (this->_eventListener) { this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localCharacteristicInfo->characteristic, subscribed); } break; } } } break; } case BLE_GATTS_EVT_SYS_ATTR_MISSING: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Sys Attr Missing ")); Serial.println(bleEvt->evt.gatts_evt.params.sys_attr_missing.hint); #endif #ifdef NRF51_S130 sd_ble_gatts_sys_attr_set(this->_connectionHandle, NULL, 0, 0); #else sd_ble_gatts_sys_attr_set(this->_connectionHandle, NULL, 0); #endif break; case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Prim Srvc Disc Rsp 0x")); Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX); #endif if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS) { uint16_t count = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.count; for (int i = 0; i < count; i++) { for (int j = 0; j < this->_numRemoteServices; j++) { if ((bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].uuid.type == this->_remoteServiceInfo[j].uuid.type) && (bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].uuid.uuid == this->_remoteServiceInfo[j].uuid.uuid)) { this->_remoteServiceInfo[j].handlesRange = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[i].handle_range; break; } } } uint16_t startHandle = bleEvt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[count - 1].handle_range.end_handle + 1; sd_ble_gattc_primary_services_discover(this->_connectionHandle, startHandle, NULL); } else { // done discovering services for (int i = 0; i < this->_numRemoteServices; i++) { if (this->_remoteServiceInfo[i].handlesRange.start_handle != 0 && this->_remoteServiceInfo[i].handlesRange.end_handle != 0) { this->_remoteServiceDiscoveryIndex = i; sd_ble_gattc_characteristics_discover(this->_connectionHandle, &this->_remoteServiceInfo[i].handlesRange); break; } } } break; case BLE_GATTC_EVT_CHAR_DISC_RSP: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Char Disc Rsp 0x")); Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX); #endif if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS) { ble_gattc_handle_range_t serviceHandlesRange = this->_remoteServiceInfo[this->_remoteServiceDiscoveryIndex].handlesRange; uint16_t count = bleEvt->evt.gattc_evt.params.char_disc_rsp.count; for (int i = 0; i < count; i++) { for (int j = 0; j < this->_numRemoteCharacteristics; j++) { if ((this->_remoteServiceInfo[this->_remoteServiceDiscoveryIndex].service == this->_remoteCharacteristicInfo[j].service) && (bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].uuid.type == this->_remoteCharacteristicInfo[j].uuid.type) && (bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].uuid.uuid == this->_remoteCharacteristicInfo[j].uuid.uuid)) { this->_remoteCharacteristicInfo[j].properties = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].char_props; this->_remoteCharacteristicInfo[j].valueHandle = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].handle_value; } } serviceHandlesRange.start_handle = bleEvt->evt.gattc_evt.params.char_disc_rsp.chars[i].handle_value; } sd_ble_gattc_characteristics_discover(this->_connectionHandle, &serviceHandlesRange); } else { bool discoverCharacteristics = false; for (int i = this->_remoteServiceDiscoveryIndex + 1; i < this->_numRemoteServices; i++) { if (this->_remoteServiceInfo[i].handlesRange.start_handle != 0 && this->_remoteServiceInfo[i].handlesRange.end_handle != 0) { this->_remoteServiceDiscoveryIndex = i; sd_ble_gattc_characteristics_discover(this->_connectionHandle, &this->_remoteServiceInfo[i].handlesRange); discoverCharacteristics = true; break; } } if (!discoverCharacteristics) { if (this->_eventListener) { this->_eventListener->BLEDeviceRemoteServicesDiscovered(*this); } } } break; case BLE_GATTC_EVT_READ_RSP: { #ifdef NRF_51822_DEBUG Serial.print(F("Evt Read Rsp 0x")); Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX); Serial.println(bleEvt->evt.gattc_evt.params.read_rsp.handle, DEC); BLEUtil::printBuffer(bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp.len); #endif this->_remoteRequestInProgress = false; if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION && this->_bondStore) { ble_gap_sec_params_t gapSecParams; #ifdef NRF51_S130 gapSecParams.kdist_periph.enc = 1; #else gapSecParams.timeout = 30; // must be 30s #endif gapSecParams.bond = true; gapSecParams.mitm = false; gapSecParams.io_caps = BLE_GAP_IO_CAPS_NONE; gapSecParams.oob = false; gapSecParams.min_key_size = 7; gapSecParams.max_key_size = 16; sd_ble_gap_authenticate(this->_connectionHandle, &gapSecParams); } else { uint16_t handle = bleEvt->evt.gattc_evt.params.read_rsp.handle; for (int i = 0; i < this->_numRemoteCharacteristics; i++) { if (this->_remoteCharacteristicInfo[i].valueHandle == handle) { if (this->_eventListener) { this->_eventListener->BLEDeviceRemoteCharacteristicValueChanged(*this, *this->_remoteCharacteristicInfo[i].characteristic, bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp. len); } break; } } } break; } case BLE_GATTC_EVT_WRITE_RSP: #ifdef NRF_51822_DEBUG Serial.print(F("Evt Write Rsp 0x")); Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX); Serial.println(bleEvt->evt.gattc_evt.params.write_rsp.handle, DEC); #endif this->_remoteRequestInProgress = false; if (bleEvt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION && this->_bondStore) { ble_gap_sec_params_t gapSecParams; #ifdef NRF51_S130 gapSecParams.kdist_periph.enc = 1; #else gapSecParams.timeout = 30; // must be 30s #endif gapSecParams.bond = true; gapSecParams.mitm = false; gapSecParams.io_caps = BLE_GAP_IO_CAPS_NONE; gapSecParams.oob = false; gapSecParams.min_key_size = 7; gapSecParams.max_key_size = 16; sd_ble_gap_authenticate(this->_connectionHandle, &gapSecParams); } break; case BLE_GATTC_EVT_HVX: { #ifdef NRF_51822_DEBUG Serial.print(F("Evt Hvx 0x")); Serial.println(bleEvt->evt.gattc_evt.gatt_status, HEX); Serial.println(bleEvt->evt.gattc_evt.params.hvx.handle, DEC); #endif uint16_t handle = bleEvt->evt.gattc_evt.params.hvx.handle; if (bleEvt->evt.gattc_evt.params.hvx.type == BLE_GATT_HVX_INDICATION) { sd_ble_gattc_hv_confirm(this->_connectionHandle, handle); } for (int i = 0; i < this->_numRemoteCharacteristics; i++) { if (this->_remoteCharacteristicInfo[i].valueHandle == handle) { if (this->_eventListener) { this->_eventListener->BLEDeviceRemoteCharacteristicValueChanged(*this, *this->_remoteCharacteristicInfo[i].characteristic, bleEvt->evt.gattc_evt.params.read_rsp.data, bleEvt->evt.gattc_evt.params.read_rsp. len); } break; } } break; } default: #ifdef NRF_51822_DEBUG Serial.print(F("bleEvt->header.evt_id = 0x")); Serial.print(bleEvt->header.evt_id, HEX); Serial.print(F(" ")); Serial.println(bleEvt->header.evt_len); #endif break; } } // sd_app_evt_wait(); }
/**@brief Function for handling BLE Stack events concerning central applications. * * @details This function keeps the connection handles of central applications up-to-date. It * parses scanning reports, initiating a connection attempt to peripherals when a target UUID * is found, and manages connection parameter update requests. Additionally, it updates the status * of LEDs used to report central applications activity. * * @note Since this function updates connection handles, @ref BLE_GAP_EVT_DISCONNECTED events * should be dispatched to the target application before invoking this function. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_central_evt(const ble_evt_t * const p_ble_evt) { const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { /** Upon connection, check which peripheral has connected (HR or RSC), initiate DB * discovery, update LEDs status and resume scanning if necessary. */ case BLE_GAP_EVT_CONNECTED: { uint32_t err_code; /** If no Heart Rate sensor or RSC sensor is currently connected, try to find them on this peripheral*/ if (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID) { NRF_LOG_PRINTF("try to find HRS or RSC on conn_handle 0x%x\r\n", p_gap_evt->conn_handle); APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < CENTRAL_LINK_COUNT + PERIPHERAL_LINK_COUNT); err_code = ble_db_discovery_start(&m_ble_db_discovery[p_gap_evt->conn_handle], p_gap_evt->conn_handle); APP_ERROR_CHECK(err_code); } /** Update LEDs status, and check if we should be looking for more * peripherals to connect to. */ LEDS_ON(CENTRAL_CONNECTED_LED); if (ble_conn_state_n_centrals() == CENTRAL_LINK_COUNT) { LEDS_OFF(CENTRAL_SCANNING_LED); } else { // Resume scanning. LEDS_ON(CENTRAL_SCANNING_LED); scan_start(); } } break; // BLE_GAP_EVT_CONNECTED /** Upon disconnection, reset the connection handle of the peer which disconnected, update * the LEDs status and start scanning again. */ case BLE_GAP_EVT_DISCONNECTED: { uint8_t n_centrals; if (p_gap_evt->conn_handle == m_conn_handle_hrs_c) { NRF_LOG_PRINTF("HRS central disconnected (reason: %d)\r\n", p_gap_evt->params.disconnected.reason); m_conn_handle_hrs_c = BLE_CONN_HANDLE_INVALID; } if (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID) { // Start scanning scan_start(); // Update LEDs status. LEDS_ON(CENTRAL_SCANNING_LED); } n_centrals = ble_conn_state_n_centrals(); if (n_centrals == 0) { LEDS_OFF(CENTRAL_CONNECTED_LED); } } break; // BLE_GAP_EVT_DISCONNECTED case BLE_GAP_EVT_ADV_REPORT: { uint32_t err_code; if (strlen(m_target_periph_name) != 0) { if (find_adv_name(&p_gap_evt->params.adv_report, m_target_periph_name)) { // Initiate connection. err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, &m_scan_param, &m_connection_param); if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code); } } } else { /** We do not want to connect to two peripherals offering the same service, so when * a UUID is matched, we check that we are not already connected to a peer which * offers the same service. */ if (find_adv_uuid(&p_gap_evt->params.adv_report, BLE_UUID_HEART_RATE_SERVICE)&& (m_conn_handle_hrs_c == BLE_CONN_HANDLE_INVALID)) { // Initiate connection. err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, &m_scan_param, &m_connection_param); if (err_code != NRF_SUCCESS) { APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code); } } } } break; // BLE_GAP_ADV_REPORT case BLE_GAP_EVT_TIMEOUT: { // We have not specified a timeout for scanning, so only connection attemps can timeout. if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request timed out.\r\n"); } } break; // BLE_GAP_EVT_TIMEOUT case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Accept parameters requested by peer. ret_code_t err_code; err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); } break; // BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST default: // No implementation needed. break; } }
/**@brief Function for handling the Application's BLE Stack events. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: { data_t adv_data; data_t type_data; // Initialize advertisement report for parsing. adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data; adv_data.data_len = p_gap_evt->params.adv_report.dlen; err_code = adv_report_parse(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE, &adv_data, &type_data); if (err_code != NRF_SUCCESS) { // Compare 128 UUID. err_code = adv_report_parse(BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, &adv_data, &type_data); } // Verify if short or complete name matches target. if (err_code == NRF_SUCCESS) { if(!memcmp( nus_service_uuid,type_data.p_data,16)) { // Stop scanning. err_code = sd_ble_gap_scan_stop(); if (err_code != NRF_SUCCESS) { printf("[APPL]: Scan stop failed, reason %d\r\n", (int)err_code); } nrf_gpio_pin_clear(SCAN_LED_PIN_NO); m_scan_param.selective = 0; // Initiate connection. err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.\ peer_addr, &m_scan_param, &m_connection_param); if (err_code != NRF_SUCCESS) { printf("[APPL]: Connection Request Failed, reason %d\r\n", (int)err_code); } break; } // } } break; } case BLE_GAP_EVT_TIMEOUT: if(p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { if (m_scan_mode == BLE_WHITELIST_SCAN) { m_scan_mode = BLE_FAST_SCAN; // Start non selective scanning. scan_start(); } } else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { // } break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Accepting parameters requested by peer. err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, &p_gap_evt->params.conn_param_update_request.conn_params); APP_ERROR_CHECK(err_code); break; default: break; } }