5. The Bluetooth® Device Address

Bluetooth® devices identify themselves using a 48-bit device address. This is commonly represented as a set of 12-hex digits and is often referred to as a BD address. These addresses are used in order to manage connections and keep track of BLE bondings.

_images/bd_android.jfif

Figure 12 12-hex digits as Bluetooth device address

iOS address hex

If you are using a Bluetooth® Explorer Tool on an iOS device then the BD address will not be displayed. If you don’t have access to an Android phone then try using the Bluetooth® Explorer Tool built into the Chrome browser, see Before You Get Started for details.

There are two types of BD addresses:
Public addresses:

They are registered with and purchased from the IEEE and contain an identifier of the entity who registered the address range (OUI). Public addresses remain static and unique for a given Bluetooth® device.

Non-public addresses:
  • No registration with the IEEE is required (and no payments to be made)

  • The first two bits of a non-public address are binary ones. In other words, the first hex digit of the address must be 0xC, 0xD, 0xE, or 0xF

  • The address can be device specific and remain constant over the life of a product

  • The address can change at some given interval - often to ensure some level of privacy

  • The address can be randomly generated at boot-up

Random addresses

Non-public addresses are often inaccurately labeled as Random. This term is misleading because, although these addresses can be generated randomly, they don’t have to be truly random.

SDK6 offers various methods for the assignment of the Bluetooth® Device Address:
  • If you are using a public address
    • A BD Address can be stored in a specific part of the OTP of the device during production. The SDK will automatically handle this. If you are using a module then this field has likely already been programmed

    • If there is no address stored in OTP, the SDK6 will assign the address provided in the file: …_config_advanced.h (previously mentioned these files in User configuration modules .The address is defined as CFG_NVDS_TAG_BD_ADDRESS modify this regarding target).

  • If you are using a non-public address
    • The SDK6 can manage generation of a random address at boot-up

    • The SDK6 can manage generation of a static random address which is unique to the device

    • The user can generate an address based on a custom scheme

In the following, we will explore the use of non-public addresses.

5.1. Non-public (Static BD Address)

We have already seen the result of using a public address which is how empty_peripheral_template was implemented initially. In the following we will explore options for generation of non-public addresses. First, we will allow the SDK6 to set a new random non-public address at every boot-up.

  • In user_config.h, change the definition of USER_CFG_ADDRESS_MODE to APP_CFG_ADDR_STATIC
    /*************************************************************************
    * Privacy Capabilities and address configuration of local device:
    * - APP_CFG_ADDR_PUB               No Privacy, Public BDA
    * - APP_CFG_ADDR_STATIC            No Privacy, Random Static BDA
    * - APP_CFG_HOST_PRIV_RPA          Host Privacy, RPA, Public Identity
    * - APP_CFG_HOST_PRIV_NRPA         Host Privacy, NRPA (non-connectable ONLY)
    * - APP_CFG_CNTL_PRIV_RPA_PUB      Controller Privacy, RPA or PUB, Public Identity
    * - APP_CFG_CNTL_PRIV_RPA_RAND     Controller Privacy, RPA, Public Identity
    *
    * Select only one option for privacy / addressing configuration.
    **************************************************************************
    */
    #define USER_CFG_ADDRESS_MODE       APP_CFG_ADDR_STATIC
    
  • Build the project (F7) and load it onto target (twice, press Ctrl+F5)

  • Use your BLE explorer app to verify that the BD address has changed and that it changes at every reboot.

5.2. Non-public (Static Unique BD Address)

In software development and certain applications, having a static and unique address for a device is often crucial. This would be an address that does not change after a reboot and that is globally unique to a specific device.

We can achieve this with a minor modification of the callback triggered when a non-public address is requested by the BLE stack:
  • Open the file user_callback_config.h and identify the callback app_on_generate_static_random_addr. This callback is currently re-routed to the function default_app_generate_static_random_addr

  • Change the re-routing to the function default_app_generate_unique_static_random_addr:
    - .app_on_generate_static_random_addr = default_app_generate_static_random_addr,
    + .app_on_generate_static_random_addr = default_app_generate_unique_static_random_addr,
    
  • Build the project (F7) and load it onto target (twice, press Ctrl+F5)

  • Use your BLE explorer app to verify that the BD address has changed and that it no longer changes at every reboot. If you have a second development kit, you will be able to observe that it advertises it’s own static unique address when running the same firmware

5.3. Non-public (User Generated BDAddress)

Occasionally, the user would like to assign a BD address based on some custom scheme. To handle this we will need to again re-route the callback that we just modified - this time to our own custom function.

This bonus re-routing will also show you how to redirect a callback to user space, a basic concept in SDK6:
  • Open the file user_callback_config.h and identify the callback app_on_generate_static_random_addr.

  • Re-route the callback to a, still to be implemented, custom function that we will call user_get_bdaddr:
    - .app_on_generate_static_random_addr = app_on_generate_static_random_addr,
    + .app_on_generate_static_random_addr = user_get_bdaddr,
    
  • In empty_peripheral_template.h, add a prototype for the custom function we are about to implement:
    void user_get_bdaddr( struct bd_addr* address );
    
  • We are now ready to implement the user generated BD address assignment. At the bottom of the user_empty_peripheral_template.c file, add the following function:
    void user_get_bdaddr( struct bd_addr *address )
    {
       struct bd_addr tempAddr = {0xEE,0xFF,0xC0,0xEE,0xFF,0xC0};
       memcpy(address, &tempAddr, 6);
    }
    
  • Build the project (F7) and load it onto target (twice, press Ctrl+F5)

  • Use your BLE explorer app to verify that the BD address has changed to C0:FF:EE:C0:FF:EE (notice that we provided the address in little-endian format).

Hint

Some explanation is required as this point. The callback sends us a pointer to a structure that our function can populate with a new BD address.We basically copy our custom address into this structure of 6 octets using memcpy.