BLE_Nano nRF51 Central heart rate

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.c Source File

main.c

00001 /*
00002  * Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
00003  *
00004  * The information contained herein is confidential property of Nordic Semiconductor. The use,
00005  * copying, transfer or disclosure of such information is prohibited except by express written
00006  * agreement with Nordic Semiconductor.
00007  *
00008  */
00009 
00010 /** 
00011  * @brief BLE Heart Rate Collector application main file.
00012  *
00013  * This file contains the source code for a sample heart rate collector.
00014  */
00015 
00016 #include <stdint.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019 #include "nordic_common.h"
00020 #include "nrf_sdm.h"
00021 #include "ble.h"
00022 #include "ble_hci.h"
00023 #include "ble_db_discovery.h "
00024 #include "softdevice_handler.h "
00025 #include "app_util.h "
00026 #include "app_error.h "
00027 #include "boards.h"
00028 #include "nrf_gpio.h"
00029 #include "pstorage.h"
00030 #include "device_manager.h"
00031 #include "ble_hrs_c.h"
00032 #include "ble_bas_c.h"
00033 #include "app_util.h "
00034 #include "app_timer.h"
00035 #include "bsp.h"
00036 #include "bsp_btn_ble.h"
00037 #include "nrf_log.h"
00038 
00039 #define CENTRAL_LINK_COUNT         1                                  /**< Number of central links used by the application. When changing this number remember to adjust the RAM settings*/
00040 #define PERIPHERAL_LINK_COUNT      0                                  /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
00041 
00042 #define STRING_BUFFER_LEN          50
00043 #define BOND_DELETE_ALL_BUTTON_ID  0                                  /**< Button used for deleting all bonded centrals during startup. */
00044 
00045 #define APP_TIMER_PRESCALER        0                                  /**< Value of the RTC1 PRESCALER register. */
00046 #define APP_TIMER_OP_QUEUE_SIZE    2                                  /**< Size of timer operation queues. */
00047 
00048 #define APPL_LOG                   NRF_LOG_PRINTF                     /**< Logger macro that will be used in this file to do logging over UART or RTT based on nrf_log configuration. */
00049 #define APPL_LOG_DEBUG             NRF_LOG_PRINTF_DEBUG               /**< Debug logger macro that will be used in this file to do logging of debug information over UART or RTT based on nrf_log configuration. This will only work if DEBUG is defined*/
00050 
00051 #define SEC_PARAM_BOND             1                                  /**< Perform bonding. */
00052 #define SEC_PARAM_MITM             1                                  /**< Man In The Middle protection not required. */
00053 #define SEC_PARAM_LESC             0                                  /**< LE Secure Connections not enabled. */
00054 #define SEC_PARAM_KEYPRESS         0                                  /**< Keypress notifications not enabled. */
00055 #define SEC_PARAM_IO_CAPABILITIES  BLE_GAP_IO_CAPS_NONE               /**< No I/O capabilities. */
00056 #define SEC_PARAM_OOB              0                                  /**< Out Of Band data not available. */
00057 #define SEC_PARAM_MIN_KEY_SIZE     7                                  /**< Minimum encryption key size. */
00058 #define SEC_PARAM_MAX_KEY_SIZE     16                                 /**< Maximum encryption key size. */
00059 
00060 #define SCAN_INTERVAL              0x00A0                             /**< Determines scan interval in units of 0.625 millisecond. */
00061 #define SCAN_WINDOW                0x0050                             /**< Determines scan window in units of 0.625 millisecond. */
00062 
00063 #define MIN_CONNECTION_INTERVAL    MSEC_TO_UNITS(7.5, UNIT_1_25_MS)   /**< Determines minimum connection interval in millisecond. */
00064 #define MAX_CONNECTION_INTERVAL    MSEC_TO_UNITS(30, UNIT_1_25_MS)    /**< Determines maximum connection interval in millisecond. */
00065 #define SLAVE_LATENCY              0                                  /**< Determines slave latency in counts of connection events. */
00066 #define SUPERVISION_TIMEOUT        MSEC_TO_UNITS(4000, UNIT_10_MS)    /**< Determines supervision time-out in units of 10 millisecond. */
00067 
00068 #define TARGET_UUID                0x180D                             /**< Target device name that application is looking for. */
00069 #define UUID16_SIZE                2                                  /**< Size of 16 bit UUID */
00070 
00071 /**@breif Macro to unpack 16bit unsigned UUID from octet stream. */
00072 #define UUID16_EXTRACT(DST, SRC) \
00073     do                           \
00074     {                            \
00075         (*(DST))   = (SRC)[1];   \
00076         (*(DST)) <<= 8;          \
00077         (*(DST))  |= (SRC)[0];   \
00078     } while (0)
00079 
00080 /**@brief Variable length data encapsulation in terms of length and pointer to data */
00081 typedef struct
00082 {
00083     uint8_t     * p_data;                                             /**< Pointer to data. */
00084     uint16_t      data_len;                                           /**< Length of data. */
00085 }data_t;
00086 
00087 typedef enum
00088 {
00089     BLE_NO_SCAN,                                                     /**< No advertising running. */
00090     BLE_WHITELIST_SCAN,                                              /**< Advertising with whitelist. */
00091     BLE_FAST_SCAN,                                                   /**< Fast advertising running. */
00092 } ble_scan_mode_t;
00093 
00094 static ble_db_discovery_t           m_ble_db_discovery;                  /**< Structure used to identify the DB Discovery module. */
00095 static ble_hrs_c_t                  m_ble_hrs_c;                         /**< Structure used to identify the heart rate client module. */
00096 static ble_bas_c_t                  m_ble_bas_c;                         /**< Structure used to identify the Battery Service client module. */
00097 static ble_gap_scan_params_t        m_scan_param;                        /**< Scan parameters requested for scanning and connection. */
00098 static dm_application_instance_t    m_dm_app_id;                         /**< Application identifier. */
00099 static dm_handle_t                  m_dm_device_handle;                  /**< Device Identifier identifier. */
00100 static uint8_t                      m_peer_count = 0;                    /**< Number of peer's connected. */
00101 static ble_scan_mode_t              m_scan_mode = BLE_FAST_SCAN;         /**< Scan mode used by application. */
00102 static uint16_t                     m_conn_handle;                       /**< Current connection handle. */
00103 static volatile bool                m_whitelist_temporarily_disabled = false; /**< True if whitelist has been temporarily disabled. */
00104 
00105 static bool                         m_memory_access_in_progress = false; /**< Flag to keep track of ongoing operations on persistent memory. */
00106 
00107 /**
00108  * @brief Connection parameters requested for connection.
00109  */
00110 static const ble_gap_conn_params_t m_connection_param =
00111 {
00112     (uint16_t)MIN_CONNECTION_INTERVAL,   // Minimum connection
00113     (uint16_t)MAX_CONNECTION_INTERVAL,   // Maximum connection
00114     0,                                   // Slave latency
00115     (uint16_t)SUPERVISION_TIMEOUT        // Supervision time-out
00116 };
00117 
00118 static void scan_start(void);
00119 
00120 
00121 /**@brief Function for asserts in the SoftDevice.
00122  *
00123  * @details This function will be called in case of an assert in the SoftDevice.
00124  *
00125  * @warning This handler is an example only and does not fit a final product. You need to analyze
00126  *          how your product is supposed to react in case of Assert.
00127  * @warning On assert from the SoftDevice, the system can only recover on reset.
00128  *
00129  * @param[in] line_num     Line number of the failing ASSERT call.
00130  * @param[in] p_file_name  File name of the failing ASSERT call.
00131  */
00132 void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
00133 {
00134     app_error_handler(0xDEADBEEF, line_num, p_file_name);
00135 }
00136 
00137 void uart_error_handle(app_uart_evt_t * p_event)
00138 {
00139     if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
00140     {
00141         APP_ERROR_HANDLER(p_event->data.error_communication);
00142     }
00143     else if (p_event->evt_type == APP_UART_FIFO_ERROR)
00144     {
00145         APP_ERROR_HANDLER(p_event->data.error_code);
00146     }
00147 }
00148 
00149 
00150 /**@brief Function for handling database discovery events.
00151  *
00152  * @details This function is callback function to handle events from the database discovery module.
00153  *          Depending on the UUIDs that are discovered, this function should forward the events
00154  *          to their respective services.
00155  *
00156  * @param[in] p_event  Pointer to the database discovery event.
00157  */
00158 static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
00159 {
00160     ble_hrs_on_db_disc_evt(&m_ble_hrs_c, p_evt);
00161     ble_bas_on_db_disc_evt(&m_ble_bas_c, p_evt);
00162 }
00163 
00164 
00165 /**@brief Callback handling device manager events.
00166  *
00167  * @details This function is called to notify the application of device manager events.
00168  *
00169  * @param[in]   p_handle      Device Manager Handle. For link related events, this parameter
00170  *                            identifies the peer.
00171  * @param[in]   p_event       Pointer to the device manager event.
00172  * @param[in]   event_status  Status of the event.
00173  */
00174 static ret_code_t device_manager_event_handler(const dm_handle_t    * p_handle,
00175                                                  const dm_event_t     * p_event,
00176                                                  const ret_code_t     event_result)
00177 {
00178     uint32_t err_code;
00179 
00180     switch (p_event->event_id)
00181     {
00182         case DM_EVT_CONNECTION:
00183         {
00184             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_CONNECTION\r\n");
00185 #ifdef ENABLE_DEBUG_LOG_SUPPORT
00186             ble_gap_addr_t * peer_addr;
00187             peer_addr = &p_event->event_param.p_gap_param->params.connected.peer_addr;
00188             APPL_LOG_DEBUG("[APPL]:[%02X %02X %02X %02X %02X %02X]: Connection Established\r\n",
00189                                 peer_addr->addr[0], peer_addr->addr[1], peer_addr->addr[2],
00190                                 peer_addr->addr[3], peer_addr->addr[4], peer_addr->addr[5]);
00191 #endif // ENABLE_DEBUG_LOG_SUPPORT
00192             
00193             err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
00194             APP_ERROR_CHECK(err_code);
00195 
00196             m_conn_handle = p_event->event_param.p_gap_param->conn_handle;
00197 
00198             m_dm_device_handle = (*p_handle);
00199 
00200             // Initiate bonding.
00201             err_code = dm_security_setup_req(&m_dm_device_handle);
00202             APP_ERROR_CHECK(err_code);
00203 
00204             m_peer_count++;
00205 
00206             if (m_peer_count < CENTRAL_LINK_COUNT)
00207             {
00208                 scan_start();
00209             }
00210             APPL_LOG_DEBUG("[APPL]: << DM_EVT_CONNECTION\r\n");
00211             break;
00212         }
00213 
00214         case DM_EVT_DISCONNECTION:
00215         {
00216             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_DISCONNECTION\r\n");
00217             memset(&m_ble_db_discovery, 0 , sizeof (m_ble_db_discovery));
00218 
00219             err_code = bsp_indication_set(BSP_INDICATE_IDLE);
00220             APP_ERROR_CHECK(err_code);
00221 
00222             if (m_peer_count == CENTRAL_LINK_COUNT)
00223             {
00224                 scan_start();
00225             }
00226             m_peer_count--;
00227             APPL_LOG_DEBUG("[APPL]: << DM_EVT_DISCONNECTION\r\n");
00228             break;
00229         }
00230 
00231         case DM_EVT_SECURITY_SETUP:
00232         {
00233             APPL_LOG_DEBUG("[APPL]:[0x%02X] >> DM_EVT_SECURITY_SETUP\r\n", p_handle->connection_id);
00234             // Slave securtiy request received from peer, if from a non bonded device, 
00235             // initiate security setup, else, wait for encryption to complete.
00236             err_code = dm_security_setup_req(&m_dm_device_handle);
00237             APP_ERROR_CHECK(err_code);
00238             APPL_LOG_DEBUG("[APPL]:[0x%02X] << DM_EVT_SECURITY_SETUP\r\n", p_handle->connection_id);
00239             break;
00240         }
00241 
00242         case DM_EVT_SECURITY_SETUP_COMPLETE:
00243         {
00244             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_SECURITY_SETUP_COMPLETE\r\n");
00245             APPL_LOG_DEBUG("[APPL]: << DM_EVT_SECURITY_SETUP_COMPLETE\r\n");
00246             break;
00247         }
00248 
00249         case DM_EVT_LINK_SECURED:
00250             APPL_LOG_DEBUG("[APPL]: >> DM_LINK_SECURED_IND\r\n");
00251             // Discover peer's services. 
00252             err_code = ble_db_discovery_start(&m_ble_db_discovery,
00253                                               p_event->event_param.p_gap_param->conn_handle);
00254             APP_ERROR_CHECK(err_code);
00255             APPL_LOG_DEBUG("[APPL]: << DM_LINK_SECURED_IND\r\n");
00256             break;
00257 
00258         case DM_EVT_DEVICE_CONTEXT_LOADED:
00259             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_LINK_SECURED\r\n");
00260             APP_ERROR_CHECK(event_result);
00261             APPL_LOG_DEBUG("[APPL]: << DM_EVT_DEVICE_CONTEXT_LOADED\r\n");
00262             break;
00263 
00264         case DM_EVT_DEVICE_CONTEXT_STORED:
00265             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_DEVICE_CONTEXT_STORED\r\n");
00266             APP_ERROR_CHECK(event_result);
00267             APPL_LOG_DEBUG("[APPL]: << DM_EVT_DEVICE_CONTEXT_STORED\r\n");
00268             break;
00269 
00270         case DM_EVT_DEVICE_CONTEXT_DELETED:
00271             APPL_LOG_DEBUG("[APPL]: >> DM_EVT_DEVICE_CONTEXT_DELETED\r\n");
00272             APP_ERROR_CHECK(event_result);
00273             APPL_LOG_DEBUG("[APPL]: << DM_EVT_DEVICE_CONTEXT_DELETED\r\n");
00274             break;
00275 
00276         default:
00277             break;
00278     }
00279 
00280     return NRF_SUCCESS;
00281 }
00282 
00283 
00284 /**
00285  * @brief Parses advertisement data, providing length and location of the field in case
00286  *        matching data is found.
00287  *
00288  * @param[in]  Type of data to be looked for in advertisement data.
00289  * @param[in]  Advertisement report length and pointer to report.
00290  * @param[out] If data type requested is found in the data report, type data length and
00291  *             pointer to data will be populated here.
00292  *
00293  * @retval NRF_SUCCESS if the data type is found in the report.
00294  * @retval NRF_ERROR_NOT_FOUND if the data type could not be found.
00295  */
00296 static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
00297 {
00298     uint32_t  index = 0;
00299     uint8_t * p_data;
00300 
00301     p_data = p_advdata->p_data;
00302 
00303     while (index < p_advdata->data_len)
00304     {
00305         uint8_t field_length = p_data[index];
00306         uint8_t field_type   = p_data[index+1];
00307 
00308         if (field_type == type)
00309         {
00310             p_typedata->p_data   = &p_data[index+2];
00311             p_typedata->data_len = field_length-1;
00312             return NRF_SUCCESS;
00313         }
00314         index += field_length + 1;
00315     }
00316     return NRF_ERROR_NOT_FOUND;
00317 }
00318 
00319 
00320 /**@brief Function for putting the chip into sleep mode.
00321  *
00322  * @note This function will not return.
00323  */
00324 static void sleep_mode_enter(void)
00325 {
00326     uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
00327     APP_ERROR_CHECK(err_code);
00328 
00329     // Prepare wakeup buttons.
00330     err_code = bsp_btn_ble_sleep_mode_prepare();
00331     APP_ERROR_CHECK(err_code);
00332 
00333     // Go to system-off mode (this function will not return; wakeup will cause a reset).
00334     err_code = sd_power_system_off();
00335     APP_ERROR_CHECK(err_code);
00336 }
00337 
00338 
00339 /**@brief Function for handling the Application's BLE Stack events.
00340  *
00341  * @param[in]   p_ble_evt   Bluetooth stack event.
00342  */
00343 static void on_ble_evt(ble_evt_t * p_ble_evt)
00344 {
00345     uint32_t                err_code;
00346     const ble_gap_evt_t   * p_gap_evt = &p_ble_evt->evt.gap_evt;
00347 
00348     switch (p_ble_evt->header.evt_id)
00349     {
00350         case BLE_GAP_EVT_ADV_REPORT:
00351         {
00352             data_t adv_data;
00353             data_t type_data;
00354 
00355             // Initialize advertisement report for parsing.
00356             adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data;
00357             adv_data.data_len = p_gap_evt->params.adv_report.dlen;
00358 
00359             err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
00360                                         &adv_data,
00361                                         &type_data);
00362 
00363             if (err_code != NRF_SUCCESS)
00364             {
00365                 // Compare short local name in case complete name does not match.
00366                 err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
00367                                             &adv_data,
00368                                             &type_data);
00369             }
00370 
00371             // Verify if short or complete name matches target.
00372             if (err_code == NRF_SUCCESS)
00373             {
00374                 uint16_t extracted_uuid;
00375 
00376                 // UUIDs found, look for matching UUID
00377                 for (uint32_t u_index = 0; u_index < (type_data.data_len/UUID16_SIZE); u_index++)
00378                 {
00379                     UUID16_EXTRACT(&extracted_uuid,&type_data.p_data[u_index * UUID16_SIZE]);
00380 
00381                     APPL_LOG_DEBUG("\t[APPL]: %x\r\n",extracted_uuid);
00382 
00383                     if(extracted_uuid == TARGET_UUID)
00384                     {
00385                         // Stop scanning.
00386                         err_code = sd_ble_gap_scan_stop();
00387 
00388                         if (err_code != NRF_SUCCESS)
00389                         {
00390                             APPL_LOG_DEBUG("[APPL]: Scan stop failed, reason %d\r\n", err_code);
00391                         }
00392                         err_code = bsp_indication_set(BSP_INDICATE_IDLE);
00393                         APP_ERROR_CHECK(err_code);
00394 
00395                         m_scan_param.selective = 0; 
00396                         m_scan_param.p_whitelist = NULL;
00397 
00398                         // Initiate connection.
00399                         err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.peer_addr,
00400                                                       &m_scan_param,
00401                                                       &m_connection_param);
00402 
00403                         m_whitelist_temporarily_disabled = false;
00404 
00405                         if (err_code != NRF_SUCCESS)
00406                         {
00407                             APPL_LOG_DEBUG("[APPL]: Connection Request Failed, reason %d\r\n", err_code);
00408                         }
00409                         break;
00410                     }
00411                 }
00412             }
00413             break;
00414         }
00415 
00416         case BLE_GAP_EVT_TIMEOUT:
00417             if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
00418             {
00419                 APPL_LOG_DEBUG("[APPL]: Scan timed out.\r\n");
00420                 scan_start();
00421             }
00422             else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
00423             {
00424                 APPL_LOG_DEBUG("[APPL]: Connection Request timed out.\r\n");
00425             }
00426             break;
00427         case BLE_GAP_EVT_CONNECTED:
00428         {
00429             err_code = ble_hrs_c_handles_assign(&m_ble_hrs_c, p_gap_evt->conn_handle, NULL);
00430             APP_ERROR_CHECK(err_code);
00431             err_code = ble_bas_c_handles_assign(&m_ble_bas_c, p_gap_evt->conn_handle, NULL);
00432             APP_ERROR_CHECK(err_code);
00433             break;
00434         }
00435         case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
00436             // Accepting parameters requested by peer.
00437             err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
00438                                                     &p_gap_evt->params.conn_param_update_request.conn_params);
00439             APP_ERROR_CHECK(err_code);
00440             break;
00441 
00442         default:
00443             break;
00444     }
00445 }
00446 
00447 
00448 /**@brief Function for handling the Application's system events.
00449  *
00450  * @param[in]   sys_evt   system event.
00451  */
00452 static void on_sys_evt(uint32_t sys_evt)
00453 {
00454     switch (sys_evt)
00455     {
00456         case NRF_EVT_FLASH_OPERATION_SUCCESS:
00457             /* fall through */
00458         case NRF_EVT_FLASH_OPERATION_ERROR:
00459 
00460             if (m_memory_access_in_progress)
00461             {
00462                 m_memory_access_in_progress = false;
00463                 scan_start();
00464             }
00465             break;
00466 
00467         default:
00468             // No implementation needed.
00469             break;
00470     }
00471 }
00472 
00473 
00474 /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
00475  *
00476  * @details This function is called from the scheduler in the main loop after a BLE stack event has
00477  *  been received.
00478  *
00479  * @param[in]   p_ble_evt   Bluetooth stack event.
00480  */
00481 static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
00482 {
00483     dm_ble_evt_handler(p_ble_evt);
00484     ble_db_discovery_on_ble_evt(&m_ble_db_discovery, p_ble_evt);
00485     ble_hrs_c_on_ble_evt(&m_ble_hrs_c, p_ble_evt);
00486     ble_bas_c_on_ble_evt(&m_ble_bas_c, p_ble_evt);
00487     bsp_btn_ble_on_ble_evt(p_ble_evt);
00488     on_ble_evt(p_ble_evt);
00489 }
00490 
00491 
00492 /**@brief Function for dispatching a system event to interested modules.
00493  *
00494  * @details This function is called from the System event interrupt handler after a system
00495  *          event has been received.
00496  *
00497  * @param[in]   sys_evt   System stack event.
00498  */
00499 static void sys_evt_dispatch(uint32_t sys_evt)
00500 {
00501     pstorage_sys_event_handler(sys_evt);
00502     on_sys_evt(sys_evt);
00503 }
00504 
00505 
00506 /**@brief Function for initializing the BLE stack.
00507  *
00508  * @details Initializes the SoftDevice and the BLE event interrupt.
00509  */
00510 static void ble_stack_init(void)
00511 {
00512     uint32_t err_code;
00513         
00514     nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
00515         
00516     // Initialize the SoftDevice handler module.
00517     SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
00518     
00519     ble_enable_params_t ble_enable_params;
00520     err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
00521                                                     PERIPHERAL_LINK_COUNT,
00522                                                     &ble_enable_params);
00523     APP_ERROR_CHECK(err_code);
00524     
00525     //Check the ram settings against the used number of links
00526     CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT);
00527     
00528     // Enable BLE stack.
00529     err_code = softdevice_enable(&ble_enable_params);
00530     APP_ERROR_CHECK(err_code);
00531 
00532     // Register with the SoftDevice handler module for BLE events.
00533     err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
00534     APP_ERROR_CHECK(err_code);
00535 
00536     // Register with the SoftDevice handler module for System events.
00537     err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
00538     APP_ERROR_CHECK(err_code);
00539 }
00540 
00541 
00542 /**@brief Function for the Device Manager initialization.
00543  *
00544  * @param[in] erase_bonds  Indicates whether bonding information should be cleared from
00545  *                         persistent storage during initialization of the Device Manager.
00546  */
00547 static void device_manager_init(bool erase_bonds)
00548 {
00549     uint32_t               err_code;
00550     dm_init_param_t        init_param = {.clear_persistent_data = erase_bonds};
00551     dm_application_param_t register_param;
00552 
00553     err_code = pstorage_init();
00554     APP_ERROR_CHECK(err_code);
00555 
00556     err_code = dm_init(&init_param);
00557     APP_ERROR_CHECK(err_code);
00558 
00559     memset(&register_param.sec_param, 0, sizeof (ble_gap_sec_params_t));
00560 
00561     // Event handler to be registered with the module.
00562     register_param.evt_handler            = device_manager_event_handler;
00563 
00564     // Service or protocol context for device manager to load, store and apply on behalf of application.
00565     // Here set to client as application is a GATT client.
00566     register_param.service_type           = DM_PROTOCOL_CNTXT_GATT_CLI_ID;
00567 
00568     // Secuirty parameters to be used for security procedures.
00569     register_param.sec_param.bond         = SEC_PARAM_BOND;
00570     register_param.sec_param.mitm         = SEC_PARAM_MITM;
00571     register_param.sec_param.lesc         = SEC_PARAM_LESC;
00572     register_param.sec_param.keypress     = SEC_PARAM_KEYPRESS;
00573     register_param.sec_param.io_caps      = SEC_PARAM_IO_CAPABILITIES;
00574     register_param.sec_param.oob          = SEC_PARAM_OOB;
00575     register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
00576     register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
00577     register_param.sec_param.kdist_peer.enc = 1;
00578     register_param.sec_param.kdist_peer.id  = 1;
00579 
00580     err_code = dm_register(&m_dm_app_id, &register_param);
00581     APP_ERROR_CHECK(err_code);
00582 }
00583 
00584 
00585 /**@brief Function for disabling the use of whitelist for scanning.
00586  */
00587 static void whitelist_disable(void)
00588 {
00589     uint32_t err_code;
00590 
00591     if ((m_scan_mode == BLE_WHITELIST_SCAN) && !m_whitelist_temporarily_disabled)
00592     {
00593         m_whitelist_temporarily_disabled = true;
00594 
00595         err_code = sd_ble_gap_scan_stop();
00596         if (err_code == NRF_SUCCESS)
00597         {
00598             scan_start();
00599         }
00600         else if (err_code != NRF_ERROR_INVALID_STATE)
00601         {
00602             APP_ERROR_CHECK(err_code);
00603         }
00604     }
00605     m_whitelist_temporarily_disabled = true;
00606 }
00607 
00608 
00609 /**@brief Function for handling events from the BSP module.
00610  *
00611  * @param[in]   event   Event generated by button press.
00612  */
00613 void bsp_event_handler(bsp_event_t event)
00614 {
00615     uint32_t err_code;
00616     switch (event)
00617     {
00618         case BSP_EVENT_SLEEP:
00619             sleep_mode_enter();
00620             break;
00621 
00622         case BSP_EVENT_DISCONNECT:
00623             err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
00624             if (err_code != NRF_ERROR_INVALID_STATE)
00625             {
00626                 APP_ERROR_CHECK(err_code);
00627             }
00628             break;
00629 
00630         case BSP_EVENT_WHITELIST_OFF:
00631             whitelist_disable();
00632             break;
00633 
00634         default:
00635             break;
00636     }
00637 }
00638 
00639 
00640 /**@brief Heart Rate Collector Handler.
00641  */
00642 static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt)
00643 {
00644     uint32_t err_code;
00645 
00646     switch (p_hrs_c_evt->evt_type)
00647     {
00648         case BLE_HRS_C_EVT_DISCOVERY_COMPLETE:
00649 
00650             // Heart rate service discovered. Enable notification of Heart Rate Measurement.
00651             err_code = ble_hrs_c_hrm_notif_enable(p_hrs_c);
00652             APP_ERROR_CHECK(err_code);
00653 
00654             APPL_LOG_DEBUG("Heart rate service discovered \r\n");
00655             break;
00656 
00657         case BLE_HRS_C_EVT_HRM_NOTIFICATION:
00658         {
00659             APPL_LOG_DEBUG("[APPL]: HR Measurement received %d \r\n", p_hrs_c_evt->params.hrm.hr_value);
00660 
00661             APPL_LOG("Heart Rate = %d\r\n", p_hrs_c_evt->params.hrm.hr_value);
00662             break;
00663         }
00664 
00665         default:
00666             break;
00667     }
00668 }
00669 
00670 
00671 /**@brief Battery levelCollector Handler.
00672  */
00673 static void bas_c_evt_handler(ble_bas_c_t * p_bas_c, ble_bas_c_evt_t * p_bas_c_evt)
00674 {
00675     uint32_t err_code;
00676 
00677     switch (p_bas_c_evt->evt_type)
00678     {
00679         case BLE_BAS_C_EVT_DISCOVERY_COMPLETE:
00680             // Batttery service discovered. Enable notification of Battery Level.
00681             APPL_LOG_DEBUG("[APPL]: Battery Service discovered. \r\n");
00682 
00683             APPL_LOG_DEBUG("[APPL]: Reading battery level. \r\n");
00684 
00685             err_code = ble_bas_c_bl_read(p_bas_c);
00686             APP_ERROR_CHECK(err_code);
00687 
00688 
00689             APPL_LOG_DEBUG("[APPL]: Enabling Battery Level Notification. \r\n");
00690             err_code = ble_bas_c_bl_notif_enable(p_bas_c);
00691             APP_ERROR_CHECK(err_code);
00692 
00693             break;
00694 
00695         case BLE_BAS_C_EVT_BATT_NOTIFICATION:
00696         {
00697             APPL_LOG_DEBUG("[APPL]: Battery Level received %d %%\r\n", p_bas_c_evt->params.battery_level);
00698 
00699             APPL_LOG_DEBUG("Battery = %d %%\r\n", p_bas_c_evt->params.battery_level);
00700             break;
00701         }
00702 
00703         case BLE_BAS_C_EVT_BATT_READ_RESP:
00704         {
00705             APPL_LOG_DEBUG("[APPL]: Battery Level Read as %d %%\r\n", p_bas_c_evt->params.battery_level);
00706 
00707             APPL_LOG_DEBUG("Battery = %d %%\r\n", p_bas_c_evt->params.battery_level);
00708             break;
00709         }
00710 
00711         default:
00712             break;
00713     }
00714 }
00715 
00716 
00717 /**
00718  * @brief Heart rate collector initialization.
00719  */
00720 static void hrs_c_init(void)
00721 {
00722     ble_hrs_c_init_t hrs_c_init_obj;
00723 
00724     hrs_c_init_obj.evt_handler = hrs_c_evt_handler;
00725 
00726     uint32_t err_code = ble_hrs_c_init(&m_ble_hrs_c, &hrs_c_init_obj);
00727     APP_ERROR_CHECK(err_code);
00728 }
00729 
00730 
00731 /**
00732  * @brief Battery level collector initialization.
00733  */
00734 static void bas_c_init(void)
00735 {
00736     ble_bas_c_init_t bas_c_init_obj;
00737 
00738     bas_c_init_obj.evt_handler = bas_c_evt_handler;
00739 
00740     uint32_t err_code = ble_bas_c_init(&m_ble_bas_c, &bas_c_init_obj);
00741     APP_ERROR_CHECK(err_code);
00742 }
00743 
00744 
00745 /**
00746  * @brief Database discovery collector initialization.
00747  */
00748 static void db_discovery_init(void)
00749 {
00750     uint32_t err_code = ble_db_discovery_init(db_disc_handler);
00751 
00752     APP_ERROR_CHECK(err_code);
00753 }
00754 
00755 
00756 /**@brief Function to start scanning.
00757  */
00758 static void scan_start(void)
00759 {
00760     ble_gap_whitelist_t   whitelist;
00761     ble_gap_addr_t      * p_whitelist_addr[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
00762     ble_gap_irk_t       * p_whitelist_irk[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
00763     uint32_t              err_code;
00764     uint32_t              count;
00765 
00766     // Verify if there is any flash access pending, if yes delay starting scanning until 
00767     // it's complete.
00768     err_code = pstorage_access_status_get(&count);
00769     APP_ERROR_CHECK(err_code);
00770 
00771     if (count != 0)
00772     {
00773         m_memory_access_in_progress = true;
00774         return;
00775     }
00776 
00777     // Initialize whitelist parameters.
00778     whitelist.addr_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
00779     whitelist.irk_count  = 0;
00780     whitelist.pp_addrs   = p_whitelist_addr;
00781     whitelist.pp_irks    = p_whitelist_irk;
00782 
00783     // Request creating of whitelist.
00784     err_code = dm_whitelist_create(&m_dm_app_id,&whitelist);
00785     APP_ERROR_CHECK(err_code);
00786 
00787     if (((whitelist.addr_count == 0) && (whitelist.irk_count == 0)) ||
00788         (m_scan_mode != BLE_WHITELIST_SCAN)                        ||
00789         (m_whitelist_temporarily_disabled))
00790     {
00791         // No devices in whitelist, hence non selective performed.
00792         m_scan_param.active       = 0;            // Active scanning set.
00793         m_scan_param.selective    = 0;            // Selective scanning not set.
00794         m_scan_param.interval     = SCAN_INTERVAL;// Scan interval.
00795         m_scan_param.window       = SCAN_WINDOW;  // Scan window.
00796         m_scan_param.p_whitelist  = NULL;         // No whitelist provided.
00797         m_scan_param.timeout      = 0x0000;       // No timeout.
00798     }
00799     else
00800     {
00801         // Selective scanning based on whitelist first.
00802         m_scan_param.active       = 0;            // Active scanning set.
00803         m_scan_param.selective    = 1;            // Selective scanning not set.
00804         m_scan_param.interval     = SCAN_INTERVAL;// Scan interval.
00805         m_scan_param.window       = SCAN_WINDOW;  // Scan window.
00806         m_scan_param.p_whitelist  = &whitelist;   // Provide whitelist.
00807         m_scan_param.timeout      = 0x001E;       // 30 seconds timeout.
00808     }
00809 
00810     err_code = sd_ble_gap_scan_start(&m_scan_param);
00811     APP_ERROR_CHECK(err_code);
00812 
00813     err_code = bsp_indication_set(BSP_INDICATE_SCANNING);
00814     APP_ERROR_CHECK(err_code);
00815 }
00816 
00817 
00818 /**@brief Function for initializing buttons and leds.
00819  *
00820  * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
00821  */
00822 static void buttons_leds_init(bool * p_erase_bonds)
00823 {
00824     bsp_event_t startup_event;
00825 
00826     uint32_t err_code = bsp_init(BSP_INIT_LED | BSP_INIT_BUTTONS,
00827                                  APP_TIMER_TICKS(100, APP_TIMER_PRESCALER),
00828                                  bsp_event_handler);
00829     APP_ERROR_CHECK(err_code);
00830 
00831     err_code = bsp_btn_ble_init(NULL, &startup_event);
00832     APP_ERROR_CHECK(err_code);
00833 
00834     *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
00835 }
00836 
00837 
00838 /**@brief Function for initializing the nrf log module.
00839  */
00840 static void nrf_log_init(void)
00841 {
00842     ret_code_t err_code = NRF_LOG_INIT();
00843     APP_ERROR_CHECK(err_code);
00844 }
00845 
00846 
00847 /** @brief Function for the Power manager.
00848  */
00849 static void power_manage(void)
00850 {
00851     uint32_t err_code = sd_app_evt_wait();
00852     APP_ERROR_CHECK(err_code);
00853 }
00854 
00855 
00856 int main(void)
00857 {
00858     bool erase_bonds;
00859 
00860     // Initialize.
00861     APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, NULL);
00862     buttons_leds_init(&erase_bonds);
00863     nrf_log_init();
00864     APPL_LOG("Heart rate collector example\r\n");
00865     ble_stack_init();
00866     device_manager_init(erase_bonds);
00867     db_discovery_init();
00868     hrs_c_init();
00869     bas_c_init();
00870 
00871     // Start scanning for peripherals and initiate connection
00872     // with devices that advertise Heart Rate UUID.
00873     scan_start();
00874 
00875     for (;; )
00876     {
00877         power_manage();
00878     }
00879 }
00880 
00881 
00882