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

ble_advdata_encode and 128-bit UUIDS

SDK 15.3.0, code is based on examples\ble_central_and_peripheral\experimental\ble_app_att_mtu_throughput.

After getting the project to work with nRF Connect on the desktop and Android, we are now trying to get it to work with nRF Connect on iOS13+.

Per the Apple Accessory development guide, it is required/expected/recommended to send the UUID in the advertising packet.

For this project/product, it would be a unique 128-bit vendor-specific UUID.

1. This works:

static void advertising_data_set(void)
{
    ret_code_t ret;
    ble_uuid_t primary_uuid =
    {
      .type = BLE_UUID_TYPE_BLE,  // BLE_UUID_TYPE_VENDOR_BEGIN,
      .uuid = MY_SERVICE_UUID,
    };

    ble_gap_adv_params_t const adv_params =
    {
        .properties    =
        {
          .type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED,
        },
        .p_peer_addr   = NULL,
        .filter_policy = BLE_GAP_ADV_FP_ANY,
        .interval      = ADV_INTERVAL,
        .duration      = 0,

        /* BLE5 includes the 2Mb/sec PHY, but most mobile devices won't have it.
         * Must be changed to connect in long range. (BLE_GAP_PHY_CODED) */
        .primary_phy   = BLE_GAP_PHY_1MBPS,
        .secondary_phy = BLE_GAP_PHY_1MBPS,
    };

    ble_advdata_t const adv_data =
    {
        .name_type          = BLE_ADVDATA_FULL_NAME,
        .flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE,
        .include_appearance = false,
        .uuids_more_available =
        {
          .uuid_cnt = 1,
          .p_uuids = &primary_uuid,
        },
    };

    ret = ble_advdata_encode(&adv_data, m_adv_data.adv_data.p_data,
                             &m_adv_data.adv_data.len);
    if(ret != NRF_SUCCESS)
    {
        NRF_LOG_ERROR("advertising_data_set: "
                      "ble_advdata_encode fails: %d (%d)", ret, dope);
        sys_err = SYSERR_BLE_ADVDATA_ENCODE_ADV_SET;
    }

    ret = sd_ble_gap_adv_set_configure(&m_adv_handle,
                                       &m_adv_data, &adv_params);
    if(ret != NRF_SUCCESS)
    {
        NRF_LOG_ERROR("advertising_data_set: "
                      "sd_ble_gap_adv_set_configure fails: %d", ret);
        sys_err = SYSERR_BLE_ADVDATA_CONFIG_ADV_SET;
    }
}

but it isn't what I want.  It advertises the 16-bit segment of the larger UUID (that is, "MY_SERVICE_UUID" is bytes 12 and 13 of "SERVICE_UUID_BASE").  It is my understanding that the use of BLE_UUID_TYPE_BLE is for assigned UUIDs; that is, "Bluetooth SIG UUID (16-bit)", not vendor-unique.

I think I want the BLE_UUID_TYPE_VENDOR_BEGIN type for the ble_uuid_t variable.  According to the SDK documentation, this is "Vendor UUID types start at this index (128-bit)".  This sounds closer to what I want.

The uuid element of the ble_uuid_t type is a uint16_t, "16-bit UUID value or octets 12-13 of 128-bit UUID".  Okay, I'm guessing that if the type is BLE_UUID_TYPE_BLE, then uuid is the 16-bit SIG-assigned UUID.  Not much uncertainty there.  This would then imply that for type BLE_UUID_TYPE_VENDOR_BEGIN, uuid is bytes 12-13 of a custom 128-bit UUID.

1. What does "start at this index" mean?

2. How do I supply the rest of the 128-bit UUID?  Does the SoftDevice obtain this from the service UUID that was already registered with sd_ble_uuid_vs_add()?  Or is uuid actually supposed to be an index into some array where the 128-bit UUID resides?

3. When type is set to BLE_UUID_TYPE_VENDOR_BEGIN, ble_advdata_encode() throws a 2, error is NRF_ERROR_INVALID_PARAM.  I've tracked this down to the call to sd_ble_uuid_encode() in ble_advdata.c.  Hard for me to believe that it's complaining about the value of type itself, when it's set to a legal value.  Or is it the value of uuid when type is set to BLE_UUID_TYPE_VENDOR_BEGIN (that is, uuid really is an index into some array somewhere, and bytes 12 and 13 form an illegal index)?

Parents
  • Hello,

    I wouldn't recommend using the ble_app_att_mtu_throughput as a starting point for your application. The reason for this is that this example is a bit complex, and really intended only to test throughput. I suggest you look at how e.g. the ble_app_uart example includes the UUID in it's advertisement. 

    I know that it only takes BLE_UUID_NUS_SERVICE (0x0001) in advertising_init(), but as long as the service is initialized, there is some softdevice magic that includes the full 128 bit UUID. You can verify this by changing a byte in the UUID, and see that the advertisement changes as well.

    Best regards,

    Edvin

Reply
  • Hello,

    I wouldn't recommend using the ble_app_att_mtu_throughput as a starting point for your application. The reason for this is that this example is a bit complex, and really intended only to test throughput. I suggest you look at how e.g. the ble_app_uart example includes the UUID in it's advertisement. 

    I know that it only takes BLE_UUID_NUS_SERVICE (0x0001) in advertising_init(), but as long as the service is initialized, there is some softdevice magic that includes the full 128 bit UUID. You can verify this by changing a byte in the UUID, and see that the advertisement changes as well.

    Best regards,

    Edvin

Children
  • Yes, well, I used the throughput example as a baseline on the advice from another Nordic engineer in view of our concern about throughput.  There's actually not much left of the Central capability left in our Peripheral-only program.  I notice that in the UART example, advertising setup is done through the Advertising Module rather than the ble_advdata_encode() and sd_ble_gap_adv_set_configure() API.  This is also true of the DFU service (which is included in our custom bootloader) and is presumably Apple-friendly.  Is Nordic recommending the use of the Advertising Module over the previous SD calls?  (I'm sure the Advertising Module just wraps the SD calls in an easier-to-use framework.)

  • Sorry for the late reply David, Edvin became a new father and is on leave. I am responsible for this thread now.

    David Ormand said:
    Is Nordic recommending the use of the Advertising Module over the previous SD calls?  (I'm sure the Advertising Module just wraps the SD calls in an easier-to-use framework.)

    Depends on your experience with Nordic solutions and also depends on your requirement. Advertising Module is a library and is more heavy weight than using the SD calls directly. A new user would find advertising module easier to use as it handles most of the pre and post processing functionality. But if your application does need the pre and post processing of an advertising packet to be more specific, then you can use the SD calls directly.

Related