Hi,
I am trying to migrate my project file from Keil 5 to Segger Embedded Studio (SES).
After porting all my source code and configuration files, SES is able to compile and download code to my custom NRF52840 board without error. But I cannot update any data on my custom BLE characteristics - It is successfully initialised but didn't receive any notification data.
But with the same code compiled with Keil, I can update my custom BLE characteristic without any errors.
Here is my code when adding custom service and characteristics:
//Function to add custom Characteristics (1) static uint32_t custom_char_add(ble_os2_t * p_custom_service, ble_uuid128_t CUSTOM_BASE_UUID, uint16_t CUSTOM_CHARACTERISTIC_UUID, uint8_t characteristic_channel) { //Add a custom characteristic UUID uint32_t err_code; ble_uuid_t char_uuid; ble_uuid128_t base_uuid = CUSTOM_BASE_UUID; char_uuid.uuid = CUSTOM_CHARACTERISTIC_UUID; err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type); APP_ERROR_CHECK(err_code); //Add read/write properties to our characteristic ble_gatts_char_md_t char_md; memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; //Enable Read char_md.char_props.write = 0; //Enable Write //Configuring Client Characteristic Configuration Descriptor metadata and add to char_md structure 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; char_md.p_cccd_md = &cccd_md; char_md.char_props.notify = 1; //Configure the attribute metadata ble_gatts_attr_md_t attr_md; memset(&attr_md, 0, sizeof(attr_md)); attr_md.vloc = BLE_GATTS_VLOC_STACK; //Set read/write security levels to our characteristic BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); //BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); //Configure the characteristic value attribute ble_gatts_attr_t attr_char_value; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; //Set characteristic length in number of bytes attr_char_value.max_len = BLE_NUS_MAX_DATA_LEN; attr_char_value.init_len = BLE_NUS_MAX_DATA_LEN; uint8_t value[244] = {0x12,0x34,0x56,0x78,0x90,0x91,0x92}; value[243] = 0x99; attr_char_value.p_value = value; //Add our new characteristic to the service switch (characteristic_channel) { case 1: err_code = sd_ble_gatts_characteristic_add(p_custom_service->service_handle, &char_md, &attr_char_value, &p_custom_service->char_handles_x); APP_ERROR_CHECK(err_code); break; case 2: err_code = sd_ble_gatts_characteristic_add(p_custom_service->service_handle, &char_md, &attr_char_value, &p_custom_service->char_handles_y); APP_ERROR_CHECK(err_code); break; case 3: err_code = sd_ble_gatts_characteristic_add(p_custom_service->service_handle, &char_md, &attr_char_value, &p_custom_service->char_handles_z); APP_ERROR_CHECK(err_code); break; } return NRF_SUCCESS; } //Function to iniliase customise service UUID void custom_service_init_mode_2(ble_os2_t * p_custom_service, ble_uuid128_t CUSTOM_BASE_UUID, uint16_t CUSTOM_SERVICE) { //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 = CUSTOM_BASE_UUID; service_uuid.uuid = CUSTOM_SERVICE; err_code = sd_ble_uuid_vs_add(&base_uuid, &service_uuid.type); APP_ERROR_CHECK(err_code); m_conn_handle = BLE_CONN_HANDLE_INVALID; //Add custom service err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_custom_service->service_handle); APP_ERROR_CHECK(err_code); uint16_t characteristic_input = BLE_CHARACTERISTIC_X; custom_char_add(p_custom_service, base_uuid, characteristic_input, 1); characteristic_input = BLE_CHARACTERISTIC_Y; custom_char_add(p_custom_service, base_uuid, characteristic_input, 2); characteristic_input = BLE_CHARACTERISTIC_Z; custom_char_add(p_custom_service, base_uuid, characteristic_input, 3); }
Here is the code when trying to initialise together with default BLE NUS.
// Function for initializing services that will be used by the application. static void services_init(void) { uint32_t err_code; ble_nus_init_t nus_init; nrf_ble_qwr_init_t qwr_init = {0}; // Initialize Queued Write Module. qwr_init.error_handler = nrf_qwr_error_handler; err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init); APP_ERROR_CHECK(err_code); // Initialize NUS. memset(&nus_init, 0, sizeof(nus_init)); nus_init.data_handler = nus_data_handler; err_code = ble_nus_init(&m_nus, &nus_init); APP_ERROR_CHECK(err_code); //Adding customised service ble_uuid128_t uuid_input = BLE_BASE_UUID; uint16_t service_input = BLE_SERVICE_MODE_1; custom_service_init_mode_2(&ble_service_mode_2, uuid_input, service_input); }
Here is the code to update data on specific characteristic.
// Function to be called when updating custom characteristic value uint32_t mode_2_characteristic_update(ble_os2_t *p_custom_service, uint8_t *p_data, uint16_t *p_length, uint8_t channel, uint16_t conn_handle) { ret_code_t err_code; ble_gatts_hvx_params_t hvx_params; VERIFY_PARAM_NOT_NULL(p_custom_service); //Update characteristic value if (m_conn_handle != BLE_CONN_HANDLE_INVALID) { memset(&hvx_params, 0, sizeof(hvx_params)); switch (channel) { case 1: hvx_params.handle = p_custom_service->char_handles_x.value_handle; break; case 2: hvx_params.handle = p_custom_service->char_handles_y.value_handle; break; case 3: hvx_params.handle = p_custom_service->char_handles_z.value_handle; break; default: hvx_params.handle = p_custom_service->char_handles_x.value_handle; break; } hvx_params.p_data = p_data; hvx_params.p_len = p_length; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; } return sd_ble_gatts_hvx(m_conn_handle, &hvx_params); }
And the I use the default ble_evt_handler with added BLE_GATTS_EVT_HVN_TX_COMPLETE to manage the activities on custom characteristics:
// Function for handling BLE events. static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: NRF_LOG_INFO("Connected"); err_code = bsp_indication_set(BSP_INDICATE_CONNECTED); APP_ERROR_CHECK(err_code); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle); APP_ERROR_CHECK(err_code); ble_flag = true; break; case BLE_GAP_EVT_DISCONNECTED: NRF_LOG_INFO("Disconnected"); // LED indication will be changed when advertising starts. m_conn_handle = BLE_CONN_HANDLE_INVALID; ble_flag = false; break; case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { NRF_LOG_DEBUG("PHY update request."); ble_gap_phys_t const phys = { .rx_phys = BLE_GAP_PHY_AUTO, .tx_phys = BLE_GAP_PHY_AUTO, }; err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys); APP_ERROR_CHECK(err_code); } break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: // Pairing not supported err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_SYS_ATTR_MISSING: // No system attributes have been stored. err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0); APP_ERROR_CHECK(err_code); break; case BLE_GATTC_EVT_TIMEOUT: // Disconnect on GATT Client timeout event. err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_TIMEOUT: // Disconnect on GATT Server timeout event. err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_HVN_TX_COMPLETE: NRF_LOG_INFO("Packet sent"); break; default: // No implementation needed. break; } }.
Here is my UUID definitions:
//BLE Customised Services & Characteristics #define BLE_BASE_UUID {0x23, 0xD1, 0x13, 0xEF, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x04, 0x6e} // 128-bit base UUID #define BLE_SERVICE_MODE_1 0x0002 // Just a random, but recognizable value #define BLE_SERVICE_MODE_2 0x0003 // Just a random, but recognizable value #define BLE_CHARACTERISTIC_X 0x0004 #define BLE_CHARACTERISTIC_Y 0x0005 #define BLE_CHARACTERISTIC_Z 0x0006 typedef struct { //uint16_t conn_handle; // Handle of current connection uint16_t service_handle; // Handle of custom service (as provided by the BLE stack). ble_gatts_char_handles_t char_handles_x; ble_gatts_char_handles_t char_handles_y; ble_gatts_char_handles_t char_handles_z; } ble_os2_t; static ble_os2_t ble_service_mode_2;
Any advice are much appreciated. Thanks!