19 #include "nordic_common.h"
21 #include "app_error.h"
24 #include "ble_srv_common.h"
25 #include "ble_advdata.h"
26 #include "ble_advertising.h"
30 #include "ble_conn_params.h"
32 #include "sensorsim.h"
33 #include "softdevice_handler.h"
34 #include "app_timer.h"
35 #include "device_manager.h"
37 #include "app_trace.h"
39 #include "nrf_delay.h"
40 #include "bsp_btn_ble.h"
41 #include "app_gpiote.h"
43 #define IS_SRVC_CHANGED_CHARACT_PRESENT 1
45 #define DEVICE_NAME "Nordic_HRM"
46 #define MANUFACTURER_NAME "NordicSemiconductor"
47 #define APP_ADV_INTERVAL 300
48 #define APP_ADV_TIMEOUT_IN_SECONDS 180
50 #define APP_TIMER_PRESCALER 0
51 #define APP_PROFILE_MAX_TIMERS (4+BSP_APP_TIMERS_NUMBER)
52 #define APP_TIMER_OP_QUEUE_SIZE 4
54 #define BATTERY_LEVEL_MEAS_INTERVAL APP_TIMER_TICKS(2000, APP_TIMER_PRESCALER)
55 #define MIN_BATTERY_LEVEL 81
56 #define MAX_BATTERY_LEVEL 100
57 #define BATTERY_LEVEL_INCREMENT 1
59 #define HEART_RATE_MEAS_INTERVAL APP_TIMER_TICKS(1000, APP_TIMER_PRESCALER)
60 #define MIN_HEART_RATE 140
61 #define MAX_HEART_RATE 300
62 #define HEART_RATE_INCREMENT 10
64 #define RR_INTERVAL_INTERVAL APP_TIMER_TICKS(300, APP_TIMER_PRESCALER)
65 #define MIN_RR_INTERVAL 100
66 #define MAX_RR_INTERVAL 500
67 #define RR_INTERVAL_INCREMENT 1
69 #define SENSOR_CONTACT_DETECTED_INTERVAL APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER)
71 #define MIN_CONN_INTERVAL MSEC_TO_UNITS(400, UNIT_1_25_MS)
72 #define MAX_CONN_INTERVAL MSEC_TO_UNITS(650, UNIT_1_25_MS)
73 #define SLAVE_LATENCY 0
74 #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
76 #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER)
77 #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER)
78 #define MAX_CONN_PARAMS_UPDATE_COUNT 3
80 #define SEC_PARAM_BOND 1
81 #define SEC_PARAM_MITM 0
82 #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE
83 #define SEC_PARAM_OOB 0
84 #define SEC_PARAM_MIN_KEY_SIZE 7
85 #define SEC_PARAM_MAX_KEY_SIZE 16
87 #define DEAD_BEEF 0xDEADBEEF
89 static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
90 static ble_bas_t m_bas;
91 static ble_hrs_t m_hrs;
92 static bool m_rr_interval_enabled = true;
94 static sensorsim_cfg_t m_battery_sim_cfg;
95 static sensorsim_state_t m_battery_sim_state;
96 static sensorsim_cfg_t m_heart_rate_sim_cfg;
97 static sensorsim_state_t m_heart_rate_sim_state;
98 static sensorsim_cfg_t m_rr_interval_sim_cfg;
99 static sensorsim_state_t m_rr_interval_sim_state;
101 APP_TIMER_DEF(m_battery_timer_id);
102 APP_TIMER_DEF(m_heart_rate_timer_id);
103 APP_TIMER_DEF(m_rr_interval_timer_id);
104 APP_TIMER_DEF(m_sensor_contact_timer_id);
106 static dm_application_instance_t m_app_handle;
108 static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_HEART_RATE_SERVICE, BLE_UUID_TYPE_BLE},
109 {BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE},
110 {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}};
118 uint8_t battery_level;
122 err_code = ble_bas_battery_level_update(&
m_bas, battery_level);
123 if ((err_code != NRF_SUCCESS) &&
124 (err_code != NRF_ERROR_INVALID_STATE) &&
125 (err_code != BLE_ERROR_NO_TX_PACKETS) &&
126 (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
129 APP_ERROR_HANDLER(err_code);
143 UNUSED_PARAMETER(p_context);
158 static uint32_t cnt = 0;
162 UNUSED_PARAMETER(p_context);
167 err_code = ble_hrs_heart_rate_measurement_send(&
m_hrs, heart_rate);
168 if ((err_code != NRF_SUCCESS) &&
169 (err_code != NRF_ERROR_INVALID_STATE) &&
170 (err_code != BLE_ERROR_NO_TX_PACKETS) &&
171 (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
174 APP_ERROR_HANDLER(err_code);
193 UNUSED_PARAMETER(p_context);
197 uint16_t rr_interval;
201 ble_hrs_rr_interval_add(&
m_hrs, rr_interval);
215 static bool sensor_contact_detected =
false;
217 UNUSED_PARAMETER(p_context);
219 sensor_contact_detected = !sensor_contact_detected;
220 ble_hrs_sensor_contact_detected_update(&
m_hrs, sensor_contact_detected);
233 err_code = app_timer_create(&m_battery_timer_id,
234 APP_TIMER_MODE_REPEATED,
236 APP_ERROR_CHECK(err_code);
238 err_code = app_timer_create(&m_heart_rate_timer_id,
239 APP_TIMER_MODE_REPEATED,
241 APP_ERROR_CHECK(err_code);
243 err_code = app_timer_create(&m_rr_interval_timer_id,
244 APP_TIMER_MODE_REPEATED,
246 APP_ERROR_CHECK(err_code);
248 err_code = app_timer_create(&m_sensor_contact_timer_id,
249 APP_TIMER_MODE_REPEATED,
251 APP_ERROR_CHECK(err_code);
263 ble_gap_conn_params_t gap_conn_params;
264 ble_gap_conn_sec_mode_t sec_mode;
266 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
268 err_code = sd_ble_gap_device_name_set(&sec_mode,
271 APP_ERROR_CHECK(err_code);
273 err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT);
274 APP_ERROR_CHECK(err_code);
276 memset(&gap_conn_params, 0,
sizeof(gap_conn_params));
283 err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
284 APP_ERROR_CHECK(err_code);
293 err_code = sd_ble_gap_adv_stop();
294 APP_ERROR_CHECK(err_code);
296 err_code = bsp_indication_set(BSP_INDICATE_IDLE);
297 APP_ERROR_CHECK(err_code);
309 err_code = sd_ble_gap_disconnect(
m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
311 if(err_code != BLE_ERROR_INVALID_CONN_HANDLE)
312 APP_ERROR_CHECK(err_code);
314 err_code = bsp_indication_set(BSP_INDICATE_IDLE);
315 APP_ERROR_CHECK(err_code);
323 err_code = ble_conn_params_stop();
324 APP_ERROR_CHECK(err_code);
335 ble_hrs_init_t hrs_init;
336 ble_bas_init_t bas_init;
337 ble_dis_init_t dis_init;
338 uint8_t body_sensor_location;
341 body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER;
343 memset(&hrs_init, 0,
sizeof(hrs_init));
345 hrs_init.evt_handler = NULL;
346 hrs_init.is_sensor_contact_supported =
true;
347 hrs_init.p_body_sensor_location = &body_sensor_location;
350 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.cccd_write_perm);
351 BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.read_perm);
352 BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.write_perm);
354 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_bsl_attr_md.read_perm);
355 BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm);
357 err_code = ble_hrs_init(&
m_hrs, &hrs_init);
358 APP_ERROR_CHECK(err_code);
361 memset(&bas_init, 0,
sizeof(bas_init));
364 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm);
365 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm);
366 BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm);
368 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm);
370 bas_init.evt_handler = NULL;
371 bas_init.support_notification =
true;
372 bas_init.p_report_ref = NULL;
373 bas_init.initial_batt_level = 100;
375 err_code = ble_bas_init(&
m_bas, &bas_init);
376 APP_ERROR_CHECK(err_code);
379 memset(&dis_init, 0,
sizeof(dis_init));
383 BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm);
384 BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm);
386 err_code = ble_dis_init(&dis_init);
387 APP_ERROR_CHECK(err_code);
427 APP_ERROR_CHECK(err_code);
430 APP_ERROR_CHECK(err_code);
433 APP_ERROR_CHECK(err_code);
436 APP_ERROR_CHECK(err_code);
454 if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
456 err_code = sd_ble_gap_disconnect(
m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
457 APP_ERROR_CHECK(err_code);
468 APP_ERROR_HANDLER(nrf_error);
477 ble_conn_params_init_t cp_init;
479 memset(&cp_init, 0,
sizeof(cp_init));
481 cp_init.p_conn_params = NULL;
485 cp_init.start_on_notify_cccd_handle =
m_hrs.hrm_handles.cccd_handle;
486 cp_init.disconnect_on_fail =
false;
490 err_code = ble_conn_params_init(&cp_init);
491 APP_ERROR_CHECK(err_code);
501 uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
502 APP_ERROR_CHECK(err_code);
505 err_code = bsp_btn_ble_sleep_mode_prepare();
506 APP_ERROR_CHECK(err_code);
509 err_code = sd_power_system_off();
510 APP_ERROR_CHECK(err_code);
526 case BLE_ADV_EVT_FAST:
527 err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
528 APP_ERROR_CHECK(err_code);
530 case BLE_ADV_EVT_IDLE:
547 switch (p_ble_evt->header.evt_id)
549 case BLE_GAP_EVT_CONNECTED:
550 err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
551 APP_ERROR_CHECK(err_code);
555 case BLE_GAP_EVT_DISCONNECTED:
575 dm_ble_evt_handler(p_ble_evt);
576 ble_hrs_on_ble_evt(&
m_hrs, p_ble_evt);
577 ble_bas_on_ble_evt(&
m_bas, p_ble_evt);
578 ble_conn_params_on_ble_evt(p_ble_evt);
579 bsp_btn_ble_on_ble_evt(p_ble_evt);
581 ble_advertising_on_ble_evt(p_ble_evt);
594 pstorage_sys_event_handler(sys_evt);
595 ble_advertising_on_sys_evt(sys_evt);
609 case BSP_EVENT_SLEEP:
613 case BSP_EVENT_DISCONNECT:
614 err_code = sd_ble_gap_disconnect(
m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
615 if (err_code != NRF_ERROR_INVALID_STATE)
617 APP_ERROR_CHECK(err_code);
621 case BSP_EVENT_WHITELIST_OFF:
622 err_code = ble_advertising_restart_without_whitelist();
623 if (err_code != NRF_ERROR_INVALID_STATE)
625 APP_ERROR_CHECK(err_code);
643 dm_event_t
const * p_event,
644 ret_code_t event_result)
646 APP_ERROR_CHECK(event_result);
660 dm_init_param_t init_param = {.clear_persistent_data = erase_bonds};
661 dm_application_param_t register_param;
664 err_code = pstorage_init();
665 APP_ERROR_CHECK(err_code);
667 err_code = dm_init(&init_param);
668 APP_ERROR_CHECK(err_code);
670 memset(®ister_param.sec_param, 0,
sizeof(ble_gap_sec_params_t));
679 register_param.service_type = DM_PROTOCOL_CNTXT_GATT_SRVR_ID;
682 APP_ERROR_CHECK(err_code);
691 ble_advdata_t advdata;
694 memset(&advdata, 0,
sizeof(advdata));
696 advdata.name_type = BLE_ADVDATA_FULL_NAME;
697 advdata.include_appearance =
true;
698 advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
702 ble_adv_modes_config_t options = {0};
703 options.ble_adv_fast_enabled = BLE_ADV_FAST_ENABLED;
707 err_code = ble_advertising_init(&advdata, NULL, &options,
on_adv_evt, NULL);
708 APP_ERROR_CHECK(err_code);
748 err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
749 APP_ERROR_CHECK(err_code);
static void conn_params_init(void)
Function for initializing the Connection Parameters module.
static uint16_t m_conn_handle
static sensorsim_cfg_t m_rr_interval_sim_cfg
static bool m_rr_interval_enabled
static void sensor_contact_detected_timeout_handler(void *p_context)
Function for handling the Sensor Contact Detected timer timeout.
static void rr_interval_timeout_handler(void *p_context)
Function for handling the RR interval timer timeout.
static sensorsim_state_t m_rr_interval_sim_state
static void advertising_stop(void)
Function for stopping advertising.
#define HEART_RATE_MEAS_INTERVAL
#define MAX_CONN_PARAMS_UPDATE_COUNT
#define SEC_PARAM_MAX_KEY_SIZE
#define RR_INTERVAL_INCREMENT
static ble_uuid_t m_adv_uuids[]
static void on_ble_evt(ble_evt_t *p_ble_evt)
Function for handling the Application's BLE Stack events.
static void conn_params_error_handler(uint32_t nrf_error)
Function for handling a Connection Parameters error.
void app_profile_start(void)
Start profile. Is called every time profile is activated.
static sensorsim_cfg_t m_heart_rate_sim_cfg
static void services_init(void)
Function for initializing services that will be used by the application.
#define MANUFACTURER_NAME
static void sys_evt_dispatch(uint32_t sys_evt)
Function for dispatching a system event to interested modules.
#define MAX_CONN_INTERVAL
#define SEC_PARAM_IO_CAPABILITIES
void app_profile_init(void)
Initialize profile. Is only called once.
#define NEXT_CONN_PARAMS_UPDATE_DELAY
#define SEC_PARAM_MIN_KEY_SIZE
static void timers_init(void)
Function for the Timer initialization.
static void ble_evt_dispatch(ble_evt_t *p_ble_evt)
Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
#define BATTERY_LEVEL_MEAS_INTERVAL
void app_profile_on_sys_evt(uint32_t sys_evt)
Handle system event.
void bsp_event_handler(bsp_event_t event)
Function for handling events from the BSP module.
static void advertising_init(void)
Function for initializing the Advertising functionality.
#define FIRST_CONN_PARAMS_UPDATE_DELAY
#define RR_INTERVAL_INTERVAL
static sensorsim_cfg_t m_battery_sim_cfg
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
Function for handling advertising events.
static void device_manager_init(bool erase_bonds)
Function for the Device Manager initialization.
#define MIN_CONN_INTERVAL
static void sleep_mode_enter(void)
Function for putting the chip into sleep mode.
static dm_application_instance_t m_app_handle
static void on_conn_params_evt(ble_conn_params_evt_t *p_evt)
Function for handling the Connection Parameters Module.
static sensorsim_state_t m_heart_rate_sim_state
static void reset_prepare(void)
Function for preparing for system reset.
#define MAX_BATTERY_LEVEL
#define MIN_BATTERY_LEVEL
static sensorsim_state_t m_battery_sim_state
static uint32_t device_manager_evt_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result)
Function for handling the Device Manager events.
#define BATTERY_LEVEL_INCREMENT
void app_profile_stop(void)
Stop profile. Note: Needs to set the softdevice in a state where it is ok to initialize PRU profile...
static void sensor_simulator_init(void)
Function for initializing the sensor simulators.
static void application_timers_start(void)
Function for starting application timers.
static void battery_level_update(void)
Function for performing battery measurement and updating the Battery Level characteristic in Battery ...
static void battery_level_meas_timeout_handler(void *p_context)
Function for handling the Battery measurement timer timeout.
#define HEART_RATE_INCREMENT
static void gap_params_init(void)
Function for the GAP initialization.
static void heart_rate_meas_timeout_handler(void *p_context)
Function for handling the Heart rate measurement timer timeout.
void app_profile_on_ble_evt(ble_evt_t *p_ble_evt)
Handle BLE event.
#define APP_ADV_TIMEOUT_IN_SECONDS
#define SENSOR_CONTACT_DETECTED_INTERVAL