Why my Custom Characteristic always show hex value instead of Int or Text?

Hi

I have created a code in segger for NRF 52840. I have created my custom service/characteristic and also the LED and Battery Level. Other Service like LED and Battery Level shows values in text or percentage. But my custom characteristic always shows in hexadecimal. Can i change it to long int or text? if so how do i? Also when i write values in any characteristic for example: if i write 123 the value shows as 7B,"{". why the extra bracket coming?

#include <stdint.h>
#include <string.h>
#include "nrf_gpio.h"
#include "our_service.h"
#include "ble_srv_common.h"
#include "app_error.h"

int32_t last_temperature = -1;
#define MAX_LEN 255
    

// ALREADY_DONE_FOR_YOU: Declaration of a function that will take care of some housekeeping of ble connections related to our service and characteristic
void ble_our_service_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
  	ble_os_t * p_our_service =(ble_os_t *) p_context;  
		// OUR_JOB: Step 3.D Implement switch case handling BLE events related to our service. 
	
        switch(p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                  p_our_service->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                  break;
            case BLE_GAP_EVT_DISCONNECTED:
                  p_our_service->conn_handle = BLE_CONN_HANDLE_INVALID;
                  break;
            default:
                  break;
        }
	
}

/**@brief Function for adding our new characterstic to "Our service" that we initiated in the previous tutorial. 
 *
 * @param[in]   p_our_service        Our Service structure.
 *
 */
static uint32_t our_char_add(ble_os_t * p_our_service, char_type_t char_type)
{
    // OUR_JOB: Step 2.A, Add a custom characteristic UUID
    uint32_t            err_code;
    ble_uuid_t          char_uuid;
    ble_uuid128_t       base_uuid = BLE_UUID_OUR_BASE_UUID;
    static uint8_t      zero_init[MAX_LEN] = {0};
    
    switch (char_type)
    {
        case hospital_char: 
          char_uuid.uuid = BLE_UUID_OUR_HOSPITAL_UUID;
          break;
        case branch_char: 
          char_uuid.uuid = BLE_UUID_OUR_BRANCH_UUID;
          break;
        case ward_char: 
          char_uuid.uuid = BLE_UUID_OUR_WARD_UUID;
          break;
        case bed_char: 
          char_uuid.uuid = BLE_UUID_OUR_BED_UUID;
          break;
        default:
          break;
    }
    
    err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type);
    APP_ERROR_CHECK(err_code);    

    
    // OUR_JOB: Step 2.F 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;
    char_md.char_props.write = 1;




    
    // OUR_JOB: Step 3.A, 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;


   
    
    // OUR_JOB: Step 2.B, 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;
    // For example if you need Man In The Middle protection (MITM) or a passkey to access your attribute. We will circle back to this. 

	
    
    
    // OUR_JOB: Step 2.G, 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);

    
    // OUR_JOB: Step 2.C, 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;
    attr_char_value.max_len = sizeof(uint8_t);
    attr_char_value.init_len = sizeof(uint8_t);
    //uint8_t value = 123;
    //attr_char_value.p_value = &value;
    attr_char_value.p_value = zero_init;


    
    // OUR_JOB: Step 2.H, Set characteristic length in number of bytes


    // OUR_JOB: Step 2.E, Add our new characteristic to the service
    switch (char_type)
    {
        case hospital_char: 
          err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                               &char_md, 
                                               &attr_char_value, 
                                               &p_our_service->char_hospital_handles);
          APP_ERROR_CHECK(err_code);
          break;
        case branch_char: 
          err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                               &char_md, 
                                               &attr_char_value, 
                                               &p_our_service->char_branch_handles);
          APP_ERROR_CHECK(err_code);
          break;
        case ward_char: 
          err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                               &char_md, 
                                               &attr_char_value, 
                                               &p_our_service->char_ward_handles);
          APP_ERROR_CHECK(err_code);
          break;
        case bed_char: 
          err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                               &char_md, 
                                               &attr_char_value, 
                                               &p_our_service->char_bed_handles);
          APP_ERROR_CHECK(err_code);
          break;
        default:
          break;
    }
   
    
                                          


    return NRF_SUCCESS;
}


/**@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)
{
    uint32_t   err_code; // Variable to hold return codes from library and softdevice functions

    // FROM_SERVICE_TUTORIAL: Declare 16-bit service and 128-bit base UUIDs and add them to the BLE stack
    ble_uuid_t        service_uuid;
    ble_uuid128_t     base_uuid = BLE_UUID_OUR_BASE_UUID;
    service_uuid.uuid = BLE_UUID_OUR_SERVICE_UUID;
    err_code = sd_ble_uuid_vs_add(&base_uuid, &service_uuid.type);
    APP_ERROR_CHECK(err_code);    
    
    // OUR_JOB: Step 3.B, Set our service connection handle to default value. I.e. an invalid handle since we are not yet in a connection.
	
    p_our_service->conn_handle = BLE_CONN_HANDLE_INVALID;
    // FROM_SERVICE_TUTORIAL: 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);
    
    // OUR_JOB: Call the function our_char_add() to add our new characteristic to the service. 
    our_char_add(p_our_service, hospital_char);
    our_char_add(p_our_service, branch_char);
    our_char_add(p_our_service, ward_char);
    our_char_add(p_our_service, bed_char);


}

// ALREADY_DONE_FOR_YOU: Function to be called when updating characteristic value
void our_temperature_characteristic_update(ble_os_t *p_our_service, int32_t *temperature_value)
{
    if (last_temperature != *temperature_value)
    {
    // OUR_JOB: Step 3.E, Update characteristic value
    if (p_our_service->conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        uint16_t len = 4;
        ble_gatts_hvx_params_t hvx_params;
        memset(&hvx_params, 0, sizeof(hvx_params));

        hvx_params.handle = p_our_service->char_hospital_handles.value_handle;
        hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = 0;
        hvx_params.p_len = &len;
        hvx_params.p_data = (uint8_t*) temperature_value;

        sd_ble_gatts_hvx(p_our_service->conn_handle, &hvx_params);

    }
    }
    last_temperature = *temperature_value;

}

Parents
  • Hi,

    For known characteristics (such as the ones from Bluetooth SIG) the nRF Connect app knows how to format the characteristic value. For instance as a number, as text, or as binary (on/off) values.

    For custom characteristics, the nRF Connect app does not know how to format the characteristic value, and defaults to showing the hex value and the corresponding ascii character. This is what you see; when using the decimal value 123, it corresponds to the hexadecimal value 0x7B, or the ascii character '{'.

    If you long press on the line, in the nRF Connect app, you should get a menu where you can select "edit" for selecting how the characteristic should be formatted.

    In the left hamburger menu in the nRF Connect app for Android, you will have "Definitions", which lists known services and characteristics. There you can also export or import definition files that are compatible with nRF Connect for Desktop.

    Regards,
    Terje

Reply
  • Hi,

    For known characteristics (such as the ones from Bluetooth SIG) the nRF Connect app knows how to format the characteristic value. For instance as a number, as text, or as binary (on/off) values.

    For custom characteristics, the nRF Connect app does not know how to format the characteristic value, and defaults to showing the hex value and the corresponding ascii character. This is what you see; when using the decimal value 123, it corresponds to the hexadecimal value 0x7B, or the ascii character '{'.

    If you long press on the line, in the nRF Connect app, you should get a menu where you can select "edit" for selecting how the characteristic should be formatted.

    In the left hamburger menu in the nRF Connect app for Android, you will have "Definitions", which lists known services and characteristics. There you can also export or import definition files that are compatible with nRF Connect for Desktop.

    Regards,
    Terje

Children
  • Thanks. I did  the same and also modified the code as below and it works fine as text. INT format is not available as of now i guess in definitions. I have another query and i think its better to open in another ticket. Thanks for the information.

    attr_char_value.max_len = 10;
    attr_char_value.init_len = 10;
    char * value = "xxxxxxxxxx";
    attr_char_value.p_value = value;

Related