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!