Hi,
I m using nrf52840 board act as central which will connect to particular device, and discover its primary services and characteristics.I am new to nordic development.I am able to discover services.
I am facing issue with conn handle while discovering characteristics results (gattc_status != success)
Please check my code and help to find out the issue.
I was trying to discover 128-bit UUID of services,not succeed in that, so that part is commented in code.
Code changes are done in ble_db_discovery.c:
Attaching ble_db_discovery.c and main.c file.
and also current output of program and expected output of nrfconnect app screenshot.
/** * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "sdk_common.h" #if NRF_MODULE_ENABLED(BLE_DB_DISCOVERY) #include "ble_db_discovery.h" #include <stdlib.h> #include "ble_srv_common.h" #define NRF_LOG_MODULE_NAME ble_db_disc #include "nrf_log.h" NRF_LOG_MODULE_REGISTER(); #define SRV_DISC_START_HANDLE 0x0001 /**< The start handle value used during service discovery. */ #define DB_DISCOVERY_MAX_USERS BLE_DB_DISCOVERY_MAX_SRV /**< The maximum number of users/registrations allowed by this module. */ #define MODULE_INITIALIZED (m_initialized == true) /**< Macro designating whether the module has been initialized properly. */ #define MAX_SERVICE_COUNT 6 #define MAX_CHARACTERISTIC_COUNT 6 #define UUID_BASE {0x04, 0x2c, 0xe1, 0xf4, 0x10, 0xc4, 0x00, 0x00, \ 0x31, 0xad, 0x51, 0x4c, 0x00, 0x00, 0x00, 0x00} // Structure storing data of all discovered services. typedef struct { ble_gattc_service_t services[MAX_SERVICE_COUNT]; /**< Data of the services found. */ uint8_t count; /**< Count of the services found. */ } device_srv_t; typedef struct { ble_uuid_t uuid; /**< UUID of the characteristic. */ uint16_t decl_handle; /**< Handle of the characteristic declaration. */ uint16_t value_handle; /**< Handle of the characteristic value. */ uint16_t cccd_desc_handle; /**< Handle of the CCCD descriptors. */ bool notify; /**< True when notification of the value permitted. */ } char_data_t; // Structure storing the data of all discovered characteristics. typedef struct { char_data_t char_data[MAX_CHARACTERISTIC_COUNT]; /**< Characteristics data. */ uint8_t count; /**< Characteristics count. */ } srv_char_t; device_srv_t * mp_device_srv[1]; /**< Pointers to the allocated memory needed to discover the services on the server. */ srv_char_t m_srv_char; /**< Stores all the characteristics data from one service to allow further operations. */ /**@brief Array of structures containing information about the registered application modules. */ static ble_uuid_t m_registered_handlers[DB_DISCOVERY_MAX_USERS]; bool m_vendor_uuid_read = false; /**< Variable that informs about the read request for a 128-bit service UUID. */ int curr_srv_id; static uint16_t count = 0; /**@brief Array of structures containing pending events to be sent to the application modules. * * @details Whenever a discovery related event is to be raised to a user module, it will be stored * in this array first. When all services needed to be discovered have been * discovered, all pending events will be sent to the corresponding user modules. **/ static struct { ble_db_discovery_evt_t evt; /**< The pending event. */ ble_db_discovery_evt_handler_t evt_handler; /**< The event handler which should be called to raise this event. */ } m_pending_user_evts[DB_DISCOVERY_MAX_USERS]; static ble_db_discovery_evt_handler_t m_evt_handler; static uint32_t m_pending_usr_evt_index; /**< The index to the pending user event array, pointing to the last added pending user event. */ static uint32_t m_num_of_handlers_reg; /**< The number of handlers registered with the DB Discovery module. */ static bool m_initialized = false; /**< This variable Indicates if the module is initialized or not. */ /**@brief Function for fetching the event handler provided by a registered application module. * * @param[in] srv_uuid UUID of the service. * * @retval evt_handler Event handler of the module, registered for the given service UUID. * @retval NULL If no event handler is found. */ static ble_db_discovery_evt_handler_t registered_handler_get(ble_uuid_t const * p_srv_uuid) { for (uint32_t i = 0; i < m_num_of_handlers_reg; i++) { if (BLE_UUID_EQ(&(m_registered_handlers[i]), p_srv_uuid)) { return (m_evt_handler); } } return NULL; } /**@brief Function for storing the event handler provided by a registered application module. * * @param[in] p_srv_uuid The UUID of the service. * @param[in] p_evt_handler The event handler provided by the application. * * @retval NRF_SUCCESS If the handler was stored or already present in the list. * @retval NRF_ERROR_NO_MEM If there is no space left to store the handler. */ static uint32_t registered_handler_set(ble_uuid_t const * p_srv_uuid, ble_db_discovery_evt_handler_t p_evt_handler) { if (registered_handler_get(p_srv_uuid) != NULL) { return NRF_SUCCESS; } if (m_num_of_handlers_reg < DB_DISCOVERY_MAX_USERS) { m_registered_handlers[m_num_of_handlers_reg] = *p_srv_uuid; m_num_of_handlers_reg++; return NRF_SUCCESS; } else { return NRF_ERROR_NO_MEM; } } /**@brief Function for sending all pending discovery events to the corresponding user modules. */ static void pending_user_evts_send(void) { for (uint32_t i = 0; i < m_num_of_handlers_reg; i++) { // Pass the event to the corresponding event handler. m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt)); } m_pending_usr_evt_index = 0; } /**@brief Function for indicating error to the application. * * @details This function will fetch the event handler based on the UUID of the service being * discovered. (The event handler is registered by the application beforehand). * The error code is added to the pending events together with the event handler. * If no event handler was found, then this function will do nothing. * * @param[in] p_db_discovery Pointer to the DB discovery structure. * @param[in] err_code Error code that should be provided to the application. * @param[in] conn_handle Connection Handle. * */ static void discovery_error_evt_trigger(ble_db_discovery_t * p_db_discovery, uint32_t err_code, uint16_t conn_handle) { ble_db_discovery_evt_handler_t p_evt_handler; ble_gatt_db_srv_t * p_srv_being_discovered; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid)); if (p_evt_handler != NULL) { ble_db_discovery_evt_t evt = { .conn_handle = conn_handle, .evt_type = BLE_DB_DISCOVERY_ERROR, .params.err_code = err_code, }; p_evt_handler(&evt); } } /**@brief Function for triggering a Discovery Complete or Service Not Found event to the * application. * * @details This function will fetch the event handler based on the UUID of the service being * discovered. (The event handler is registered by the application beforehand). * It then triggers an event indicating the completion of the service discovery. * If no event handler was found, then this function will do nothing. * * @param[in] p_db_discovery Pointer to the DB discovery structure. * @param[in] is_srv_found Variable to indicate if the service was found at the peer. * @param[in] conn_handle Connection Handle. */ static void discovery_complete_evt_trigger(ble_db_discovery_t * p_db_discovery, bool is_srv_found, uint16_t conn_handle) { ble_db_discovery_evt_handler_t p_evt_handler; ble_gatt_db_srv_t * p_srv_being_discovered; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid)); if (p_evt_handler != NULL) { if (m_pending_usr_evt_index < DB_DISCOVERY_MAX_USERS) { // Insert an event into the pending event list. m_pending_user_evts[m_pending_usr_evt_index].evt.conn_handle = conn_handle; m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db = *p_srv_being_discovered; if (is_srv_found) { m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type = BLE_DB_DISCOVERY_COMPLETE; } else { m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type = BLE_DB_DISCOVERY_SRV_NOT_FOUND; } m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler; m_pending_usr_evt_index++; if (m_pending_usr_evt_index == m_num_of_handlers_reg) { // All registered modules have pending events. Send all pending events to the user // modules. pending_user_evts_send(); } else { // Too many events pending. Do nothing. (Ideally this should not happen.) } } } } /**@brief Function for handling service discovery completion. * * @details This function will be used to determine if there are more services to be discovered, * and if so, initiate the discovery of the next service. * * @param[in] p_db_discovery Pointer to the DB Discovery Structure. * @param[in] conn_handle Connection Handle. */ static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery, uint16_t conn_handle) { p_db_discovery->discoveries_count++; // NRF_LOG_INFO("incremented discovery count:%d",p_db_discovery->discoveries_count); // Check if more services need to be discovered. if (p_db_discovery->discoveries_count < m_num_of_handlers_reg) { // Reset the current characteristic index since a new service discovery is about to start. p_db_discovery->curr_char_ind = 0; // Initiate discovery of the next service. p_db_discovery->curr_srv_ind++; // NRF_LOG_INFO("incremented service index: %d",p_db_discovery->curr_srv_ind); ble_gatt_db_srv_t * p_srv_being_discovered; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind]; // Reset the characteristic count in the current service to zero since a new service // discovery is about to start. p_srv_being_discovered->char_count = 0; NRF_LOG_INFO("Starting discovery of servicce with UUID 0x%x on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, conn_handle); uint32_t err_code; err_code = sd_ble_gattc_primary_services_discover(conn_handle, SRV_DISC_START_HANDLE, &(p_srv_being_discovered->srv_uuid)); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; // Error with discovering the service. // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code, conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = conn_handle; return; } } else { // No more service discovery is needed. p_db_discovery->discovery_in_progress = false; m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = conn_handle; } } /**@brief Function for finding out if a characteristic discovery should be performed after the * last discovered characteristic. * * @details This function is used during the time of database discovery to find out if there is * a need to do more characteristic discoveries. The value handles of the * last discovered characteristic is compared with the end handle of the service. * If the service handle is greater than one of the former characteristic handles, * it means that a characteristic discovery is required. * * @param[in] p_db_discovery The pointer to the DB Discovery structure. * @param[in] p_after_char The pointer to the last discovered characteristic. * * @retval True if a characteristic discovery is required. * @retval False if a characteristic discovery is NOT required. */ /* static bool is_char_discovery_reqd(ble_db_discovery_t * p_db_discovery, ble_gattc_char_t * p_after_char) { if (p_after_char->handle_value < p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle) { // Handle value of the characteristic being discovered is less than the end handle of // the service being discovered. There is a possibility of more characteristics being // present. Hence a characteristic discovery is required. return true; } return false; } */ /**@brief Function to find out if a descriptor discovery is required. * * @details This function finds out if there is a possibility of existence of descriptors between * current characteristic and the next characteristic. If so, this function will compute * the handle range on which the descriptors may be present and will return it. * If the current characteristic is the last known characteristic, then this function * will use the service end handle to find out if the current characteristic can have * descriptors. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_curr_char Pointer to the current characteristic. * @param[in] p_next_char Pointer to the next characteristic. This should be NULL if the * caller knows that there is no characteristic after the current * characteristic at the peer. * @param[out] p_handle_range Pointer to the handle range in which descriptors may exist at the * the peer. * * @retval True If a descriptor discovery is required. * @retval False If a descriptor discovery is NOT required. */ static bool is_desc_discovery_reqd(ble_db_discovery_t * p_db_discovery, ble_gatt_db_char_t * p_curr_char, ble_gatt_db_char_t * p_next_char, ble_gattc_handle_range_t * p_handle_range) { if (p_next_char == NULL) { // Current characteristic is the last characteristic in the service. Check if the value // handle of the current characteristic is equal to the service end handle. if ( p_curr_char->characteristic.handle_value == p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle ) { // No descriptors can be present for the current characteristic. p_curr_char is the last // characteristic with no descriptors. return false; } p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1; // Since the current characteristic is the last characteristic in the service, the end // handle should be the end handle of the service. p_handle_range->end_handle = p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle; return true; } // p_next_char != NULL. Check for existence of descriptors between the current and the next // characteristic. if ((p_curr_char->characteristic.handle_value + 1) == p_next_char->characteristic.handle_decl) { // No descriptors can exist between the two characteristic. return false; } p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1; p_handle_range->end_handle = p_next_char->characteristic.handle_decl - 1; return true; } /**@brief Function for performing characteristic discovery. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] conn_handle Connection Handle. * * @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the characteristic * discovery. Otherwise an error code. This function returns the error code returned * by the SoftDevice API @ref sd_ble_gattc_characteristics_discover. */ static uint32_t characteristics_discover(ble_db_discovery_t * p_db_discovery, uint16_t conn_handle) { ble_gatt_db_srv_t * p_srv_being_discovered; ble_gattc_handle_range_t handle_range; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); handle_range.start_handle = p_srv_being_discovered->handle_range.start_handle; handle_range.end_handle = p_srv_being_discovered->handle_range.end_handle; return sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); } /**@brief Function for performing descriptor discovery, if required. * * @details This function will check if descriptor discovery is required and then perform it if * needed. If no more descriptor discovery is required for the service, then the output * parameter p_raise_discov_complete is set to true, indicating to the caller that a * discovery complete event can be triggered to the application. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[out] p_raise_discov_complete The value pointed to by this pointer will be set to true if * the Discovery Complete event can be triggered to the * application. * @param[in] conn_handle Connection Handle. * * @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the descriptor * discovery, or if no more descriptor discovery is required. Otherwise an error code. * This function returns the error code returned by the SoftDevice API @ref * sd_ble_gattc_descriptors_discover. */ static uint32_t descriptors_discover(ble_db_discovery_t * p_db_discovery, bool * p_raise_discov_complete, uint16_t conn_handle) { ble_gattc_handle_range_t handle_range; ble_gatt_db_char_t * p_curr_char_being_discovered; ble_gatt_db_srv_t * p_srv_being_discovered; bool is_discovery_reqd = false; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_curr_char_being_discovered = &(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]); if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count) { // This is the last characteristic of this service. is_discovery_reqd = is_desc_discovery_reqd(p_db_discovery, p_curr_char_being_discovered, NULL, &handle_range); } else { uint8_t i; ble_gatt_db_char_t * p_next_char; for (i = p_db_discovery->curr_char_ind; i < p_srv_being_discovered->char_count; i++) { if (i == (p_srv_being_discovered->char_count - 1)) { // The current characteristic is the last characteristic in the service. p_next_char = NULL; } else { p_next_char = &(p_srv_being_discovered->charateristics[i + 1]); } // Check if it is possible for the current characteristic to have a descriptor. if (is_desc_discovery_reqd(p_db_discovery, p_curr_char_being_discovered, p_next_char, &handle_range)) { is_discovery_reqd = true; break; } else { // No descriptors can exist. p_curr_char_being_discovered = p_next_char; p_db_discovery->curr_char_ind++; } } } if (!is_discovery_reqd) { // No more descriptor discovery required. Discovery is complete. // This informs the caller that a discovery complete event can be triggered. *p_raise_discov_complete = true; return NRF_SUCCESS; } *p_raise_discov_complete = false; return sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); } /**@brief Function for handling primary service discovery response. * * @details This function will handle the primary service discovery response and start the * discovery of characteristics within that service. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ void on_primary_srv_discovery_rsp(ble_db_discovery_t * p_db_discovery, ble_gattc_evt_t const * p_ble_gattc_evt) { ble_gatt_db_srv_t * p_srv_being_discovered; uint16_t bytes_to_copy; static uint16_t offset = 0; int conn_hdle; conn_hdle = p_ble_gattc_evt->conn_handle; ble_gattc_service_t * const p_service = mp_device_srv[conn_hdle]->services; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { // return; } ble_gattc_evt_prim_srvc_disc_rsp_t const * p_prim_srvc_disc_rsp_evt; uint32_t err_code; p_prim_srvc_disc_rsp_evt = &(p_ble_gattc_evt->params.prim_srvc_disc_rsp); count = p_prim_srvc_disc_rsp_evt->count; NRF_LOG_INFO("service count %d",count); // If no more services are found. if ((count != 0) && (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)) { if ((count + offset) > MAX_SERVICE_COUNT) { bytes_to_copy = MAX_SERVICE_COUNT - offset; } else { bytes_to_copy = count; } // Save services data. memcpy((p_service + offset),p_prim_srvc_disc_rsp_evt->services, bytes_to_copy * sizeof(ble_gattc_service_t)); offset += count; for(curr_srv_id= 0;curr_srv_id <= count; curr_srv_id++ ) { p_srv_being_discovered->srv_uuid = p_prim_srvc_disc_rsp_evt->services[curr_srv_id].uuid; p_srv_being_discovered->handle_range = p_prim_srvc_disc_rsp_evt->services[curr_srv_id].handle_range; NRF_LOG_INFO("Found serviice UUID %x and its start handle:%d , End handle: %d, type:%d, cuur_srv:%d", p_srv_being_discovered->srv_uuid.uuid, p_srv_being_discovered->handle_range.start_handle, p_srv_being_discovered->handle_range.end_handle, p_srv_being_discovered->srv_uuid.type,curr_srv_id); } // If the last service has not been reached, this function must be called again with a new start handle. if(count != 0) { err_code = sd_ble_gattc_primary_services_discover(conn_hdle, p_prim_srvc_disc_rsp_evt->services[count - 1].handle_range.end_handle + 1, NULL); if(err_code == NRF_SUCCESS) { NRF_LOG_INFO("Discovery done successfully.."); } else { NRF_LOG_INFO("Discovery Fail.."); } return; } } /*for (uint8_t i = 0; i < offset; i++) { NRF_LOG_INFO("UUID: %x and its type: %d",p_service[i].uuid.uuid,p_service[i].uuid.type); if (p_service[i].uuid.type == BLE_UUID_TYPE_UNKNOWN) { m_vendor_uuid_read = true; // Read service 128-bit UUID. err_code = sd_ble_gattc_read(conn_hdle, p_service[i].handle_range.start_handle, 0); if(err_code == NRF_SUCCESS) { NRF_LOG_INFO("Read done successfully.."); } else { NRF_LOG_INFO("Read Fail.."); } offset = 0; } else { } }*/ else { if(p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND) { NRF_LOG_INFO("Service UUID 0x%x not found.", p_srv_being_discovered->srv_uuid.uuid); } else if(count == 0) { NRF_LOG_INFO("No other service found"); } // Trigger Service Not Found event to the application. discovery_complete_evt_trigger(p_db_discovery, false, p_ble_gattc_evt->conn_handle); on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle); } err_code = characteristics_discover(p_db_discovery, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; NRF_LOG_INFO("Error with discovering the characteristics"); // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; } offset = 0; } /**@brief Function for handling characteristic discovery response. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ static void on_characteristic_discovery_rsp(ble_db_discovery_t * p_db_discovery, ble_gattc_evt_t const * p_ble_gattc_evt) { uint32_t err_code; // ble_gatt_db_srv_t * p_srv_being_discovered; uint16_t bytes_to_copy; // bool perform_desc_discov = false; uint16_t charr_count; static uint16_t char_offset = 0; uint16_t conn_handle = p_ble_gattc_evt->conn_handle; if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { //return; } charr_count = p_ble_gattc_evt->params.char_disc_rsp.count; NRF_LOG_RAW_INFO("characteristics at start: %d\r\n", charr_count); if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) { NRF_LOG_INFO("In success\r\n"); ble_gattc_evt_char_disc_rsp_t const * p_char_disc_rsp_evt; p_char_disc_rsp_evt = &(p_ble_gattc_evt->params.char_disc_rsp); uint32_t i; //uint32_t j; if ((charr_count + char_offset) > MAX_CHARACTERISTIC_COUNT) { bytes_to_copy = MAX_CHARACTERISTIC_COUNT - char_offset; NRF_LOG_RAW_INFO("Too many characteristics discovered\r\n"); } else { bytes_to_copy = charr_count; } // Save characteristics data. for (uint8_t i = char_offset; i < bytes_to_copy; i++) { m_srv_char.char_data[i].decl_handle = p_char_disc_rsp_evt->chars[i].handle_decl; m_srv_char.char_data[i].value_handle = p_char_disc_rsp_evt->chars[i].handle_value; m_srv_char.char_data[i].uuid = p_char_disc_rsp_evt->chars[i].uuid; m_srv_char.char_data[i].notify = p_char_disc_rsp_evt->chars[i].char_props.notify; m_srv_char.char_data[i].cccd_desc_handle = 0; char_offset++; } // Display characteristics data. for (i = 0; i < char_offset; i++) { ble_gatt_char_props_t char_param = p_ble_gattc_evt->params.char_disc_rsp.chars[i].char_props; NRF_LOG_RAW_INFO("Characteristic UUID: %X\r\n", p_ble_gattc_evt->params.char_disc_rsp.chars[i].uuid.uuid); NRF_LOG_RAW_INFO("Parameters:\r\n"); NRF_LOG_RAW_INFO("broadcast: %d ", char_param.broadcast); NRF_LOG_RAW_INFO("read: %d ", char_param.read); NRF_LOG_RAW_INFO("write_wo_resp: %d ", char_param.write_wo_resp); NRF_LOG_RAW_INFO("write: %d ", char_param.write); NRF_LOG_RAW_INFO("notify: %d\r\n", char_param.notify); NRF_LOG_RAW_INFO("indicate: %d ", char_param.indicate); NRF_LOG_RAW_INFO("auth_signed_wr: %d\r\n", char_param.auth_signed_wr); } } // If the last characteristic has not been reached, look for a new handle range. ble_gattc_handle_range_t handle_range; handle_range.start_handle = m_srv_char.char_data[char_offset - 1].value_handle + 1; // Search for end handle. for (uint8_t j = 0; j < mp_device_srv[conn_handle]->count; j++) { if (handle_range.start_handle > mp_device_srv[conn_handle]->services[j].handle_range.start_handle) { handle_range.end_handle = mp_device_srv[conn_handle]->services[j].handle_range.end_handle; break; } } // Handle value of the characteristic being discovered is less than the end handle of // the service being discovered. There is no possibility of more characteristics being // present. if ((m_srv_char.char_data[char_offset - 1].value_handle >= handle_range.end_handle) || (char_offset == MAX_CHARACTERISTIC_COUNT) || (p_ble_gattc_evt->gatt_status != BLE_GATT_STATUS_SUCCESS)) { NRF_LOG_RAW_INFO("characteristics at end: %d\r\n", char_offset); m_srv_char.count = char_offset; char_offset = 0; // Search for the CCCD descriptors. // descriptors_discover(p_ble_gattc_evt); return; } // If the last Characteristic has not been reached, this function must be called again with new handle range. err_code = sd_ble_gattc_characteristics_discover(p_ble_gattc_evt->conn_handle, &handle_range); if(err_code == NRF_SUCCESS) { NRF_LOG_INFO("Char Discovery done successfully.."); } else { NRF_LOG_INFO("Char Discovery Fail.."); } } /**@brief Function for handling descriptor discovery response. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GATT Client event. */ static void on_descriptor_discovery_rsp(ble_db_discovery_t * const p_db_discovery, const ble_gattc_evt_t * const p_ble_gattc_evt) { const ble_gattc_evt_desc_disc_rsp_t * p_desc_disc_rsp_evt; ble_gatt_db_srv_t * p_srv_being_discovered; if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle) { return; } p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_desc_disc_rsp_evt = &(p_ble_gattc_evt->params.desc_disc_rsp); ble_gatt_db_char_t * p_char_being_discovered = &(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]); if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS) { // The descriptor was found at the peer. // Iterate through and collect CCCD, Extended Properties, // User Description & Report Reference descriptor handles. for (uint32_t i = 0; i < p_desc_disc_rsp_evt->count; i++) { switch (p_desc_disc_rsp_evt->descs[i].uuid.uuid) { case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: p_char_being_discovered->cccd_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP: p_char_being_discovered->ext_prop_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: p_char_being_discovered->user_desc_handle = p_desc_disc_rsp_evt->descs[i].handle; break; case BLE_UUID_REPORT_REF_DESCR: p_char_being_discovered->report_ref_handle = p_desc_disc_rsp_evt->descs[i].handle; break; } /* Break if we've found all the descriptors we are looking for. */ if (p_char_being_discovered->cccd_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->ext_prop_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->user_desc_handle != BLE_GATT_HANDLE_INVALID && p_char_being_discovered->report_ref_handle != BLE_GATT_HANDLE_INVALID) { break; } } } bool raise_discov_complete = false; if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count) { // No more characteristics and descriptors need to be discovered. Discovery is complete. // Send a discovery complete event to the user application. raise_discov_complete = true; } else { // Begin discovery of descriptors for the next characteristic. uint32_t err_code; p_db_discovery->curr_char_ind++; err_code = descriptors_discover(p_db_discovery, &raise_discov_complete, p_ble_gattc_evt->conn_handle); if (err_code != NRF_SUCCESS) { p_db_discovery->discovery_in_progress = false; // Error with discovering the service. // Indicate the error to the registered user application. discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle); m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE; m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle; return; } } if (raise_discov_complete) { NRF_LOG_DEBUG("Discovery of service with UUID 0x%x completed with success" " on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, p_ble_gattc_evt->conn_handle); discovery_complete_evt_trigger(p_db_discovery, true, p_ble_gattc_evt->conn_handle); on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle); } } static void on_read_rsp(const ble_gattc_evt_t * const p_ble_gattc_evt) { uint32_t err_code; uint16_t conn_handle = p_ble_gattc_evt->conn_handle; ble_uuid128_t uuid = {UUID_BASE}; const ble_gattc_evt_read_rsp_t * p_read_rsp = &(p_ble_gattc_evt->params.read_rsp); NRF_LOG_INFO("Read data = 0x%x,0x%x",p_read_rsp->data[13],p_read_rsp->data[14]); NRF_LOG_INFO("Read_rsp_len: %d",p_read_rsp->len); if (m_vendor_uuid_read) { for (uint8_t i = 0; i < mp_device_srv[conn_handle]->count; i++) { // if (p_read_rsp->len == 16) if (p_read_rsp->handle == mp_device_srv[conn_handle]->services[i].handle_range.start_handle) { //lint -save -e420 memcpy(uuid.uuid128, p_read_rsp->data, sizeof(uuid.uuid128)); //lint -restore err_code = sd_ble_uuid_vs_add(&uuid, &mp_device_srv[conn_handle]->services[i].uuid.type); if(err_code == NRF_SUCCESS) { NRF_LOG_INFO("Adding 128-bit UUID done successfully.."); //NRF_LOG_INFO("128-bit UUID : %x",uuid.uuid128); } else { NRF_LOG_INFO("Adding 128-bit UUID Fail.."); } break; } } return; } } uint32_t ble_db_discovery_init(const ble_db_discovery_evt_handler_t evt_handler) { uint32_t err_code = NRF_SUCCESS; VERIFY_PARAM_NOT_NULL(evt_handler); m_num_of_handlers_reg = 0; m_initialized = true; m_pending_usr_evt_index = 0; m_evt_handler = evt_handler; return err_code; } uint32_t ble_db_discovery_close() { m_num_of_handlers_reg = 0; m_initialized = false; m_pending_usr_evt_index = 0; return NRF_SUCCESS; } uint32_t ble_db_discovery_evt_register(ble_uuid_t const * p_uuid) { VERIFY_PARAM_NOT_NULL(p_uuid); VERIFY_MODULE_INITIALIZED(); return registered_handler_set(p_uuid, m_evt_handler); } static uint32_t discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle) { uint32_t err_code; ble_gatt_db_srv_t * p_srv_being_discovered; memset(p_db_discovery, 0x00, sizeof(ble_db_discovery_t)); p_db_discovery->conn_handle = conn_handle; m_pending_usr_evt_index = 0; p_db_discovery->discoveries_count = 0; p_db_discovery->curr_srv_ind = 0; p_db_discovery->curr_char_ind = 0; p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]); p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind]; NRF_LOG_DEBUG("Starting discovery of service with UUID 0x%x on connection handle 0x%x.", p_srv_being_discovered->srv_uuid.uuid, conn_handle); err_code = sd_ble_gattc_primary_services_discover(conn_handle, SRV_DISC_START_HANDLE, &(p_srv_being_discovered->srv_uuid)); if (err_code != NRF_ERROR_BUSY) { VERIFY_SUCCESS(err_code); p_db_discovery->discovery_in_progress = true; p_db_discovery->discovery_pending = false; } else { p_db_discovery->discovery_in_progress = true; p_db_discovery->discovery_pending = true; } return NRF_SUCCESS; } uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle) { VERIFY_PARAM_NOT_NULL(p_db_discovery); VERIFY_MODULE_INITIALIZED(); if (m_num_of_handlers_reg == 0) { // No user modules were registered. There are no services to discover. return NRF_ERROR_INVALID_STATE; } if (p_db_discovery->discovery_in_progress) { return NRF_ERROR_BUSY; } return discovery_start(p_db_discovery, conn_handle); } /**@brief Function for handling disconnected event. * * @param[in] p_db_discovery Pointer to the DB Discovery structure. * @param[in] p_ble_gattc_evt Pointer to the GAP event. */ static void on_disconnected(ble_db_discovery_t * p_db_discovery, ble_gap_evt_t const * p_evt) { if (p_evt->conn_handle == p_db_discovery->conn_handle) { p_db_discovery->discovery_in_progress = false; p_db_discovery->discovery_pending = false; p_db_discovery->conn_handle = BLE_CONN_HANDLE_INVALID; } } void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) { VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt); VERIFY_PARAM_NOT_NULL_VOID(p_context); VERIFY_MODULE_INITIALIZED_VOID(); //NRF_LOG_INFO("In ble_discovery_evt function"); ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context; switch (p_ble_evt->header.evt_id) { case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: NRF_LOG_INFO("Found services in............."); on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt)); break; case BLE_GATTC_EVT_CHAR_DISC_RSP: on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt)); NRF_LOG_INFO("In Charcteristics rsp"); break; case BLE_GATTC_EVT_DESC_DISC_RSP: on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt)); break; case BLE_GAP_EVT_DISCONNECTED: on_disconnected(p_db_discovery, &(p_ble_evt->evt.gap_evt)); break; case BLE_GATTC_EVT_READ_RSP: on_read_rsp(&(p_ble_evt->evt.gattc_evt)); NRF_LOG_INFO("Read_Rsp"); break; default: break; } if ( (p_db_discovery->discovery_pending) && (p_ble_evt->header.evt_id >= BLE_GATTC_EVT_BASE) && (p_ble_evt->header.evt_id <= BLE_GATTC_EVT_LAST) && (p_ble_evt->evt.gattc_evt.conn_handle == p_db_discovery->conn_handle)) { (void)discovery_start(p_db_discovery, p_db_discovery->conn_handle); } } #endif // NRF_MODULE_ENABLED(BLE_DB_DISCOVERY)
/** * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** * @brief BLE LED Button Service central and client application main file. * * This file contains the source code for a sample client application using the LED Button service. */ #include <stdint.h> #include <stdio.h> #include <string.h> #include "nrf_sdh.h" #include "nrf_sdh_ble.h" #include "nrf_sdh_soc.h" #include "nrf_pwr_mgmt.h" #include "app_timer.h" #include "boards.h" #include "bsp.h" #include "bsp_btn_ble.h" #include "ble.h" #include "ble_hci.h" #include "ble_advertising.h" #include "ble_conn_params.h" #include "ble_db_discovery.h" #include "ble_lbs_c.h" #include "nrf_ble_gatt.h" #include "nrf_ble_scan.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #define CENTRAL_SCANNING_LED BSP_BOARD_LED_0 /**< Scanning LED will be on when the device is scanning. */ #define CENTRAL_CONNECTED_LED BSP_BOARD_LED_1 /**< Connected LED will be on when the device is connected. */ #define LEDBUTTON_LED BSP_BOARD_LED_2 /**< LED to indicate a change of state of the the Button characteristic on the peer. */ #define SCAN_INTERVAL 0x00A0 /**< Determines scan interval in units of 0.625 millisecond. */ #define SCAN_WINDOW 0x0050 /**< Determines scan window in units of 0.625 millisecond. */ #define SCAN_DURATION 0x0000 /**< Timout when scanning. 0x0000 disables timeout. */ #define MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) /**< Determines minimum connection interval in milliseconds. */ #define MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS) /**< Determines maximum connection interval in milliseconds. */ #define SLAVE_LATENCY 0 /**< Determines slave latency in terms of connection events. */ #define SUPERVISION_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Determines supervision time-out in units of 10 milliseconds. */ #define LEDBUTTON_BUTTON_PIN BSP_BUTTON_0 /**< Button that will write to the LED characteristic of the peer */ #define SCANNING_BUTTON BSP_BUTTON_3 /**< abort any connections if any and start advertising/scan , non connectable scannable packets */ #define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50) /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */ #define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ #define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */ NRF_BLE_SCAN_DEF(m_scan); /**< Scanning module instance. */ BLE_LBS_C_DEF(m_ble_lbs_c); /**< Main structure used by the LBS client module. */ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ BLE_DB_DISCOVERY_DEF(m_db_disc); /**< DB discovery module instance. */ #define SRV_DISC_START_HANDLE 0x0001 /**< The start handle value used during service discovery. */ static char const m_target_periph_name[] = "RW2-000404919"; /**< Name of the device we try to connect to. This name is searched in the scan report data*/ /**@brief Function to handle asserts in the SoftDevice. * * @details This function will be called in case of an assert in the SoftDevice. * * @warning This handler is an example only and does not fit a final product. You need to analyze * how your product is supposed to react in case of Assert. * @warning On assert from the SoftDevice, the system can only recover on reset. * * @param[in] line_num Line number of the failing ASSERT call. * @param[in] p_file_name File name of the failing ASSERT call. */ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) { app_error_handler(0xDEADBEEF, line_num, p_file_name); } /**@brief Function for the LEDs initialization. * * @details Initializes all LEDs used by the application. */ static void leds_init(void) { bsp_board_init(BSP_INIT_LEDS); } /**@brief Function for enabling button input. */ static void buttons_enable(void) { ret_code_t err_code = app_button_enable(); APP_ERROR_CHECK(err_code); } /**@brief Function to start scanning. */ static void scan_start(void) { ret_code_t err_code; NRF_LOG_INFO("Start scanning."); err_code = nrf_ble_scan_start(&m_scan); APP_ERROR_CHECK(err_code); bsp_board_led_off(CENTRAL_CONNECTED_LED); bsp_board_led_on(CENTRAL_SCANNING_LED); } /**@brief Handles events coming from the LED Button central module. */ /* static void lbs_c_evt_handler(ble_lbs_c_t * p_lbs_c, ble_lbs_c_evt_t * p_lbs_c_evt) { switch (p_lbs_c_evt->evt_type) { case BLE_LBS_C_EVT_DISCOVERY_COMPLETE: { ret_code_t err_code; err_code = ble_lbs_c_handles_assign(&m_ble_lbs_c, p_lbs_c_evt->conn_handle, &p_lbs_c_evt->params.peer_db); NRF_LOG_INFO("LED Button service discovered on conn_handle 0x%x.", p_lbs_c_evt->conn_handle); err_code = app_button_enable(); APP_ERROR_CHECK(err_code); // LED Button service discovered. Enable notification of Button. err_code = ble_lbs_c_button_notif_enable(p_lbs_c); APP_ERROR_CHECK(err_code); } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE case BLE_LBS_C_EVT_BUTTON_NOTIFICATION: { NRF_LOG_INFO("Button state changed on peer to 0x%x.", p_lbs_c_evt->params.button.button_state); if (p_lbs_c_evt->params.button.button_state) { bsp_board_led_on(LEDBUTTON_LED); } else { bsp_board_led_off(LEDBUTTON_LED); } } break; // BLE_LBS_C_EVT_BUTTON_NOTIFICATION default: // No implementation needed. break; } } */ /**@brief Function for handling BLE events. * * @param[in] p_ble_evt Bluetooth stack event. * @param[in] p_context Unused. */ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) { ret_code_t err_code; // For readability. ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; // ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context; // ble_uuid128_t base_uuid = {UUID_BASE}; // uint8_t uuidType = 2; 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: NRF_LOG_INFO("Connected."); err_code = sd_ble_gattc_primary_services_discover(p_gap_evt->conn_handle, SRV_DISC_START_HANDLE,NULL); APP_ERROR_CHECK(err_code); if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("Discovery done successfully.."); } // peripherals to connect to. bsp_board_led_on(CENTRAL_CONNECTED_LED); bsp_board_led_off(CENTRAL_SCANNING_LED); break; // Upon disconnection, reset the connection handle of the peer which disconnected, update // the LEDs status and start scanning again. case BLE_GAP_EVT_DISCONNECTED: { NRF_LOG_INFO("Disconnected"); scan_start(); } break; 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) { NRF_LOG_DEBUG("Connection request timed out."); } } break; case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { // Accept 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_PHY_UPDATE_REQUEST: { NRF_LOG_DEBUG("PHY update request."); ble_gap_phys_t const phys = { .rx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO, }; err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys); APP_ERROR_CHECK(err_code); } break; case BLE_GATTC_EVT_TIMEOUT: { // Disconnect on GATT Client timeout event. NRF_LOG_DEBUG("GATT Client Timeout."); err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } break; case BLE_GATTS_EVT_TIMEOUT: { // Disconnect on GATT Server timeout event. NRF_LOG_DEBUG("GATT Server Timeout."); err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); } break; default: // No implementation needed. break; } } /**@brief LED Button client initialization. */ /* static void lbs_c_init(void) { ret_code_t err_code; ble_lbs_c_init_t lbs_c_init_obj; lbs_c_init_obj.evt_handler = lbs_c_evt_handler; err_code = ble_lbs_c_init(&m_ble_lbs_c, &lbs_c_init_obj); APP_ERROR_CHECK(err_code); } */ /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupts. */ static void ble_stack_init(void) { ret_code_t err_code; err_code = nrf_sdh_enable_request(); APP_ERROR_CHECK(err_code); // Configure the BLE stack using the default settings. // Fetch the start address of the application RAM. uint32_t ram_start = 0; err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); APP_ERROR_CHECK(err_code); // Enable BLE stack. err_code = nrf_sdh_ble_enable(&ram_start); APP_ERROR_CHECK(err_code); // Register a handler for BLE events. NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); } /**@brief Function for handling events from the button handler module. * * @param[in] pin_no The pin that the event applies to. * @param[in] button_action The button action (press/release). */ static void button_event_handler(uint8_t pin_no, uint8_t button_action) { ret_code_t err_code; switch (pin_no) { case LEDBUTTON_BUTTON_PIN: err_code = ble_lbs_led_status_send(&m_ble_lbs_c, button_action); if (err_code != NRF_SUCCESS && err_code != BLE_ERROR_INVALID_CONN_HANDLE && err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("LBS write LED state %d", button_action); } break; case SCANNING_BUTTON: scan_start(); break; default: APP_ERROR_HANDLER(pin_no); break; } } /**@brief Function for handling Scaning events. * * @param[in] p_scan_evt Scanning event. */ static void scan_evt_handler(scan_evt_t const * p_scan_evt) { ret_code_t err_code; switch(p_scan_evt->scan_evt_id) { case NRF_BLE_SCAN_EVT_CONNECTING_ERROR: err_code = p_scan_evt->params.connecting_err.err_code; APP_ERROR_CHECK(err_code); break; default: break; } } /**@brief Function for initializing the button handler module. */ static void buttons_init(void) { ret_code_t err_code; //The array must be static because a pointer to it will be saved in the button handler module. static app_button_cfg_t buttons[] = { {LEDBUTTON_BUTTON_PIN, false, BUTTON_PULL, button_event_handler}, {SCANNING_BUTTON, false, BUTTON_PULL, button_event_handler} }; err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY); APP_ERROR_CHECK(err_code); } /**@brief Function for handling database discovery events. * * @details This function is callback function to handle events from the database discovery module. * Depending on the UUIDs that are discovered, this function should forward the events * to their respective services. * * @param[in] p_event Pointer to the database discovery event. */ static void db_disc_handler(ble_db_discovery_evt_t * p_evt) { ble_lbs_on_db_disc_evt(&m_ble_lbs_c, p_evt); } /**@brief Database discovery initialization. */ static void db_discovery_init(void) { ret_code_t err_code = ble_db_discovery_init(db_disc_handler); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the log. */ static void log_init(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } /**@brief Function for initializing the timer. */ static void timer_init(void) { ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the Power manager. */ static void power_management_init(void) { ret_code_t err_code; err_code = nrf_pwr_mgmt_init(); APP_ERROR_CHECK(err_code); } static void scan_init(void) { ret_code_t err_code; nrf_ble_scan_init_t init_scan; memset(&init_scan, 0, sizeof(init_scan)); init_scan.connect_if_match = true; init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG; err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name); APP_ERROR_CHECK(err_code); // Setting filters for scanning. err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the GATT module. */ static void gatt_init(void) { ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL); APP_ERROR_CHECK(err_code); } /**@ Function for settings scan filters. */ /* static void scan_filters_set(void) { ret_code_t err_code; //ble_uuid_t target_uuid = {.uuid = TARGET_UUID, .type = BLE_UUID_TYPE_BLE}; err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name); APP_ERROR_CHECK(err_code); err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false); } */ /**@brief Function for handling the idle state (main loop). * * @details Handle any pending log operation(s), then sleep until the next event occurs. */ static void idle_state_handle(void) { NRF_LOG_FLUSH(); nrf_pwr_mgmt_run(); } int main(void) { // Initialize. log_init(); timer_init(); leds_init(); buttons_init(); power_management_init(); ble_stack_init(); scan_init(); gatt_init(); db_discovery_init(); //lbs_c_init(); buttons_enable(); // Start execution. NRF_LOG_INFO("Blinky CENTRAL example started."); NRF_LOG_INFO("Press button 4 to start scanning."); // Turn on the LED to signal scanning. //bsp_board_led_on(CENTRAL_SCANNING_LED); // Enter main loop. for (;;) { idle_state_handle(); } }
Output on terminal:
<info> app: Blinky CENTRAL example started.
<info> app: Press button 4 to start scanning.
<info> app: Start scanning.
<info> app: Connected.
<info> app: Discovery done successfully..
<info> ble_db_disc: Found services in.............
<info> ble_db_disc: service count 3
<info> ble_db_disc: Found serviice UUID 1800 and its start handle:1 , End handle: 7, type:1, cuur_srv:0
<info> ble_db_disc: Found serviice UUID 1801 and its start handle:8 , End handle: 11, type:1, cuur_srv:1
<info> ble_db_disc: Found serviice UUID 180A and its start handle:12 , End handle: 20, type:1, cuur_srv:2
<info> ble_db_disc: Found serviice UUID 5D4 and its start handle:0 , End handle: 0, type:0, cuur_srv:3
<info> ble_db_disc: Discovery done successfully..
<info> ble_db_disc: Found services in.............
<info> ble_db_disc: service count 1
<info> ble_db_disc: Found serviice UUID 0 and its start handle:21 , End handle: 65535, type:0, cuur_srv:0
<info> ble_db_disc: Found serviice UUID 1B8E and its start handle:80 , End handle: 8192, type:0, cuur_srv:1
<info> ble_db_disc: Discovery done successfully..
<info> ble_db_disc: Found services in.............
<info> ble_db_disc: service count 0
<info> ble_db_disc: No other service found
characteristics at start: 0
characteristics at end: 0
<info> ble_db_disc: In Charcteristics rsp
Regards,
Prajakta