nRF53: how to set the BLE Public MAC Address from the APP core?

Hi,

We have an application running on the nRF53, and would like to change the BLE MAC address from the default Random Static Address, to a Public Address with a valid Vendor OUI.

I tried to use bt_id_create(), but that seems to work only for Random Static Addresses (i.e., with the first 2 MSBits of the MAC Address set to 1). Trying to set an address with the actual Vendor OUI results in: "Only static random identity address supported"

I also tried to use bt_ctlr_set_public_addr(), but that function doesn't appear to be linked into the APP core image.

Is there a straightforward way to set the Public MAC Address from the APP Core, in a way similar to calling bt_id_create()? I found some tickets on DevZone implying that it can be done from the NET Core by sending a message from the APP Core, but that seems overly complicated and they were older tickets (and we're not using the SoftDevice).  Thanks!

Parents
  • Hi,

    You can set the address on the app side as well, using bt_id_create(). You can see an example of that in this exercise (here the address is not public, but the method is the same regardless of address type). 

  • Hi Einar - the problem with using bt_id_create() is that it only works with Random Static Addresses - i.e., ones where the 2 MSBit's of the first octet are set to 1.  A Public MAC Address has the 2 MSBit's set to 0.

    i.e., this works:

    bt_addr_le_from_str("FF:EE:DD:CC:BB:AA", "random", &addr);
    bt_id_create(&addr, NULL);

    but this will result in the error "Only static random identity address supported":

    bt_addr_le_from_str("3F:EE:DD:CC:BB:AA", "public", &addr);
    bt_id_create(&addr, NULL);

  • Hi,

    Yes, you are right. I did not notice this. Honestly public address is not much used, but you can do this via another approach described here and here. This is a modified beacon sample from SDK 2.9 which does it:

    /* main.c - Application main entry point */
    
    /*
     * Copyright (c) 2015-2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/util.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/hci.h>
    
    #include <zephyr/settings/settings.h>
    #include <sdc_hci_vs.h>
    
    
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    
    /*
     * Set Advertisement data. Based on the Eddystone specification:
     * https://github.com/google/eddystone/blob/master/protocol-specification.md
     * https://github.com/google/eddystone/tree/master/eddystone-url
     */
    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
    	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),
    	BT_DATA_BYTES(BT_DATA_SVC_DATA16,
    		      0xaa, 0xfe, /* Eddystone UUID */
    		      0x10, /* Eddystone-URL frame type */
    		      0x00, /* Calibrated Tx power at 0m */
    		      0x00, /* URL Scheme Prefix http://www. */
    		      'z', 'e', 'p', 'h', 'y', 'r',
    		      'p', 'r', 'o', 'j', 'e', 'c', 't',
    		      0x08) /* .org */
    };
    
    /* Set Scan Response data */
    static const struct bt_data sd[] = {
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static int set_bd_addr(void)
    {
    	int err = 0;
    	struct net_buf *buf;
    	sdc_hci_cmd_vs_zephyr_write_bd_addr_t *cmd_params;
    
    	buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_ZEPHYR_WRITE_BD_ADDR ,
    				sizeof(*cmd_params));
    	if (!buf) {
    		printk("Could not allocate command buffer\n");
    		return -ENOMEM;
    	}
    
    	cmd_params = net_buf_add(buf, sizeof(*cmd_params));
    
    	cmd_params->bd_addr[0]= 0xCC;
    	cmd_params->bd_addr[1]= 0xCC;
    	cmd_params->bd_addr[2]= 0xCC;
    	cmd_params->bd_addr[3]= 0xCC;
    	cmd_params->bd_addr[4]= 0xCC;
    	cmd_params->bd_addr[5]= 0xCC;
    
    
    
        printk("bt_hci_cmd_send_sync \n");
    
    	err = bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_ZEPHYR_WRITE_BD_ADDR, buf, NULL);
    	printk("err: %d \n",err);
    	if (err) {
    		printk("err: %d \n",err);
    		return err;
    	}
    
    	printk("Successfully set bd addr \n");
    
    	return 0;
    }
    
    static void bt_ready(int err)
    {
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	bt_addr_le_t addr = {0};
    	size_t count = 1;
    
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	set_bd_addr();
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
        		settings_load();
    	}
    
    	/* Start advertising */
    	err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad, ARRAY_SIZE(ad),
    			      sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to start (err %d)\n", err);
    		return;
    	}
    
    
    	/* For connectable advertising you would use
    	 * bt_le_oob_get_local().  For non-connectable non-identity
    	 * advertising an non-resolvable private address is used;
    	 * there is no API to retrieve that.
    	 */
    
    	bt_id_get(&addr, &count);
    	bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));
    
    	printk("Beacon started, advertising as %s\n", addr_s);
    }
    
    int main(void)
    {
    	int err;
    
    	printk("Starting Beacon Demo\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(bt_ready);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    	}
    	return 0;
    }
    

    You also need some additional configs in case settings was not used before:

    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y

Reply
  • Hi,

    Yes, you are right. I did not notice this. Honestly public address is not much used, but you can do this via another approach described here and here. This is a modified beacon sample from SDK 2.9 which does it:

    /* main.c - Application main entry point */
    
    /*
     * Copyright (c) 2015-2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/util.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/hci.h>
    
    #include <zephyr/settings/settings.h>
    #include <sdc_hci_vs.h>
    
    
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    
    /*
     * Set Advertisement data. Based on the Eddystone specification:
     * https://github.com/google/eddystone/blob/master/protocol-specification.md
     * https://github.com/google/eddystone/tree/master/eddystone-url
     */
    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
    	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),
    	BT_DATA_BYTES(BT_DATA_SVC_DATA16,
    		      0xaa, 0xfe, /* Eddystone UUID */
    		      0x10, /* Eddystone-URL frame type */
    		      0x00, /* Calibrated Tx power at 0m */
    		      0x00, /* URL Scheme Prefix http://www. */
    		      'z', 'e', 'p', 'h', 'y', 'r',
    		      'p', 'r', 'o', 'j', 'e', 'c', 't',
    		      0x08) /* .org */
    };
    
    /* Set Scan Response data */
    static const struct bt_data sd[] = {
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static int set_bd_addr(void)
    {
    	int err = 0;
    	struct net_buf *buf;
    	sdc_hci_cmd_vs_zephyr_write_bd_addr_t *cmd_params;
    
    	buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_ZEPHYR_WRITE_BD_ADDR ,
    				sizeof(*cmd_params));
    	if (!buf) {
    		printk("Could not allocate command buffer\n");
    		return -ENOMEM;
    	}
    
    	cmd_params = net_buf_add(buf, sizeof(*cmd_params));
    
    	cmd_params->bd_addr[0]= 0xCC;
    	cmd_params->bd_addr[1]= 0xCC;
    	cmd_params->bd_addr[2]= 0xCC;
    	cmd_params->bd_addr[3]= 0xCC;
    	cmd_params->bd_addr[4]= 0xCC;
    	cmd_params->bd_addr[5]= 0xCC;
    
    
    
        printk("bt_hci_cmd_send_sync \n");
    
    	err = bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_ZEPHYR_WRITE_BD_ADDR, buf, NULL);
    	printk("err: %d \n",err);
    	if (err) {
    		printk("err: %d \n",err);
    		return err;
    	}
    
    	printk("Successfully set bd addr \n");
    
    	return 0;
    }
    
    static void bt_ready(int err)
    {
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	bt_addr_le_t addr = {0};
    	size_t count = 1;
    
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	set_bd_addr();
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
        		settings_load();
    	}
    
    	/* Start advertising */
    	err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad, ARRAY_SIZE(ad),
    			      sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to start (err %d)\n", err);
    		return;
    	}
    
    
    	/* For connectable advertising you would use
    	 * bt_le_oob_get_local().  For non-connectable non-identity
    	 * advertising an non-resolvable private address is used;
    	 * there is no API to retrieve that.
    	 */
    
    	bt_id_get(&addr, &count);
    	bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));
    
    	printk("Beacon started, advertising as %s\n", addr_s);
    }
    
    int main(void)
    {
    	int err;
    
    	printk("Starting Beacon Demo\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(bt_ready);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    	}
    	return 0;
    }
    

    You also need some additional configs in case settings was not used before:

    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y

Children
Related