/**@brief Function for handling BLE_GAP_ADV_REPORT events. * Search for a peer with matching device name. * If found, stop advertising and send a connection request to the peer. */ void on_ble_gap_evt_adv_report(ble_gap_evt_t const * p_gap_evt) { if (!find_adv_name(&p_gap_evt->params.adv_report, m_target_periph_name)) { return; } NRF_LOG_INFO("Device \"%s\" found, sending a connection request.\r\n", (uint32_t) m_target_periph_name); // Stop advertising. (void) sd_ble_gap_adv_stop(); // Initiate connection. m_conn_param.min_conn_interval = CONN_INTERVAL_DEFAULT; m_conn_param.max_conn_interval = CONN_INTERVAL_DEFAULT; ret_code_t err_code; err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr, &m_scan_param, &m_conn_param); if (err_code != NRF_SUCCESS) { NRF_LOG_ERROR("sd_ble_gap_connect() failed: 0x%x.\r\n", err_code); } }
/**@brief Function for handling the advertising report BLE event. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_adv_report(const ble_evt_t * const p_ble_evt) { uint32_t err_code; uint8_array_t adv_data; uint8_array_t dev_name; bool do_connect = false; // For readibility. const ble_gap_evt_t * const p_gap_evt = &p_ble_evt->evt.gap_evt; 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.size = p_gap_evt->params.adv_report.dlen; //search for advertising names bool found_name = false; err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &adv_data, &dev_name); if (err_code != NRF_SUCCESS) { // 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) { // If we can't parse the data, then exit return; } else { found_name = true; } } else { found_name = true; } if (found_name) { if (strlen(m_target_periph_name) != 0) { if(memcmp(m_target_periph_name, dev_name.p_data, dev_name.size) == 0) { do_connect = true; } } } 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); } } }
/* Function to request a connection to a previously found device */ bool conn_request_connection(uint8_t device_index) { uint32_t err_code; bool success = false; /* if requested index (from ascii to int) is lower than num of devices */ if(device_index < devices_list_index) { /* store pending connection index */ pending_nus_conn_index = device_index; /* request a connection */ err_code = sd_ble_gap_connect(&found_devices[device_index].gap_addr, &m_scan_params, &m_connection_param); if (err_code == NRF_SUCCESS) { /* success */ success = true; } else { /* connection fail */ } } else { /* invalid device index */ } return success; }
//Connect to a specific peripheral bool GAPController::connectToPeripheral(ble_gap_addr_t* address) { if(currentlyConnecting) return false; currentlyConnecting = true; u32 err = 0; ble_gap_scan_params_t scan_params; ble_gap_conn_params_t conn_params; scan_params.selective = 0; scan_params.active = 0; /* No active scanning */ scan_params.interval = Config->meshConnectingScanInterval; scan_params.window = Config->meshConnectingScanWindow; scan_params.timeout = Config->meshConnectingScanTimeout; conn_params.min_conn_interval = Config->meshMinConnectionInterval; conn_params.max_conn_interval = Config->meshMaxConnectionInterval; conn_params.slave_latency = Config->meshPeripheralSlaveLatency; conn_params.conn_sup_timeout = Config->meshConnectionSupervisionTimeout; //Connect to the peripheral err = sd_ble_gap_connect(address, &scan_params, &conn_params); APP_ERROR_CHECK(err); //Set scan state off. Connecting uses scan itself and deactivates the scan procedure ScanController::scanningState = SCAN_STATE_OFF; logt("CONN", "pairing"); return true; }
ble_error_t nRF5xGap::connect(const Address_t peerAddr, Gap::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParamsIn) { ble_gap_addr_t addr; addr.addr_type = peerAddrType; memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); ble_gap_conn_params_t connParams; if (connectionParams != NULL) { connParams.min_conn_interval = connectionParams->minConnectionInterval; connParams.max_conn_interval = connectionParams->maxConnectionInterval; connParams.slave_latency = connectionParams->slaveLatency; connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; } else { connParams.min_conn_interval = 50; connParams.max_conn_interval = 100; connParams.slave_latency = 0; connParams.conn_sup_timeout = 600; } ble_gap_scan_params_t scanParams; scanParams.selective = 0; /**< If 1, ignore unknown devices (non whitelisted). */ scanParams.p_whitelist = NULL; /**< Pointer to whitelist, NULL if none is given. */ if (scanParamsIn != NULL) { scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ } else { scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ } uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams); if (rc == NRF_SUCCESS) { return BLE_ERROR_NONE; } switch (rc) { case NRF_ERROR_INVALID_ADDR: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_INVALID_PARAM: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_INVALID_STATE: return BLE_ERROR_INVALID_STATE; case BLE_ERROR_GAP_INVALID_BLE_ADDR: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_NO_MEM: return BLE_ERROR_NO_MEM; case NRF_ERROR_BUSY: return BLE_STACK_BUSY; default: case BLE_ERROR_GAP_WHITELIST_IN_USE: return BLE_ERROR_UNSPECIFIED; } }
uint32_t conn_mw_ble_gap_connect(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); ble_gap_addr_t addr; ble_gap_addr_t * p_addr = &addr; ble_gap_scan_params_t scan_params; ble_gap_scan_params_t * p_scan_params = &scan_params; 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; #if NRF_SD_BLE_API_VERSION >= 4 uint8_t conn_cfg_tag; err_code = ble_gap_connect_req_dec(p_rx_buf, rx_buf_len, &p_addr, &p_scan_params, &p_conn_params, &conn_cfg_tag); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_connect(p_addr, p_scan_params, p_conn_params, conn_cfg_tag); #else err_code = ble_gap_connect_req_dec(p_rx_buf, rx_buf_len, &p_addr, &p_scan_params, &p_conn_params); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_connect(p_addr, p_scan_params, p_conn_params); #endif err_code = ble_gap_connect_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
uint32_t conn_mw_ble_gap_connect(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); ble_gap_addr_t addr; ble_gap_addr_t * p_addr = &addr; ble_gap_addr_t * pp_addr_tab[BLE_GAP_WHITELIST_ADDR_MAX_COUNT]; ble_gap_irk_t * pp_irk_tab[BLE_GAP_WHITELIST_IRK_MAX_COUNT]; ble_gap_addr_t addr_tab[BLE_GAP_WHITELIST_ADDR_MAX_COUNT]; ble_gap_irk_t irk_tab[BLE_GAP_WHITELIST_IRK_MAX_COUNT]; for (uint8_t i = 0; i < BLE_GAP_WHITELIST_ADDR_MAX_COUNT; ++i) { pp_addr_tab[i] = &addr_tab[i]; } for (uint8_t i = 0; i < BLE_GAP_WHITELIST_IRK_MAX_COUNT; ++i) { pp_irk_tab[i] = &irk_tab[i]; } ble_gap_whitelist_t whitelist; whitelist.addr_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT; whitelist.pp_addrs = pp_addr_tab; whitelist.irk_count = BLE_GAP_WHITELIST_IRK_MAX_COUNT; whitelist.pp_irks = pp_irk_tab; ble_gap_scan_params_t scan_params; scan_params.p_whitelist = &whitelist; ble_gap_scan_params_t * p_scan_params = &scan_params; 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_connect_req_dec(p_rx_buf, rx_buf_len, &p_addr, &p_scan_params, &p_conn_params); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_connect(p_addr, p_scan_params, p_conn_params); err_code = ble_gap_connect_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
ble_error_t nRF5xGap::connect(const Address_t peerAddr, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParamsIn) { ble_gap_addr_t addr; addr.addr_type = peerAddrType; memcpy(addr.addr, peerAddr, Gap::ADDR_LEN); ble_gap_conn_params_t connParams; if (connectionParams != NULL) { connParams.min_conn_interval = connectionParams->minConnectionInterval; connParams.max_conn_interval = connectionParams->maxConnectionInterval; connParams.slave_latency = connectionParams->slaveLatency; connParams.conn_sup_timeout = connectionParams->connectionSupervisionTimeout; } else { connParams.min_conn_interval = 50; connParams.max_conn_interval = 100; connParams.slave_latency = 0; connParams.conn_sup_timeout = 600; } /* Allocate the stack's whitelist statically */ ble_gap_whitelist_t whitelist; ble_gap_addr_t *whitelistAddressPtrs[YOTTA_CFG_WHITELIST_MAX_SIZE]; ble_gap_irk_t *whitelistIrkPtrs[YOTTA_CFG_IRK_TABLE_MAX_SIZE]; /* Initialize the whitelist */ whitelist.pp_addrs = whitelistAddressPtrs; whitelist.pp_irks = whitelistIrkPtrs; whitelist.addr_count = 0; whitelist.irk_count = 0; /* Add missing IRKs to whitelist from the bond table held by the SoftDevice */ if (scanningPolicyMode != Gap::SCAN_POLICY_IGNORE_WHITELIST) { ble_error_t error = generateStackWhitelist(whitelist); if (error != BLE_ERROR_NONE) { return error; } } ble_gap_scan_params_t scanParams; scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */ scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */ if (scanParamsIn != NULL) { scanParams.active = scanParamsIn->getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ scanParams.interval = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.window = scanParamsIn->getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.timeout = scanParamsIn->getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ } else { scanParams.active = _scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */ scanParams.interval = _scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.window = _scanningParams.getWindow(); /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ scanParams.timeout = _scanningParams.getTimeout(); /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ } uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams); if (rc == NRF_SUCCESS) { return BLE_ERROR_NONE; } switch (rc) { case NRF_ERROR_INVALID_ADDR: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_INVALID_PARAM: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_INVALID_STATE: return BLE_ERROR_INVALID_STATE; case BLE_ERROR_GAP_INVALID_BLE_ADDR: return BLE_ERROR_INVALID_PARAM; case NRF_ERROR_NO_MEM: return BLE_ERROR_NO_MEM; case NRF_ERROR_BUSY: return BLE_STACK_BUSY; default: case BLE_ERROR_GAP_WHITELIST_IN_USE: return BLE_ERROR_UNSPECIFIED; } }
/**@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. * * @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_ADV_REPORT: { data_t adv_data; data_t type_data; // Initialize advertisement report for parsing. adv_data.p_data = p_ble_evt->evt.gap_evt.params.adv_report.data; adv_data.data_len = p_ble_evt->evt.gap_evt.params.adv_report.dlen; err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &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_SHORT_LOCAL_NAME, &adv_data, &type_data); } // Verify if short or complete name matches target. if ((err_code == NRF_SUCCESS) && (0 == memcmp(TARGET_DEV_NAME,type_data.p_data,type_data.data_len))) { 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 = sd_ble_gap_connect(&p_ble_evt->evt.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; } case BLE_GAP_EVT_TIMEOUT: if(p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) { APPL_LOG("[APPL]: Scan Timedout.\r\n"); } else if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN) { APPL_LOG("[APPL]: Connection Request Timedout.\r\n"); } 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_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_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; } }
/**@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; 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; } }