//============================================================================// // This is where we initialize our services and register them with the stack. // // The services that we create are: // // 1) Custom Service // 2) Battery Service // 3) Device Information Service // 4) DFU Service (if enabled via macro) static void services_init(void) { uint32_t err_code; ble_bas_init_t bas_init; ble_dis_init_t dis_init; //-------------------------------------------------------------------------- // Set up the Custom Service err_code = CS_Init(&_cs); APP_ERROR_CHECK(err_code); //-------------------------------------------------------------------------- // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); //-------------------------------------------------------------------------- // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&_bas, &bas_init); APP_ERROR_CHECK(err_code); //-------------------------------------------------------------------------- // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, (char *)MANUFACTURER_NAME); ble_srv_ascii_to_utf8(&dis_init.model_num_str, (char *)MODEL_NUMBER); ble_srv_ascii_to_utf8(&dis_init.serial_num_str, (char *)SERIAL_NUMBER); ble_srv_ascii_to_utf8(&dis_init.hw_rev_str, (char *)HARDWARE_REVISION); ble_srv_ascii_to_utf8(&dis_init.fw_rev_str, (char *)FIRMWARE_REVISION); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); dfu_app_dm_appl_instance_set(_app_handle); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Heart Rate, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_hrs_init_t hrs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; uint8_t body_sensor_location; // Initialize Heart Rate Service. body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER; memset(&hrs_init, 0, sizeof(hrs_init)); hrs_init.evt_handler = NULL; hrs_init.is_sensor_contact_supported = true; hrs_init.p_body_sensor_location = &body_sensor_location; // Here the sec level for the Heart Rate Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.cccd_write_perm); //***************MODIFIED BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.write_perm); //********************* BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_bsl_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm); err_code = ble_hrs_init(&m_hrs, &hrs_init); APP_ERROR_CHECK(err_code); // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, (char *)MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; //service_error_handler - Not used as only the switch from app to DFU mode is required and not full dfu service. err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
/* * Function for adding the Temperature characteristic. */ static uint32_t temperature_char_add(ble_temp_t * p_temp) { ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; ble_gatts_char_pf_t char_pf; ble_gatts_attr_md_t desc_md; static const uint8_t user_desc[] = "Temperature"; // Setup CCCD attribute memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; memset(&char_pf, 0, sizeof(char_pf)); char_pf.format = BLE_GATT_CPF_FORMAT_UTF8S; // Setup User Description attribute memset(&desc_md, 0, sizeof(desc_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); desc_md.vloc = BLE_GATTS_VLOC_STACK; // Temp Service Characterstic memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = 1; char_md.p_char_user_desc = (uint8_t*) &user_desc; char_md.char_user_desc_size = sizeof(user_desc); char_md.char_user_desc_max_size = sizeof(user_desc); char_md.p_char_pf = &char_pf; char_md.p_user_desc_md = &desc_md; char_md.p_cccd_md = &cccd_md; char_md.p_sccd_md = NULL; ble_uuid.type = p_temp->uuid_type; ble_uuid.uuid = TEMP_UUID_TEMPERATURE_CHAR; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = sizeof(uint16_t); attr_char_value.init_offs = 0; attr_char_value.max_len = sizeof(uint16_t); attr_char_value.p_value = NULL; return sd_ble_gatts_characteristic_add(p_temp->service_handle, &char_md, &attr_char_value, &p_temp->temperature_char_handles); }
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt, const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init) { ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID; p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS; p_sc_ctrlpt->size_list_supported_locations = p_sc_ctrlpt_init->size_list_supported_locations; if ((p_sc_ctrlpt_init->size_list_supported_locations != 0) && (p_sc_ctrlpt_init->list_supported_locations != NULL)) { memcpy(p_sc_ctrlpt->list_supported_locations, p_sc_ctrlpt_init->list_supported_locations, p_sc_ctrlpt->size_list_supported_locations * sizeof(ble_sensor_location_t)); } p_sc_ctrlpt->service_handle = p_sc_ctrlpt_init->service_handle; p_sc_ctrlpt->evt_handler = p_sc_ctrlpt_init->evt_handler; p_sc_ctrlpt->supported_functions = p_sc_ctrlpt_init->supported_functions; p_sc_ctrlpt->sensor_location_handle = p_sc_ctrlpt_init->sensor_location_handle; p_sc_ctrlpt->error_handler = p_sc_ctrlpt_init->error_handler; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; memset(&char_md, 0, sizeof(char_md)); char_md.char_props.indicate = 1; char_md.char_props.write = 1; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = &cccd_md; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SC_CTRLPT_CHAR); memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm); attr_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 1; attr_md.vlen = 1; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = 0; attr_char_value.init_offs = 0; attr_char_value.max_len = BLE_SC_CTRLPT_MAX_LEN; attr_char_value.p_value = 0; return sd_ble_gatts_characteristic_add(p_sc_ctrlpt->service_handle, &char_md, &attr_char_value, &p_sc_ctrlpt->sc_ctrlpt_handles); }
static uint32_t ble_stack_init(bool init_softdevice) { uint32_t err_code; nrf_clock_lf_cfg_t clock_lf_cfg = { .source = NRF_CLOCK_LF_SRC_RC, .rc_ctiv = 16, // recommended for nRF52 .rc_temp_ctiv = 2, // recommended for nRF52 .xtal_accuracy = 0}; if (init_softdevice) { err_code = nrf_dfu_mbr_init_sd(); VERIFY_SUCCESS(err_code); } NRF_LOG_INFO("vector table: 0x%08x\r\n", BOOTLOADER_START_ADDR); err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR); VERIFY_SUCCESS(err_code); SOFTDEVICE_HANDLER_APPSH_INIT(&clock_lf_cfg, true); ble_enable_params_t ble_enable_params; // Only one connection as a central is used when performing dfu. err_code = softdevice_enable_get_default_config(1, 1, &ble_enable_params); VERIFY_SUCCESS(err_code); #if (NRF_SD_BLE_API_VERSION == 3) ble_enable_params.gatt_enable_params.att_mtu = NRF_BLE_MAX_MTU_SIZE; #endif // Enable BLE stack. err_code = softdevice_enable(&ble_enable_params); return err_code; } /**@brief Function for adding DFU Packet characteristic to the BLE Stack. * * @param[in] p_dfu DFU Service structure. * * @return NRF_SUCCESS on success. Otherwise an error code. */ static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu) { ble_gatts_char_md_t char_md = {{0}}; ble_gatts_attr_t attr_char_value = {0}; ble_gatts_attr_md_t attr_md = {{0}}; ble_uuid_t char_uuid; char_md.char_props.write_wo_resp = 1; char_uuid.type = p_dfu->uuid_type; char_uuid.uuid = BLE_DFU_PKT_CHAR_UUID; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.vlen = 1; attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.max_len = MAX_DFU_PKT_LEN; attr_char_value.p_value = NULL; return sd_ble_gatts_characteristic_add(p_dfu->service_handle, &char_md, &attr_char_value, &p_dfu->dfu_pkt_handles); }
/**@brief Initialize services that will be used by the application. * * @details Initialize the Location and Navigation, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_lns_init_t lns_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; memset(&lns_init, 0, sizeof(lns_init)); lns_init.evt_handler = on_lns_evt; lns_init.lncp_evt_handler = on_ln_ctrlpt_evt; lns_init.error_handler = lns_error_handler; lns_init.is_position_quality_present = true; lns_init.is_control_point_present = true; lns_init.is_navigation_present = true; lns_init.available_features = BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED | BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED | BLE_LNS_FEATURE_LOCATION_SUPPORTED | BLE_LNS_FEATURE_ELEVATION_SUPPORTED | BLE_LNS_FEATURE_HEADING_SUPPORTED | BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED | BLE_LNS_FEATURE_UTC_TIME_SUPPORTED | BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED | BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED | BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED | BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED | BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED | BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED | BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED | BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED | BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED | BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED | BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED | BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED | BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED | BLE_LNS_FEATURE_POSITION_STATUS_SUPPORTED; m_sim_location_speed = initial_lns_location_speed; m_sim_position_quality = initial_lns_pos_quality; m_sim_navigation = initial_lns_navigation; lns_init.p_location_speed = &m_sim_location_speed; lns_init.p_position_quality = &m_sim_position_quality; lns_init.p_navigation = &m_sim_navigation; lns_init.loc_nav_feature_security_req_read_perm = SEC_OPEN; lns_init.loc_speed_security_req_cccd_write_perm = SEC_OPEN; lns_init.position_quality_security_req_read_perm = SEC_OPEN; lns_init.navigation_security_req_cccd_write_perm = SEC_OPEN; lns_init.ctrl_point_security_req_write_perm = SEC_OPEN; lns_init.ctrl_point_security_req_cccd_write_perm = SEC_OPEN; err_code = ble_lns_init(&m_lns, &lns_init); APP_ERROR_CHECK(err_code); ble_lns_route_t route1 = {.route_name = "Route one"}; err_code = ble_lns_add_route(&m_lns, &route1); ble_lns_route_t route2 = {.route_name = "Route two"}; err_code = ble_lns_add_route(&m_lns, &route2); // Initialize Battery Service memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); } /**@brief Initialize the simulators. */ static void sim_init(void) { // battery simulation m_battery_sim_cfg.min = MIN_BATTERY_LEVEL; m_battery_sim_cfg.max = MAX_BATTERY_LEVEL; m_battery_sim_cfg.incr = BATTERY_LEVEL_INCREMENT; m_battery_sim_cfg.start_at_max = true; sensorsim_init(&m_battery_sim_state, &m_battery_sim_cfg); } /**@brief Start application timers. */ static void application_timers_start(void) { uint32_t err_code; // Start application timers err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL); APP_ERROR_CHECK(err_code); err_code = app_timer_start(m_loc_and_nav_timer_id, LOC_AND_NAV_DATA_INTERVAL, NULL); APP_ERROR_CHECK(err_code); }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Heart Rate, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); if (err_code == NRF_SUCCESS) debug_printf("Battery service initialised!\r\n"); else { debug_printf("Error with initialising battery service.\r\n"); APP_ERROR_CHECK(err_code); } // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); if (err_code == NRF_SUCCESS) debug_printf("Device Information service initialised!\r\n"); else { debug_printf("Error with initialising device information service.\r\n"); APP_ERROR_CHECK(err_code); } // Initialize CCH custom Service. cch_service_init(&m_cch_service); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); dfu_app_dm_appl_instance_set(m_app_handle); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
void simble_adv_start(void) { struct ble_gap_advdata advdata = { .length = 0 }; struct ble_gap_ad_flags flags = { .payload_length = 1, .type = BLE_GAP_AD_TYPE_FLAGS, .flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE, }; simble_add_advdata(&flags, &advdata); struct ble_gap_ad_name name; uint16_t namelen = sizeof(advdata); if (sd_ble_gap_device_name_get(name.name, &namelen) != NRF_SUCCESS) namelen = 0; name.type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; name.payload_length = namelen; simble_add_advdata(&name, &advdata); sd_ble_gap_adv_data_set(advdata.data, advdata.length, NULL, 0); ble_gap_adv_params_t adv_params = { .type = BLE_GAP_ADV_TYPE_ADV_IND, .fp = BLE_GAP_ADV_FP_ANY, .interval = 0x400, }; sd_ble_gap_adv_start(&adv_params); onboard_led(ONBOARD_LED_ON); } static void simble_srv_tx_init(void) { uint16_t srv_handle; ble_uuid_t srv_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x1804}; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &srv_uuid, &srv_handle); ble_gatts_char_handles_t chr_handles; ble_gatts_char_md_t char_meta = {.char_props = {.read = 1}}; ble_uuid_t chr_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x2a07}; ble_gatts_attr_md_t chr_attr_meta = { .vloc = BLE_GATTS_VLOC_STACK, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); uint8_t tx_val = 0; ble_gatts_attr_t chr_attr = { .p_uuid = &chr_uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = sizeof(tx_val), .max_len = sizeof(tx_val), .p_value = &tx_val, }; sd_ble_gatts_characteristic_add(srv_handle, &char_meta, &chr_attr, &chr_handles); } /* DM requires a `app_error_handler` */ void __attribute__((weak)) app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) { app_trace_log("[simble]: err: %d, line: %d, file: %s\r\n", error_code, line_num, p_file_name); for (;;) { /* NOTHING */ } } void simble_init(const char *name) { app_trace_init(); sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL); /* XXX assertion handler */ ble_enable_params_t ble_params = { #if defined(SD120) .gap_enable_params = { .role = BLE_GAP_ROLE_PERIPH, }, #endif .gatts_enable_params = { .service_changed = 1, }, }; sd_ble_enable(&ble_params); ble_gap_conn_sec_mode_t mode; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&mode); sd_ble_gap_device_name_set(&mode, (const uint8_t *)name, strlen(name)); // flash storage pstorage_init(); simble_srv_tx_init(); } uint8_t simble_get_vendor_uuid_class(void) { ble_uuid128_t vendorid = {{0x13,0xb0,0xa0,0x71,0xfe,0x62,0x4c,0x01,0xaa,0x4d,0xd8,0x03,0,0,0x0b,0xd0}}; static uint8_t vendor_type = BLE_UUID_TYPE_UNKNOWN; if (vendor_type != BLE_UUID_TYPE_UNKNOWN) return (vendor_type); sd_ble_uuid_vs_add(&vendorid, &vendor_type); return (vendor_type); } void simble_srv_register(struct service_desc *s) { s->next = services; services = s; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &s->uuid, &s->handle); for (int i = 0; i < s->char_count; ++i) { struct char_desc *c = &s->chars[i]; ble_gatts_attr_md_t cccd_md; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; int have_write = c->write_cb != NULL; ble_gatts_char_md_t char_meta = { .char_props = { .broadcast = 0, .read = 1, .write_wo_resp = have_write, .write = have_write, .notify = c->notify, .indicate = c->indicate, .auth_signed_wr = have_write, }, .p_char_user_desc = (uint8_t *)c->desc, .char_user_desc_size = strlen(c->desc), .char_user_desc_max_size = strlen(c->desc), .p_char_pf = c->format.format != 0 ? &c->format : NULL, .p_cccd_md = (c->notify || c->indicate) ? &cccd_md : NULL, }; ble_gatts_attr_md_t chr_attr_meta = { .vlen = 1, .vloc = BLE_GATTS_VLOC_STACK, .rd_auth = 1, .wr_auth = 1, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); if (have_write) BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.write_perm); else BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); ble_gatts_attr_t chr_attr = { .p_uuid = &c->uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = 0, .max_len = c->length, }; sd_ble_gatts_characteristic_add(s->handle, &char_meta, &chr_attr, &c->handles); } } void simble_srv_init(struct service_desc *s, uint8_t type, uint16_t id) { *s = (struct service_desc){ .uuid = {.type = type, .uuid = id}, .char_count = 0, }; }; void simble_srv_char_add(struct service_desc *s, struct char_desc *c, uint8_t type, uint16_t id, const char *desc, uint16_t length) { *c = (struct char_desc){ .uuid = { .type = type, .uuid = id }, .desc = desc, .length = length, };
static uint32_t ach_report_char_add(const uint8_t uuid_type) { // Report characteristic ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_md_t attr_md; ble_uuid_t char_uuid; ble_gatts_attr_t attr_char_value; // Controlpoint characteristic ble_gatts_char_md_t char_ctrlpt_md; ble_gatts_attr_md_t cccd_ctrlpt_md; ble_gatts_attr_md_t attr_ctrlpt_md; ble_uuid_t char_ctrlpt_uuid; ble_gatts_attr_t attr_char_ctrlpt_value; memset(&cccd_md, 0, sizeof(cccd_md)); cccd_md.vloc = BLE_GATTS_VLOC_STACK; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = 1; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = &cccd_md; char_md.p_sccd_md = NULL; char_uuid.type = uuid_type; char_uuid.uuid = LOCAL_CHAR_UUID; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; memset(&attr_char_value, 0, sizeof(attr_char_value)); //lint --e{545} memset(&m_char_value, 0, APP_REPORT_CHAR_LEN); attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = APP_REPORT_CHAR_LEN; attr_char_value.init_offs = 0; attr_char_value.max_len = APP_REPORT_CHAR_LEN; attr_char_value.p_value = m_char_value; uint32_t err_code; err_code = sd_ble_gatts_characteristic_add(m_service_handle, &char_md, &attr_char_value, &m_char_handles); if (err_code != NRF_SUCCESS) { return err_code; } memset(&cccd_ctrlpt_md, 0, sizeof(cccd_ctrlpt_md)); cccd_ctrlpt_md.vloc = BLE_GATTS_VLOC_STACK; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_ctrlpt_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_ctrlpt_md.write_perm); memset(&char_ctrlpt_md, 0, sizeof(char_ctrlpt_md)); char_ctrlpt_md.char_props.notify = 1; char_ctrlpt_md.char_props.write = 1; char_ctrlpt_md.p_char_user_desc = NULL; char_ctrlpt_md.p_char_pf = NULL; char_ctrlpt_md.p_user_desc_md = NULL; char_ctrlpt_md.p_cccd_md = &cccd_ctrlpt_md; char_ctrlpt_md.p_sccd_md = NULL; char_ctrlpt_uuid.type = uuid_type; char_ctrlpt_uuid.uuid = LOCAL_CHAR_CTRLPT_UUID; memset(&attr_ctrlpt_md, 0, sizeof(attr_ctrlpt_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_ctrlpt_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_ctrlpt_md.write_perm); attr_ctrlpt_md.vloc = BLE_GATTS_VLOC_STACK; attr_ctrlpt_md.rd_auth = 0; attr_ctrlpt_md.wr_auth = 1; attr_ctrlpt_md.vlen = 0; memset(&attr_char_ctrlpt_value, 0, sizeof(attr_char_ctrlpt_value)); //lint --e{545} memset(&m_char_ctrlpt_value, 0, APP_CTRLPT_CHAR_LEN); attr_char_ctrlpt_value.p_uuid = &char_ctrlpt_uuid; attr_char_ctrlpt_value.p_attr_md = &attr_ctrlpt_md; attr_char_ctrlpt_value.init_len = APP_CTRLPT_CHAR_LEN; attr_char_ctrlpt_value.init_offs = 0; attr_char_ctrlpt_value.max_len = APP_CTRLPT_CHAR_LEN; attr_char_ctrlpt_value.p_value = m_char_ctrlpt_value; err_code = sd_ble_gatts_characteristic_add(m_service_handle, &char_ctrlpt_md, &attr_char_ctrlpt_value, &m_char_ctrlpt_handles); return err_code; }
/**@brief Function for adding the accel Level characteristic. * * @param[in] p_acc accel Service structure. * @param[in] p_acc_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t accel_level_char_add(ble_acc_t * p_acc, const ble_acc_init_t * p_acc_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; // ble_gatts_attr_t attr_char_value_2; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; // ble_gatts_attr_md_t attr_md_2; ble_gatts_attr_md_t user_desc_md; ble_gatts_char_pf_t accel_pf; uint8_t initial_accel_level; uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN]; uint8_t init_len; uint8_t user_desc[] = "ACCEL"; // Add accel Level characteristic if (p_acc->is_notification_supported) { memset(&cccd_md, 0, sizeof(cccd_md)); // According to acc_SPEC_V10, the read operation on cccd should be possible without // authentication. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_acc_init->accel_level_char_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&user_desc_md, 0, sizeof(user_desc_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&user_desc_md.read_perm); // BLE_GAP_CONN_SEC_MODE_SET_OPEN(&user_desc_md.write_perm); user_desc_md.vloc = BLE_GATTS_VLOC_STACK; memset(&accel_pf, 0, sizeof(accel_pf)); accel_pf.format = BLE_GATT_CPF_FORMAT_UINT16; accel_pf.exponent = 0; accel_pf.unit = 0x2713; //acceleration data memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.write = 1; char_md.char_props.notify = (p_acc->is_notification_supported) ? 1 : 0; char_md.p_char_user_desc = user_desc; char_md.char_user_desc_max_size = 6; char_md.char_user_desc_size = 6; char_md.p_char_pf = &accel_pf; char_md.p_user_desc_md = &user_desc_md; char_md.p_cccd_md = (p_acc->is_notification_supported) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; //adds the acce id to the softdevice stack, puts a reference to where it is //into acc_uuid_type ble_uuid.type = p_acc->uuid_type; ble_uuid.uuid = BLE_UUID_TYPE_VENDOR_BEGIN; memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_acc_init->accel_level_char_attr_md.read_perm; attr_md.write_perm = p_acc_init->accel_level_char_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; initial_accel_level = p_acc_init->initial_batt_level; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = sizeof(uint16_t); attr_char_value.init_offs = 0; attr_char_value.max_len = sizeof(uint16_t); attr_char_value.p_value = &initial_accel_level; err_code = sd_ble_gatts_characteristic_add(p_acc->service_handle, &char_md, &attr_char_value, &p_acc->accel_level_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_acc_init->p_report_ref != NULL) { // Add Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_acc_init->accel_level_report_read_perm; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; init_len = ble_srv_report_ref_encode(encoded_report_ref, p_acc_init->p_report_ref); memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = init_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_report_ref; err_code = sd_ble_gatts_descriptor_add(p_acc->accel_level_handles.value_handle, &attr_char_value, &p_acc->report_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } else { p_acc->report_ref_handle = BLE_GATT_HANDLE_INVALID; } return NRF_SUCCESS; }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Running Speed and Cadence, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_hts_init_t hts_init; ble_rscs_init_t rscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // Initialize Health Thermometer Service memset(&hts_init, 0, sizeof(hts_init)); hts_init.evt_handler = on_hts_evt; hts_init.temp_type_as_characteristic = 0; hts_init.temp_type = BLE_HTS_TEMP_TYPE_BODY; // Here the sec level for the Health Thermometer Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hts_init.hts_meas_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_meas_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_meas_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hts_init.hts_temp_type_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_temp_type_attr_md.write_perm); err_code = ble_hts_init(&m_hts, &hts_init); APP_ERROR_CHECK(err_code); // Initialize Running Speed and Cadence Service memset(&rscs_init, 0, sizeof(rscs_init)); rscs_init.evt_handler = NULL; rscs_init.feature = BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT| BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT| // BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT; // Here the sec level for the Running Speed and Cadence Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_meas_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_feature_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_feature_attr_md.write_perm); err_code = ble_rscs_init(&m_rscs, &rscs_init); APP_ERROR_CHECK(err_code); // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Running Speed and Cadence, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_rscs_init_t rscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // Initialize Running Speed and Cadence Service memset(&rscs_init, 0, sizeof(rscs_init)); rscs_init.evt_handler = NULL; rscs_init.feature = BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT | BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT; rscs_init.initial_rcm.is_inst_stride_len_present = true; rscs_init.initial_rcm.is_total_distance_present = false; rscs_init.initial_rcm.is_running = false; rscs_init.initial_rcm.inst_stride_length = 0; // Here the sec level for the Running Speed and Cadence Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_meas_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_feature_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_feature_attr_md.write_perm); err_code = ble_rscs_init(&m_rscs, &rscs_init); APP_ERROR_CHECK(err_code); // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); }
/**@brief Function for adding Report Map characteristics. * * @param[in] p_hids HID Service structure. * @param[in] p_hids_init Service initialization structure. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t rep_map_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; // Add Report Map characteristic memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = NULL; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_MAP_CHAR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_hids_init->rep_map.security_mode.read_perm; attr_md.write_perm = p_hids_init->rep_map.security_mode.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 1; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = p_hids_init->rep_map.data_len; attr_char_value.init_offs = 0; attr_char_value.max_len = p_hids_init->rep_map.data_len; attr_char_value.p_value = p_hids_init->rep_map.p_data; err_code = sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md, &attr_char_value, &p_hids->rep_map_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_hids_init->rep_map.ext_rep_ref_num != 0 && p_hids_init->rep_map.p_ext_rep_ref == NULL) { return NRF_ERROR_INVALID_PARAM; } for (int i = 0; i < p_hids_init->rep_map.ext_rep_ref_num; ++i) { uint8_t encoded_rep_ref[sizeof(ble_uuid128_t)]; uint8_t encoded_rep_ref_len; // Add External Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_EXTERNAL_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; err_code = sd_ble_uuid_encode(&p_hids_init->rep_map.p_ext_rep_ref[i], &encoded_rep_ref_len, encoded_rep_ref); if (err_code != NRF_SUCCESS) { return err_code; } memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = encoded_rep_ref_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_rep_ref; err_code = sd_ble_gatts_descriptor_add(p_hids->rep_map_handles.value_handle, &attr_char_value, &p_hids->rep_map_ext_rep_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } return NRF_SUCCESS; }
/**@brief Function for adding characteristic to Eddystone service. * * @param[in] p_escs Eddystone Configuration Service structure. * @param[in] p_escs_init Information needed to initialize the service. * @param[in] p_char_init Information needed to initialize the characteristic. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t char_add(const char_init_t * p_char_init, nrf_ble_escs_t * p_escs, void * p_value, ble_gatts_char_handles_t * p_handles) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; VERIFY_PARAM_NOT_NULL(p_char_init); VERIFY_PARAM_NOT_NULL(p_escs); VERIFY_PARAM_NOT_NULL(p_value); VERIFY_PARAM_NOT_NULL(p_handles); memset(&char_md, 0, sizeof(char_md)); memset(&attr_char_value, 0, sizeof(attr_char_value)); memset(&ble_uuid, 0, sizeof(ble_uuid)); memset(&attr_md, 0, sizeof(attr_md)); if(p_char_init->read) { char_md.char_props.read = 1; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); } else { BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm); } if(p_char_init->write) { BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); char_md.char_props.write = 1; } else { BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); } ble_uuid.type = p_escs->uuid_type; ble_uuid.uuid = p_char_init->uuid; attr_md.vloc = p_char_init->vloc; attr_md.rd_auth = p_char_init->rd_auth; attr_md.wr_auth = p_char_init->wr_auth; attr_md.vlen = p_char_init->vlen; attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = p_char_init->init_len; attr_char_value.p_value = p_value; attr_char_value.max_len = p_char_init->max_len; err_code = sd_ble_gatts_characteristic_add(p_escs->service_handle, &char_md, &attr_char_value, p_handles); if(err_code == NRF_SUCCESS) { ASSERT(m_handle_to_uuid_map_idx < BLE_ESCS_NUMBER_OF_CHARACTERISTICS); m_handle_to_uuid_map[m_handle_to_uuid_map_idx].val_handle = p_handles->value_handle; m_handle_to_uuid_map[m_handle_to_uuid_map_idx].uuid = p_char_init->uuid; m_handle_to_uuid_map_idx++; } return err_code; }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Cycling Speed and Cadence, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_cscs_init_t cscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; ble_sensor_location_t sensor_location; // Initialize Cycling Speed and Cadence Service. memset(&cscs_init, 0, sizeof(cscs_init)); cscs_init.evt_handler = NULL; cscs_init.feature = BLE_CSCS_FEATURE_WHEEL_REV_BIT | BLE_CSCS_FEATURE_CRANK_REV_BIT | BLE_CSCS_FEATURE_MULTIPLE_SENSORS_BIT; // Here the sec level for the Cycling Speed and Cadence Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_meas_attr_md.cccd_write_perm); // for the measurement characteristic, only the CCCD write permission can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_feature_attr_md.read_perm); // for the feature characteristic, only the read permission can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_ctrlpt_attr_md.write_perm); // for the SC control point characteristic, only the write permission and CCCD write can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_ctrlpt_attr_md.cccd_write_perm); // for the SC control point characteristic, only the write permission and CCCD write can be set by the application, others are mandated by service specification cscs_init.ctrplt_supported_functions = BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED |BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED |BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED; cscs_init.ctrlpt_evt_handler = sc_ctrlpt_event_handler; cscs_init.list_supported_locations = supported_locations; cscs_init.size_list_supported_locations = sizeof(supported_locations) / sizeof(ble_sensor_location_t); sensor_location = BLE_SENSOR_LOCATION_FRONT_WHEEL; // initializes the sensor location to add the sensor location characteristic. cscs_init.sensor_location = &sensor_location; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_sensor_loc_attr_md.read_perm); // for the sensor location characteristic, only the read permission can be set by the application, others are mendated by service specification err_code = ble_cscs_init(&m_cscs, &cscs_init); APP_ERROR_CHECK(err_code); // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); }
/**@brief Initialize HID Service. */ static void hids_init(void) { uint32_t err_code; ble_hids_init_t hids_init_obj; ble_hids_inp_rep_init_t input_report_array[1]; ble_hids_inp_rep_init_t * p_input_report; ble_hids_outp_rep_init_t output_report_array[1]; ble_hids_outp_rep_init_t * p_output_report; uint8_t hid_info_flags; static uint8_t report_map_data[] = { 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x05, 0x07, // Usage Page (Key Codes) 0x19, 0xe0, // Usage Minimum (224) 0x29, 0xe7, // Usage Maximum (231) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x81, 0x01, // Input (Constant) reserved byte(1) 0x95, 0x05, // Report Count (5) 0x75, 0x01, // Report Size (1) 0x05, 0x08, // Usage Page (Page# for LEDs) 0x19, 0x01, // Usage Minimum (1) 0x29, 0x05, // Usage Maximum (5) 0x91, 0x02, // Output (Data, Variable, Absolute), Led report 0x95, 0x01, // Report Count (1) 0x75, 0x03, // Report Size (3) 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding 0x95, 0x06, // Report Count (6) 0x75, 0x08, // Report Size (8) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x65, // Logical Maximum (101) 0x05, 0x07, // Usage Page (Key codes) 0x19, 0x00, // Usage Minimum (0) 0x29, 0x65, // Usage Maximum (101) 0x81, 0x00, // Input (Data, Array) Key array(6 bytes) 0x09, 0x05, // Usage (Vendor Defined) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Count (2) 0x95, 0x02, // Report Size (8 bit) 0xB1, 0x02, // Feature (Data, Variable, Absolute) 0xC0 // End Collection (Application) }; // Initialize HID Service p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX]; p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN; p_input_report->rep_ref.report_id = INPUT_REP_REF_ID; p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm); p_output_report = &output_report_array[OUTPUT_REPORT_INDEX]; p_output_report->max_len = OUTPUT_REPORT_MAX_LEN; p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID; p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.write_perm); hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK; memset(&hids_init_obj, 0, sizeof(hids_init_obj)); hids_init_obj.evt_handler = on_hids_evt; hids_init_obj.error_handler = service_error_handler; hids_init_obj.is_kb = true; hids_init_obj.is_mouse = false; hids_init_obj.inp_rep_count = 1; hids_init_obj.p_inp_rep_array = input_report_array; hids_init_obj.outp_rep_count = 1; hids_init_obj.p_outp_rep_array = output_report_array; hids_init_obj.feature_rep_count = 0; hids_init_obj.p_feature_rep_array = NULL; hids_init_obj.rep_map.data_len = sizeof(report_map_data); hids_init_obj.rep_map.p_data = report_map_data; hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION; hids_init_obj.hid_information.b_country_code = 0; hids_init_obj.hid_information.flags = hid_info_flags; hids_init_obj.included_services_count = 0; hids_init_obj.p_included_services_array = NULL; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.rep_map.security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.rep_map.security_mode.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.hid_information.security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.hid_information.security_mode.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_inp_rep.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_inp_rep.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_boot_kb_inp_rep.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_rep.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_rep.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_ctrl_point.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_ctrl_point.write_perm); err_code = ble_hids_init(&m_hids, &hids_init_obj); APP_ERROR_CHECK(err_code); }
/**@brief Function for adding the Battery Level characteristic. * * @param[in] p_bas Battery Service structure. * @param[in] p_bas_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t battery_level_char_add(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; uint8_t initial_battery_level; uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN]; uint8_t init_len; // Add Battery Level characteristic if (p_bas->is_notification_supported) { memset(&cccd_md, 0, sizeof(cccd_md)); // According to BAS_SPEC_V10, the read operation on cccd should be possible without // authentication. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_bas_init->battery_level_char_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = (p_bas->is_notification_supported) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_bas_init->battery_level_char_attr_md.read_perm; attr_md.write_perm = p_bas_init->battery_level_char_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; initial_battery_level = p_bas_init->initial_batt_level; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = sizeof(uint8_t); attr_char_value.init_offs = 0; attr_char_value.max_len = sizeof(uint8_t); attr_char_value.p_value = &initial_battery_level; err_code = sd_ble_gatts_characteristic_add(p_bas->service_handle, &char_md, &attr_char_value, &p_bas->battery_level_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_bas_init->p_report_ref != NULL) { // Add Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_bas_init->battery_level_report_read_perm; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; init_len = ble_srv_report_ref_encode(encoded_report_ref, p_bas_init->p_report_ref); memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = init_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_report_ref; err_code = sd_ble_gatts_descriptor_add(p_bas->battery_level_handles.value_handle, &attr_char_value, &p_bas->report_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } else { p_bas->report_ref_handle = BLE_GATT_HANDLE_INVALID; } return NRF_SUCCESS; }
/**@brief Function for adding the Ambient Service values characteristic. * * @param[in] p_amb Ambient Service Service structure. * @param[in] p_amb_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t sensors_char_add(ble_ambient_t * p_amb, const ble_ambient_init_t * p_amb_init){ uint32_t err_code = NRF_SUCCESS; ble_gatts_attr_md_t cccd_md; ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char; ble_gatts_attr_md_t attr_md_no_write; ble_gatts_attr_md_t attr_md_read_write; #if TEMP_ENABLED || PR_ENABLED || HUM_ENABLED || LUM_ENABLED || HUMSOLO_ENABLED ble_uuid_t ble_char_uuid; #endif // Add Ambient Service values characteristics if (p_amb->is_notification_supported) { memset(&cccd_md, 0, sizeof(cccd_md)); // According to BAS_SPEC_V10, the read operation on cccd should be possible without // authentication. Always set cccd to OPEN! BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&char_md, 0, sizeof(char_md)); //Set characteristic metadata, use same for similar characteristics char_md.char_props.read = 1; char_md.char_props.notify = (p_amb->is_notification_supported) ? 1 : 0; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = (p_amb->is_notification_supported) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; char_md.char_ext_props.wr_aux = 0; //Set atribute metadata for sensor values memset(&attr_md_no_write, 0, sizeof(attr_md_no_write)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md_no_write.read_perm); //can read BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md_no_write.write_perm); //can't write attr_md_no_write.vloc = BLE_GATTS_VLOC_STACK; attr_md_no_write.rd_auth = 0; attr_md_no_write.wr_auth = 0; attr_md_no_write.vlen = 1; //Set atribute metadata for configuration memset(&attr_md_read_write, 0, sizeof(attr_md_read_write)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md_read_write.read_perm); //can read BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md_read_write.write_perm); //can write attr_md_read_write.vloc = BLE_GATTS_VLOC_STACK; attr_md_read_write.rd_auth = 0; attr_md_read_write.wr_auth = 0; attr_md_read_write.vlen = 0; memset(&attr_char, 0, sizeof(attr_char)); ///***************** TEMP ***********************/ #if TEMP_ENABLED //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_TEMP_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_no_write; attr_char.init_len = AMB_TEMP_MAX_PACKET_VALUE; attr_char.init_offs = 0; attr_char.max_len = AMB_TEMP_MAX_PACKET_VALUE; attr_char.p_value = p_amb->temp_value; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; //Add temp characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->temp_handles); if(err_code != NRF_SUCCESS) return err_code; //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_TEMP_CONFIG_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_read_write; attr_char.init_len = sizeof(uint8_t); attr_char.init_offs = 0; attr_char.max_len = sizeof(uint8_t); attr_char.p_value = &(p_amb->temp_configuration); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 1; //Add temp configuration characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->temp_configuration_handles); if(err_code != NRF_SUCCESS) return err_code; #endif ///***************** PR ***********************/ #if PR_ENABLED //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_PR_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_no_write; attr_char.init_len = AMB_PR_MAX_PACKET_VALUE; attr_char.init_offs = 0; attr_char.max_len = AMB_PR_MAX_PACKET_VALUE; attr_char.p_value = p_amb->pr_value; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; //Add pressure characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->pr_handles); if(err_code != NRF_SUCCESS) return err_code; //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_PR_CONFIG_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_read_write; attr_char.init_len = sizeof(uint8_t); attr_char.init_offs = 0; attr_char.max_len = sizeof(uint8_t); attr_char.p_value = &(p_amb->pr_configuration); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 1; //Add temp configuration characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->pr_configuration_handles); if(err_code != NRF_SUCCESS) return err_code; #endif ///***************** HUM ***********************/ #if HUM_ENABLED //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_HUM_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_no_write; attr_char.init_len = AMB_HUM_MAX_PACKET_VALUE; attr_char.init_offs = 0; attr_char.max_len = AMB_HUM_MAX_PACKET_VALUE; attr_char.p_value = p_amb->hum_value; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; //Add pressure characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->hum_handles); if(err_code != NRF_SUCCESS) return err_code; //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_HUM_CONFIG_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_read_write; attr_char.init_len = sizeof(uint8_t); attr_char.init_offs = 0; attr_char.max_len = sizeof(uint8_t); attr_char.p_value = &(p_amb->hum_configuration); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 1; //Add temp configuration characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->hum_configuration_handles); if(err_code != NRF_SUCCESS) return err_code; #endif ///***************** HUMSOLO ***********************/ #if HUMSOLO_ENABLED //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_HUMSOLO_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_no_write; attr_char.init_len = AMB_HUMSOLO_MAX_PACKET_VALUE; attr_char.init_offs = 0; attr_char.max_len = AMB_HUMSOLO_MAX_PACKET_VALUE; attr_char.p_value = p_amb->humsolo_value; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; //Add pressure characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->humsolo_handles); if(err_code != NRF_SUCCESS) return err_code; //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_HUMSOLO_CONFIG_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_read_write; attr_char.init_len = sizeof(uint8_t); attr_char.init_offs = 0; attr_char.max_len = sizeof(uint8_t); attr_char.p_value = &(p_amb->humsolo_configuration); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 1; //Add temp configuration characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->humsolo_configuration_handles); if(err_code != NRF_SUCCESS) return err_code; #endif ///***************** LUM ***********************/ #if LUM_ENABLED //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_LUM_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_no_write; attr_char.init_len = AMB_LUM_MAX_PACKET_VALUE; attr_char.init_offs = 0; attr_char.max_len = AMB_LUM_MAX_PACKET_VALUE; attr_char.p_value = p_amb->lum_value; char_md.char_props.write = 0; char_md.char_props.write_wo_resp = 0; //Add luminosity characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->lum_handles); if(err_code != NRF_SUCCESS) return err_code; //Set atributes struct ble_char_uuid.type = p_amb->uuid_type; ble_char_uuid.uuid = AMBIENT_UUID_LUM_CONFIG_CHAR; attr_char.p_uuid = &ble_char_uuid; attr_char.p_attr_md = &attr_md_read_write; attr_char.init_len = sizeof(uint8_t); attr_char.init_offs = 0; attr_char.max_len = sizeof(uint8_t); attr_char.p_value = &(p_amb->lum_configuration); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 1; //Add temp configuration characteristic err_code = sd_ble_gatts_characteristic_add(p_amb->service_handle, &char_md, &attr_char, &p_amb->lum_configuration_handles); if(err_code != NRF_SUCCESS) return err_code; #endif //A map for handles, maybe a bit rudimentary... type_to_handle[0].type = BLE_AMBIENT_TEMP; #if TEMP_ENABLED type_to_handle[0].handle = &(p_amb->temp_handles); type_to_handle[0].config_handle = &(p_amb->temp_configuration_handles); type_to_handle[0].value = (p_amb->temp_value); #endif type_to_handle[1].type = BLE_AMBIENT_PR; #if PR_ENABLED type_to_handle[1].handle = &(p_amb->pr_handles); type_to_handle[1].config_handle = &(p_amb->pr_configuration_handles); type_to_handle[1].value = (p_amb->pr_value); #endif type_to_handle[2].type = BLE_AMBIENT_HUM; #if HUM_ENABLED type_to_handle[2].handle = &(p_amb->hum_handles); type_to_handle[2].config_handle = &(p_amb->hum_configuration_handles); type_to_handle[2].value = (p_amb->hum_value); #endif type_to_handle[3].type = BLE_AMBIENT_LUM; #if LUM_ENABLED type_to_handle[3].handle = &(p_amb->lum_handles); type_to_handle[3].config_handle = &(p_amb->lum_configuration_handles); type_to_handle[3].value = (p_amb->lum_value); #endif type_to_handle[4].type = BLE_AMBIENT_HUMSOLO; #if HUMSOLO_ENABLED type_to_handle[4].handle = &(p_amb->humsolo_handles); type_to_handle[4].config_handle = &(p_amb->humsolo_configuration_handles); type_to_handle[4].value = (p_amb->humsolo_value); #endif return err_code; }