This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Understanding Advertisement of multiple 128 bit custom UUID

Hi Everyone, 

I am using nRF52832 with SDK v14.2 and SD v5.0.0 on a custom chip. 

I want to advertise 2 custom UUID (DFU and NUS) and i wanted to know the correct way to do it. I understand that advertisement packet is 31 bytes and so is scan response packet. So, having one custom UUID on advertisement packet and the other on scan response packet makes sense since custom UUID is 16 bytes long. 

I did the same way and with nRF connect app i can see both services but when i sniffed for the packets being transmitted, i saw only one UUID there. 

I have attached the code here for a look. I have also attached sniffer trace for advertisement and scan response packet for your reference. Please advise why is it not advertising NUS UUID and still be able to detect by the nRF connect app when connected? 

.AdvertisingPacketScanResponsePacket

 

ret_code_t advertising_init(void)
{
    ret_code_t u32ErrCode = NRF_SUCCESS;
    ble_uuid_t astAdvUuids[] =                                          /**< Universally unique service identifier. */
    {
      {BLE_DFU_UUID, DFU_SERVICE_UUID_TYPE},
      {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}
    };
    ble_advertising_init_t stInit;

    memset(&stInit, 0, sizeof(stInit));

    stInit.advdata.name_type          = BLE_ADVDATA_FULL_NAME;
    stInit.advdata.include_appearance = false;
    stInit.advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

    stInit.advdata.uuids_complete.uuid_cnt = 1;
    stInit.advdata.uuids_complete.p_uuids = &astAdvUuids[0];

    stInit.srdata.uuids_more_available.uuid_cnt = 1;
    stInit.srdata.uuids_more_available.p_uuids  = &astAdvUuids[1];

    stInit.config.ble_adv_fast_enabled  = true;
    stInit.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
    stInit.config.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;

    stInit.evt_handler = on_adv_evt;

    u32ErrCode = ble_advertising_init(&m_advertising, &stInit);
    APP_ERROR_CHECK(u32ErrCode);

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);

    //nfc ble pair library init
    nrf_ble_pairing_init(&m_advertising);
    return u32ErrCode;
}

Thank you!

Parents
  • Hi,

    Looking at your code I see that you put one UUID in the advertising data (stInit.advdata) and one in the scan response data (stInit.srdata). Most scanners will do active scanning, which means that they will also ask for and read the scan response data. Therefore you see it in nRF Connect. You can see it in the sniffer as well, but then you need to look at the scan response packet to see the second UUID.

    Note that you can put both UUID's in the advertising packet instead, provided it can fit (depending on the length of the name, since you put the full name in the advertising packet).

  • Hi Einar, 

    I checked in the scan response packet as well (attached). I can only see one UUID being transmitted. (both having the same base UUID but different service ID- one being 0xFE59 and the other 0x0001)

  • I see. Have you added the vendor-specific base UUID with sd_ble_uuid_vs_add(), and was that used with the first call (if you made more calls to it)? If you add more, you should use the type populated in the second parameter int he call to sd_ble_uuid_vs_add(), so that you know it is correct, regardless of the order things happen in.

  • I am calling sd_ble_uuid_vs_add() at two places, one where i am initializing the NUS service and the other for buttonless DFU service init. I do not understand the part where you say to use the type populated in the second parameter. Could you please give me an example on how to? 

    Attaching both ble_nus and dfu_buttonless service init snippet here for your reference. 

    uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        uint32_t      err_code;
        ble_uuid_t    ble_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
        VERIFY_PARAM_NOT_NULL(p_nus_init);
    
        // Initialize the service structure.
        p_nus->conn_handle             = BLE_CONN_HANDLE_INVALID;
        p_nus->data_handler            = p_nus_init->data_handler;
        p_nus->is_notification_enabled = false;
    
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        // Add a custom base UUID.
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        // Add the service.
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                            &ble_uuid,
                                            &p_nus->service_handle);
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        VERIFY_SUCCESS(err_code);
    
        // Add the RX Characteristic.
        err_code = rx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        // Add the TX Characteristic.
        err_code = tx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }

    uint32_t ble_dfu_buttonless_init(const ble_dfu_buttonless_init_t * p_dfu_init)
    {
        uint32_t        err_code;
        ble_uuid_t      service_uuid;
        ble_uuid128_t   nordic_base_uuid = BLE_NORDIC_VENDOR_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_dfu_init);
    
        // Initialize the service structure.
        m_dfu.conn_handle                  = BLE_CONN_HANDLE_INVALID;
        m_dfu.evt_handler                  = p_dfu_init->evt_handler;
        m_dfu.is_waiting_for_reset         = false;
        m_dfu.is_ctrlpt_indication_enabled = false;
    
        err_code = ble_dfu_buttonless_backend_init(&m_dfu);
        VERIFY_SUCCESS(err_code);
        
        BLE_UUID_BLE_ASSIGN(service_uuid, BLE_DFU_SERVICE_UUID);
    
        // Add the DFU service declaration.
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                            &service_uuid,
                                            &(m_dfu.service_handle));
    
        VERIFY_SUCCESS(err_code);
    
        // Add vendor specific base UUID to use with the Buttonless DFU characteristic.
        err_code = sd_ble_uuid_vs_add(&nordic_base_uuid, &m_dfu.uuid_type);
        VERIFY_SUCCESS(err_code);
    
        // Add the Buttonless DFU Characteristic (with bonds/without bonds).
        err_code = ble_dfu_buttonless_char_add(&m_dfu);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }

  • Hi,

    I was not clear enough, but the point is that the UUID type depends on the order you call sd_ble_uuid_vs_add(). Therefore, the second parameter is a pointer to the UUID type as an output, and this is the type you should choose. Therefore, the first call to sd_ble_uuid_vs_add() will give you ID 2 (BLE_UUID_TYPE_VENDOR_BEGIN) and the second call will give you ID 3.

    This means that using a hardcoded value is problematic when adding more than one base UUID. You could always make sure to get it right, but then things will be messed up if you cange the order of which BLE service is initialized first. The alternative is to use the type provided when you call sd_ble_uuid_vs_add(). You can obtain that from m_nus (or whatever you named your NUS instance crated with BLE_NUS_DEF), like this: m_nus.uuid_type. But note that it will not be valid until after you have initialized the NUS service.

  • In a case where ID 2 and ID 3 are the same, i.e, both DFU_SERVICE_UUID_TYPE and NUS_SERVICE_UUID_TYPE is BLE_UUID_TYPE_VENDOR_BEGIN, what should happen then? In my case, i am doing the above signalling that both type are vendor specific. Now, when initializing the services, buttonless dfu first and then NUS, i am calling sd_ble_uuid_vs_add() where within each function base UUID for respective services are being assigned (from the code attached above). I thought this should be the right way to have mulitple VS UUID in the applicationQuestion

  • The name "type" in the SoftDevice and SDK is a bit misleading and makes this more difficult to understand, but the point is that the UUID type is really just a UUID ID, which indicates which of the added base UUID's you should use.

    SK said:
    In a case where ID 2 and ID 3 are the same, i.e, both DFU_SERVICE_UUID_TYPE and NUS_SERVICE_UUID_TYPE is BLE_UUID_TYPE_VENDOR_BEGIN, what should happen then?

    This shoult not happen, because it is incorrect. As you can read from the name of the define BLE_UUID_TYPE_VENDOR_BEGIN is the first (i.e. "begin") of the vendor types. Sinc you are using two different base UUID's, you need to add both. And then you get different types. The type is just an ID pointing to the base UUID, so since you are using separate base UUID's, they cannot possibly have the same UUID type.

    SK said:
    In my case, i am doing the above signalling that both type are vendor specific. Now, when initializing the services, buttonless dfu first and then NUS, i am calling sd_ble_uuid_vs_add() where within each function base UUID for respective services are being assigned (from the code attached above). I thought this should be the right way to have mulitple VS UUID in the application

    Yes. But you need to provide the correct UUID for both services when you populate your advertising packet, and as explained earlier in this post, you are not. You are using the same UUID base (since you use the same type), even though you have added both bases.

Reply
  • The name "type" in the SoftDevice and SDK is a bit misleading and makes this more difficult to understand, but the point is that the UUID type is really just a UUID ID, which indicates which of the added base UUID's you should use.

    SK said:
    In a case where ID 2 and ID 3 are the same, i.e, both DFU_SERVICE_UUID_TYPE and NUS_SERVICE_UUID_TYPE is BLE_UUID_TYPE_VENDOR_BEGIN, what should happen then?

    This shoult not happen, because it is incorrect. As you can read from the name of the define BLE_UUID_TYPE_VENDOR_BEGIN is the first (i.e. "begin") of the vendor types. Sinc you are using two different base UUID's, you need to add both. And then you get different types. The type is just an ID pointing to the base UUID, so since you are using separate base UUID's, they cannot possibly have the same UUID type.

    SK said:
    In my case, i am doing the above signalling that both type are vendor specific. Now, when initializing the services, buttonless dfu first and then NUS, i am calling sd_ble_uuid_vs_add() where within each function base UUID for respective services are being assigned (from the code attached above). I thought this should be the right way to have mulitple VS UUID in the application

    Yes. But you need to provide the correct UUID for both services when you populate your advertising packet, and as explained earlier in this post, you are not. You are using the same UUID base (since you use the same type), even though you have added both bases.

Children
  • It's confusing :(

    struct ble_uuid_t is defined as this: 

    /** @brief  Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */
    typedef struct
    {
      uint16_t    uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */
      uint8_t     type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */
    } ble_uuid_t;

    Now, type when referred to BLE_UUID_TYPES tells me to add this below:

    So type is uint8_t  whereas a 16 byte UUID is type ble_uuid128_t. Now inserting 16 bytes is not making sense and is giving me all sorts of warning messages. Do you want me to try pointing 16 bytes value to the 'type' field? 

    What i tried instead --> BLE_UUID_TYPE_VENDOR_BEGIN is 0x02. If my understanding is correct, VS types starts at this index, so i can very well take 0x03 (BLE_UUID_TYPE_VENDOR_BEGIN  + 1) as my next VS UUID, right? But when i  try to run, it is giving me invalid param error.

  • Another thing i noticed is that if we look into the buttonless DFU example, advertising packet only adds this service: 

    static ble_uuid_t m_adv_uuids[] = {{BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}};

    Why is the addition of device information service included rather than adding 128 bit VS UUID for the ble dfu? 

  • Hi,

    SK said:
    So type is uint8_t  whereas a 16 byte UUID is type ble_uuid128_t. Now inserting 16 bytes is not making sense and is giving me all sorts of warning messages. Do you want me to try pointing 16 bytes value to the 'type' field? 

    No. The type field is uint8_t, and it is just an ID/index/offset (call it what you like). Think of it as a reference tho the UUID base you have added. To brake it down:

    1. Add a UUID base with sd_ble_uuid_vs_add(). The second parameter to this function call is a pointer to a uint8_t, and this is an output. This means that the variable you pint to is populated with the number that is the UUID type (which is an index).
    2. Whenever you need to use this base UUID, such as when populating an advertising packet, you should refer to the UUID type, and since this is a reference to the base UUID, the SoftDevice (BLE stack) will make sure that the correct base UUID is used.
    SK said:
    so i can very well take 0x03 (BLE_UUID_TYPE_VENDOR_BEGIN  + 1) as my next VS UUID, right?

    Yes. The "proper" way would be to use the output, but this is orderly numbered so that the first call you make to sd_ble_uuid_vs_add() will give you a type 2, the second will give you type 3 and so on.

    SK said:
    But when i  try to run, it is giving me invalid param error.

    From where do you get invalid param? You should call sd_ble_uuid_vs_add() before you reference the UUID type, could that be the problem?

  • That is a decision made by those who made the example. There is no need to advertise all service UUID's, and the fact that the peripheral example supports DFU is probably not the most important thing about it. So I would say it makes sense, at least if it were a real application. The central can anyway find out that it supports DFU by doing a service discovery after it has connected.

  • Hi Einar, 

    From where do you get invalid param? You should call sd_ble_uuid_vs_add() before you reference the UUID type, could that be the problem?

    Right! This was the issue. Thanks a lot! 

    so i can very well take 0x03 (BLE_UUID_TYPE_VENDOR_BEGIN  + 1) as my next VS UUID, right?

    This works as well. I can see both UUID's now. One in ADV packet and other  in SCAN_RSP packet as expected.

Related