This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to create characteristics with different UUIDs?

Hi everyone,
my colleague developed a firmware using Arduino Nano 33 BLE and PlatformIO. Now I have to rewrite the code using Segger Embedded Studio. The problem is in the declaration of the characteristics of a service. There are in fact two characteristics that have different base UUIDs.

My colleague added these characteristics using the following code:

//Battery Service
BLEService Battery_service("72050700-df73-4f35-8e62-965e9d019cb3");

    BLEStringCharacteristic Battery_SerialID("72050701-df73-4f35-8e62-965e9d019cb3", BLERead, 17);
    BLEStringCharacteristic Battery_Hardware_rev("72050702-df73-4f35-8e62-965e9d019cb3", BLERead, 12);
    BLEStringCharacteristic Battery_Firmware_rev("72050703-df73-4f35-8e62-965e9d019cb3", BLERead, 12);
    BLEUnsignedCharCharacteristic Battery_charge("72050704-df73-4f35-8e62-965e9d019cb3", BLERead | BLENotify);
    BLEShortCharacteristic Battery_temperature("72050705-df73-4f35-8e62-965e9d019cb3", BLERead | BLENotify);
    BLEUnsignedCharCharacteristic Battery_health("72050706-df73-4f35-8e62-965e9d019cb3", BLERead);
    BLEUnsignedShortCharacteristic Battery_cycles("72050707-df73-4f35-8e62-965e9d019cb3", BLERead);
    BLEUnsignedCharCharacteristic Battery_warning("72050708-df73-4f35-8e62-965e9d019cb3", BLERead | BLEWrite);
    BLEUnsignedCharCharacteristic Battery_settings("72050709-df73-4f35-8e62-965e9d019cb3", BLERead | BLEWrite);

//Authentication Service
BLEService Autentication_service("00000001-0000-4f35-8e62-965e9d019cb3");

    BLEUnsignedShortCharacteristic KeyA("00000001-0001-4f35-8e62-965e9d019cb3", BLERead);
    BLEUnsignedShortCharacteristic KeyB("00000001-0002-4f35-8e62-965e9d019cb3", BLERead | BLEWrite);
...

//Battery Service --> Add Characteristics
Bluetooth::Battery_service.addCharacteristic(Battery_SerialID);
Bluetooth::Battery_service.addCharacteristic(Battery_Hardware_rev);
Bluetooth::Battery_service.addCharacteristic(Battery_Firmware_rev);
Bluetooth::Battery_service.addCharacteristic(Battery_charge);
Bluetooth::Battery_service.addCharacteristic(Battery_temperature);
Bluetooth::Battery_service.addCharacteristic(Battery_health);
Bluetooth::Battery_service.addCharacteristic(Battery_cycles);
Bluetooth::Battery_service.addCharacteristic(Battery_warning);
Bluetooth::Battery_service.addCharacteristic(Battery_settings);

//Authentication Service
Bluetooth::Autentication_service.addCharacteristic(KeyA);
Bluetooth::Autentication_service.addCharacteristic(KeyB);
    

I know well how to implement the battery service and its characteristics using Segger Embedded Studio.

In fact, the characteristics of the battery have a UUID that respects the 7205xxxx-df73-4f35-8e62-965e9d019cb3 structure. As indicated in this guide.

The authentication service, on the other hand, has two characteristics that do not respect the aforementioned structure.

How do I add these two characteristics?

Thanks so much.

Parents
  • Hello,

    I assume you are using the nRF5 SDK now? In that case, you will need to use sd_ble_uuid_vs_add() to add the base UUIDs for your characteristics. Below you can find a diff showing the changes I made to our UART service initialization (see UART/Serial Port Emulation over BLE) to make the RX characteristic have a different base UUID compared to the primary service.

    diff --git a/ble_nus.c b/ble_nus.c
    index ca77de6..b32772f 100644
    --- a/ble_nus.c
    +++ b/ble_nus.c
    @@ -244,12 +244,16 @@ void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
         }
     }
     
    +#define NUS_RX_BASE_UUID {0x80, 0xb9, 0xcb, 0x22, 0xd4, 0x47, 0x4b, 0x85, 0x8a, 0x4b, 0x88, 0x8e, 0x00, 0x00, 0x90, 0xf2}
    +
     
     uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
     {
         ret_code_t            err_code;
         ble_uuid_t            ble_uuid;
    +    uint8_t               uuid_tag;
         ble_uuid128_t         nus_base_uuid = NUS_BASE_UUID;
    +    ble_uuid128_t         nus_rx_base_uuid = NUS_RX_BASE_UUID;
         ble_add_char_params_t add_char_params;
     
         VERIFY_PARAM_NOT_NULL(p_nus);
    @@ -272,11 +276,15 @@ uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
                                             &p_nus->service_handle);
         /**@snippet [Adding proprietary Service to the SoftDevice] */
         VERIFY_SUCCESS(err_code);
    +    
    +
    +    err_code = sd_ble_uuid_vs_add(&nus_rx_base_uuid, &uuid_tag);
    +    VERIFY_SUCCESS(err_code);
     
         // Add the RX Characteristic.
         memset(&add_char_params, 0, sizeof(add_char_params));
         add_char_params.uuid                     = BLE_UUID_NUS_RX_CHARACTERISTIC;
    -    add_char_params.uuid_type                = p_nus->uuid_type;
    +    add_char_params.uuid_type                = uuid_tag;
         add_char_params.max_len                  = BLE_NUS_MAX_RX_CHAR_LEN;
         add_char_params.init_len                 = sizeof(uint8_t);
         add_char_params.is_var_len               = true;
    diff --git a/sdk_config.h b/sdk_config.h
    index 126fe8f..aa4b7ad 100644
    --- a/sdk_config.h
    +++ b/sdk_config.h
    @@ -11466,7 +11466,7 @@
     
     // <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs. 
     #ifndef NRF_SDH_BLE_VS_UUID_COUNT
    -#define NRF_SDH_BLE_VS_UUID_COUNT 1
    +#define NRF_SDH_BLE_VS_UUID_COUNT 2
     #endif
     
     // <q> NRF_SDH_BLE_SERVICE_CHANGED  - Include the Service Changed characteristic in the Attribute Table.

    Best regards,

    Vidar

  • Hi Vidar,
    thanks for your answer.
    I was able to reach my goal thanks to your help.
    I was able to add the characteristic but I can't read or write the characteristic. How do I enable reading and writing of the characteristic?
    I used the ble_gatts_char_md_t structure with the sd_ble_gatts_characteristic_add function. See code below:

        uint32_t authentications_service_key_a_add(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
        {
            uint32_t            err_code;
            ble_gatts_char_md_t char_md;
            ble_gatts_attr_t    attr_char_value;
            ble_uuid_t          ble_uuid;
            ble_gatts_attr_md_t attr_md;
    
            memset(&char_md, 0, sizeof(char_md));
    
            char_md.char_props.read   = 1;
            char_md.char_props.write  = 0;
            char_md.char_props.notify = 0; 
            char_md.p_char_user_desc  = NULL;
            char_md.p_char_pf         = NULL;
            char_md.p_user_desc_md    = NULL;
            char_md.p_cccd_md         = NULL; 
            char_md.p_sccd_md         = NULL;
    		
            ble_uuid.type = p_cus->uuid_type;
            ble_uuid.uuid = KEY_A_CHARACTERISTIC_UUID;
    
            memset(&attr_md, 0, sizeof(attr_md));
    
            attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
            attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
            attr_md.vloc       = BLE_GATTS_VLOC_STACK;
            attr_md.rd_auth    = 0;
            attr_md.wr_auth    = 0;
            attr_md.vlen       = 0;
    
            memset(&attr_char_value, 0, sizeof(attr_char_value));
    
            attr_char_value.p_uuid    = &ble_uuid;
            attr_char_value.p_attr_md = &attr_md;
            attr_char_value.init_len  = sizeof(uint16_t);
            attr_char_value.init_offs = 0;
            attr_char_value.max_len   = sizeof(uint16_t);
    
            err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                       &attr_char_value,
                                                       &p_cus->key_a_handles);
    
            return err_code;
        }

    The characteristic_add function does not have a parameter of type ble_gatts_char_md_t. How can I do?
    What is the difference between the characteristic_add function and the sd_ble_gatts_characteristic_add function?
    Thanks so much.

  • Hi,

    Excellent! characteristic_add() is a helper function to simplify the process of adding new characteristics. If you look at the implementation of it, you can see that it calls the same Softdevice function in the end.

    Regardless of which function you use, you have to set the .write_wo_resp  or .write proprty to '1' to enable writes to the characteristic. Here it's how it's enabled for the NUS RX characteristic for reference:

Reply
  • Hi,

    Excellent! characteristic_add() is a helper function to simplify the process of adding new characteristics. If you look at the implementation of it, you can see that it calls the same Softdevice function in the end.

    Regardless of which function you use, you have to set the .write_wo_resp  or .write proprty to '1' to enable writes to the characteristic. Here it's how it's enabled for the NUS RX characteristic for reference:

Children
Related