Hello,
I'm working on adding an HTS service to an existing device (nRF52832), and running into a problem that can be reproduced on PCA10040 and S132 5.0
When my code is running and I use nRF Connect (Android) to monitor the device and read the temperature, withing a few seconds the temperature_measurement_send() function hits APP_ERROR_HANDLER with error 0X3401. Please note that this happens only if the device is not bonded. If , the device is bonded and everything works.
I need to be able to use the HTS profile both when the device is bonded and when it's not. So I'm trying to understand why it doesn't work without bonding. The failing portion of the code is
static void temperature_measurement_send(void) { ble_hts_meas_t temperature_meas; ret_code_t err_code = 0; if (!m_hts_meas_ind_conf_pending) { hts_measurement(&temperature_meas); if (m_hts.conn_handle != BLE_CONN_HANDLE_INVALID) { err_code = ble_hts_measurement_send(&m_hts, &temperature_meas); } switch (err_code) { case NRF_SUCCESS: // Measurement was successfully sent, wait for confirmation. m_hts_meas_ind_conf_pending = true; break; case NRF_ERROR_INVALID_STATE: // Ignore error. break; default: APP_ERROR_HANDLER(err_code); break; } } }.
And here's how it's initialized
BLE_BAS_DEF(m_bas); /**< Structure used to identify the battery service. */ BLE_HTS_DEF(m_hts); /**< Structure used to identify the health thermometer service. */ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */ static ble_uuid_t m_adv_uuids[] = /**< Universally unique service identifiers. */ { {BLE_UUID_HEALTH_THERMOMETER_SERVICE, BLE_UUID_TYPE_BLE}, {BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE}, {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE} }; /**@brief Function for initializing the Advertising functionality. * * @details Encodes the required advertising data and passes it to the stack. * Also builds a structure to be passed to the stack when starting advertising. */ static void advertising_init(void) { ret_code_t err_code; ble_advertising_init_t init; memset(&init, 0, sizeof(init)); init.advdata.name_type = BLE_ADVDATA_FULL_NAME; init.advdata.include_appearance = true; init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); init.advdata.uuids_complete.p_uuids = m_adv_uuids; init.config.ble_adv_fast_enabled = true; init.config.ble_adv_fast_interval = APP_ADV_INTERVAL; init.config.ble_adv_fast_timeout = APP_ADV_TIMEOUT_IN_SECONDS; init.evt_handler = on_adv_evt; err_code = ble_advertising_init(&m_advertising, &init); APP_ERROR_CHECK(err_code); ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); } /**@brief Function for initializing services that will be used by the application. * * @details Initialize the Health Thermometer, Battery and Device Information services. */ static void services_init(void) { ret_code_t err_code; ble_hts_init_t hts_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; ble_dis_sys_id_t sys_id; char foo[]="012345678\0"; // Initialize Health Thermometer Service memset(&hts_init, 0, sizeof(hts_init)); hts_init.evt_handler = on_hts_evt; hts_init.temp_type_as_characteristic = TEMP_TYPE_AS_CHARACTERISTIC; hts_init.temp_type = BLE_HTS_TEMP_TYPE_FINGER; // 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 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); NRF_LOG_INFO("Battery init = %d.", err_code); NRF_LOG_INFO("Battery init addr = %d.", &err_code); 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_srv_ascii_to_utf8(&dis_init.model_num_str, MODEL_NUM); sys_id.manufacturer_id = MANUFACTURER_ID; sys_id.organizationally_unique_id = ORG_UNIQUE_ID; dis_init.p_sys_id = &sys_id; 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); }
I have seen other questions about error 0x3401, but none of the suggestions seemed to apply to my case. Pointers are really appreciated
EDIT: I added the following code to the temperature_measurement_send() function
case BLE_GATTS_EVT_SYS_ATTR_MISSING: err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0); APP_ERROR_CHECK(err_code);
And the problem goes away, but the device is automatically bonded as a result. Is there a way to solve the problem without bonding automatically?