I've been trying to add a new BLE service to my device. I've followed the instructions in this tutorial, up to step 7 (so no characteristics or anything), but the device is not advertising. In fact, the software seems to fail entirely; it does not seem to make it past the advertising_init and services_init functions in the initialization sequence. (In main() the device is supposed to blink an LED after this sequence is finished, which it does not.)
I've done nothing to modify the code other than these changes specified in the tutorial. The software compiles and loads on the device without any warnings or errors. I've posted the relevant code below; let me know if you need any more information.
// main.c static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_HEART_RATE_SERVICE, BLE_UUID_TYPE_BLE}, {BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE}, {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}, {BLE_UUID_OUR_SERVICE, BLE_UUID_TYPE_VENDOR_BEGIN}}; ble_os_t m_our_service; 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); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&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_OPEN(&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_OPEN(&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(&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); our_service_init(&m_our_service); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT } static void advertising_init(void) { ble_advdata_t srdata; memset(&srdata, 0, sizeof(srdata)); srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); srdata.uuids_complete.p_uuids = m_adv_uuids; uint32_t err_code; ble_advdata_t advdata; // Build advertising data struct to pass into @ref ble_advertising_init. memset(&advdata, 0, sizeof(advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.include_appearance = true; advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); advdata.uuids_complete.p_uuids = m_adv_uuids; ble_adv_modes_config_t options = {0}; options.ble_adv_slow_enabled = BLE_ADV_SLOW_ENABLED; options.ble_adv_slow_interval = APP_ADV_INTERVAL; options.ble_adv_slow_timeout = APP_ADV_TIMEOUT_IN_SECONDS; err_code = ble_advertising_init(&advdata, &srdata, &options, on_adv_evt, NULL); APP_ERROR_CHECK(err_code); } int main(void){ uint32_t err_code; SEGGER_RTT_WriteString(0, "Exectuing program.\n"); timers_init(); ble_stack_init(); device_manager_init(1); // i set erase_bonds to 1 so the embedivet won't do that annoying thing where it refuses to bond with the central after you change the central's firmware gap_params_init(); services_init(); advertising_init(); conn_params_init(); setupPins(); nrf_gpio_pin_write(MODE, 1); //enable the load switch flashGreen(); // test green led twi_init(); // initialize the i2c bus ledFlash(); // indicate success rtcSetup(); // reach out to the accelerometer ledFlash(); // indicate success // Run the rest of the program; the code never makes it to this point }
// our_service.h #ifndef OUR_SERVICE_H__ #define OUR_SERVICE_H__ #include <stdint.h> #include "ble.h" #include "ble_srv_common.h" #define BLE_UUID_OUR_BASE_UUID {{0x23, 0xD1, 0x13, 0xEF, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}} // 128-bit base UUID #define BLE_UUID_OUR_SERVICE 0xABCD // Just a random, but recognizable value /** * @brief This structure contains various status information for our service. * It only holds one entry now, but will be populated with more items as we go. * The name is based on the naming convention used in Nordic's SDKs. * 'ble indicates that it is a Bluetooth Low Energy relevant structure and * os is short for Our Service). */ typedef struct { uint16_t service_handle; /**< Handle of Our Service (as provided by the BLE stack). */ }ble_os_t; /**@brief Function for initializing our new service. * * @param[in] p_our_service Pointer to Our Service structure. */ void our_service_init(ble_os_t * p_our_service); #endif /* _ OUR_SERVICE_H__ */
// our_service.c #include <stdint.h> #include <string.h> #include "our_service.h" #include "ble_srv_common.h" #include "app_error.h" #include "SEGGER_RTT.h" /**@brief Function for initiating our new service. * * @param[in] p_our_service Our Service structure. * */ void our_service_init(ble_os_t * p_our_service) { // STEP 3: Declare 16 bit service and 128 bit base UUIDs and add them to BLE stack table uint32_t err_code; ble_uuid_t service_uuid; ble_uuid128_t base_uuid = BLE_UUID_OUR_BASE_UUID; service_uuid.uuid = BLE_UUID_OUR_SERVICE; err_code = sd_ble_uuid_vs_add(&base_uuid, &service_uuid.type); APP_ERROR_CHECK(err_code); // STEP 4: Add our service err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_our_service->service_handle); APP_ERROR_CHECK(err_code); // Print messages to Segger Real Time Terminal // UNCOMMENT THE FOUR LINES BELOW AFTER INITIALIZING THE SERVICE OR THE EXAMPLE WILL NOT COMPILE. SEGGER_RTT_WriteString(0, "Exectuing our_service_init().\n"); // Print message to RTT to the application flow SEGGER_RTT_printf(0, "Service UUID: 0x%#04x\n", service_uuid.uuid); // Print service UUID should match definition BLE_UUID_OUR_SERVICE SEGGER_RTT_printf(0, "Service UUID type: 0x%#02x\n", service_uuid.type); // Print UUID type. Should match BLE_UUID_TYPE_VENDOR_BEGIN. Search for BLE_UUID_TYPES in ble_types.h for more info SEGGER_RTT_printf(0, "Service handle: 0x%#04x\n", p_our_service->service_handle); // Print out the service handle. Should match service handle shown in MCP under Attribute values }