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

Advertising Bluetooth LE 128-bit vendor specific UUID

I am wondering what is the logic and magic behind using sdk API's to advertise vendor specific 128-bit service UUIDs. In the "Nordic UART Service" example (nus, SDK12.2.0) there is:

static ble_uuid_t                       m_adv_uuids[] = {{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};  /**< Universally unique service identifier. */

But the BLE_UUID_NUS_SERVICE is not the 128-bit UUID but just 16-bit:

#define BLE_UUID_NUS_SERVICE 0x0001                      /**< The UUID of the Nordic UART Service. */

Digging the other source code files the true 128-bit UID can be found from ble_nus.c:

#define NUS_BASE_UUID                  {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */

So, ble_advertising_init() gets only the 16-bit "UUID" but is still able to build advertising data with the true 128-bit UUID. This is very strange. I tried to examine internal implementations and it looks like the 128-bit UUID is send to the Soft Device before calling ble_advertising_init. Is it so, could somebody please explain the underlying logic? What if I have several vendor specific 128-bit UUIDs, how do the advertising data build functions know which one must be set into the advertising data, if only 16-bit "UUID" is given?

  • It is a bit hard to see the logic.

    The base UUID is added to the SoftDevice inside ble_nus_init():

    /**@snippet [Adding proprietary Service to S110 SoftDevice] */
    // Add a custom base UUID.
    err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
    VERIFY_SUCCESS(err_code);
    

    The returned type is referenced when telling the advertising module which UUID to advertise.

  • Thanks, I did not note it goes that way. Very compilacated system, it makes difficult to build API that would allow easy/dynamic addition of new UUID's. I mean, I am splitting the mesh in main.c into logical pieces, so I would not need to copy-paste that much code for every new customer project.

    This UUID implementation is challenging because there is now that mentioned "hidden" dependency between e.g. the ble_nus.c and the main.c, where advertising data is constructed. I would like to have "BluetoothUartService.c" and there a BluetoothUartService_init() function that just adds all necessary things like the event handler and advertised UUID into the system.

  • Maybe you can remove the "hidden" dependency by adding the base UUID in main, and then give the type as an argument to ble_nus_init()?

  • Maybe, but I would not like to modify any of the sdk codes, to enable easy updates from Nordic. But it looks like there is a solution. I can make my Uart init() function to call an "addAdvertisingServiceUUID()" function (in main.c) with the p_nus->uuid_type as an argument, so the main.c dependency to the Uart service (nus) can be removed completely. The opposite dependecy from nus --> main is acceptable, since it still allows me to leave out nus when not needed, without needing to modify ANY of the code (as opposite to your examples, where you need to patch the code from several places).

    Actually, my main.c is now BluetoothBase_nRF51.c. I am trying to make an additional easier abstraction layer between the application and the Nordic's hardware and sdk. Hard work.

Related