how to obtain a fixed BLE MAC address when CONFIG_BT_PRIVACY is defined

Hi,

I am using nrf52840 to develop a product. I use NCS sdk v2.5.0. 

I developed a project based on the [Bluetooth: Central HIDS] example in the NCS SDK. This example enables the CONFIG_BT_PRIVACY macro definition, which causes the BLE advertising MAC address to be a new random address every time the device is powered on.

I want the BLE advertise to use a fixed MAC address each time without affecting the HID functionality.

Is this possible?

Thanks !

  • It is not that simple to do that. 

    You can use bt_id_create before enabling the bluetooth (bt_enable) but it will limit the ability to create random address later. Please look at the documentation for bt_id_create

  • Thanks for your reply.

    I have already tried this, but it didn't work. The broadcast address is still random every time the device is powered on. Additionally, it affects the HIDS functionality.
    Here is some of my code:

    prj.conf

    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable internal LFCLK control
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_250PPM=y
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
    
    # Add HIDS config
    CONFIG_BT_CENTRAL=y
    CONFIG_BT_SMP=y
    CONFIG_BT_HOGP=y
    CONFIG_BT_SCAN=y
    CONFIG_BT_SCAN_FILTER_ENABLE=y
    CONFIG_BT_SCAN_UUID_CNT=1
    CONFIG_BT_PRIVACY=y
    
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_GATT_DM=y
    CONFIG_BT_USER_PHY_UPDATE=y
    
    # Connection parameters
    #CONFIG_BT_PERIPHERAL_PREF_MIN_INT=24 #(1.25ms units -> 30ms)
    #CONFIG_BT_PERIPHERAL_PREF_MAX_INT=40 #(1.25ms units -> 50ms)
    # Peripheral latency:
    #CONFIG_BT_PERIPHERAL_PREF_LATENCY=0  #(Unit is given in number of connection intervals)
    # Supervision timeout:
    #CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=42 #(10ms units -> 420ms)
    
    # Enable the UART driver
    CONFIG_UART_ASYNC_API=y
    CONFIG_NRFX_UARTE0=y
    CONFIG_NRFX_UARTE1=y
    CONFIG_SERIAL=y
    CONFIG_BT_NUS_UART_RX_WAIT_TIME=20000
    CONFIG_BT_NUS_UART_BUFFER_SIZE=256
    CONFIG_NRFX_TIMER1=y
    CONFIG_UART_1_NRF_HW_ASYNC=y
    CONFIG_UART_1_NRF_HW_ASYNC_TIMER=1
    
    CONFIG_GPIO=y
    CONFIG_I2C=y
    CONFIG_ADC=y
    
    # SPI LCD interface
    CONFIG_SPI=y
    
    # Make sure printk is printing to the UART console
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y
    
    # Increase the size of the heap memory pool to 16KB
    CONFIG_HEAP_MEM_POOL_SIZE=16384
    
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DEVICE_NAME="Handheld_A2"
    CONFIG_BT_DEVICE_APPEARANCE=833
    CONFIG_BT_MAX_CONN=2
    CONFIG_BT_MAX_PAIRED=2
    
    # Enable the NUS service
    CONFIG_BT_NUS=y
    #CONFIG_BT_NUS_UART_ASYNC_ADAPTER=y
    #CONFIG_UART_INTERRUPT_DRIVEN=y
    
    # Set MTU size and radio packet length to max
    CONFIG_BT_USER_DATA_LEN_UPDATE=y
    CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
    #CONFIG_BT_L2CAP_TX_BUF_COUNT=5
    CONFIG_BT_BUF_ACL_RX_SIZE=251
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    CONFIG_BT_L2CAP_TX_MTU=247
    
    # Enable bonding
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    
    # Enable DK LED and Buttons library
    CONFIG_DK_LIBRARY=y
    
    # This example requires more stack
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    # Config logger
    CONFIG_LOG=y
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    CONFIG_LOG_PRINTK=y
    CONFIG_LOG_BUFFER_SIZE=4096
    
    # Enable process float (double) numbers
    CONFIG_FPU=y
    
    CONFIG_RING_BUFFER=y
    CONFIG_ASSERT=y
    
    #Enable MCUBOOT bootloader build in the application
    CONFIG_BOOTLOADER_MCUBOOT=y
    #Enable BLE OTA, include MCUMGR and the dependencies in the build
    CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y
    CONFIG_NORDIC_QSPI_NOR=n
    #CONFIG_DISABLE_FLASH_PATCH=y
    
    # Project select
    CONFIG_PROJECT_A2=n
    CONFIG_PROJECT_A5=y
    CONFIG_PROJECT_A5_N7101=n

    main.c

    static int ficr_static_addr_set(void)
    {
    	int ret;
    	static bt_addr_le_t addr;
    	char buf[BT_ADDR_LE_STR_LEN] = {0};
    
    	if ((NRF_FICR->DEVICEID[0] != UINT32_MAX) ||
    	    ((NRF_FICR->DEVICEID[1] & UINT16_MAX) != UINT16_MAX)) {
    		/* Put the device ID from FICR into address */
    		sys_put_le32(NRF_FICR->DEVICEID[0], &addr.a.val[0]);
    		sys_put_le16(NRF_FICR->DEVICEID[1], &addr.a.val[4]);
    
    		/* The FICR value is a just a random number, with no knowledge
    		 * of the Bluetooth Specification requirements for random
    		 * static addresses.
    		 */
    		BT_ADDR_SET_STATIC(&addr.a);
    		addr.type = BT_ADDR_LE_RANDOM;
    
    		bt_addr_le_to_str(&addr, buf, ARRAY_SIZE(buf));
    		LOG_INF("Get FICR MAC addr is: %s", buf);
    
    #if 1
    		// Define a custom IRK
    		uint8_t custom_irk[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    								0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    
    		ret = bt_id_create(&addr, custom_irk);
    		if (ret < 0) {
    			LOG_ERR("Failed to create ID %d", ret);
    			return ret;
    		}
    #endif
    
    		return 0;
    	}
    
    	/* If no address can be created (e.g. based on
    	 * FICR), then a random address is created
    	 */
    	LOG_WRN("Unable to read from FICR");
    
    	return 0;
    }
    
    int main(void)
    {
        ......
    	if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			LOG_ERR("Failed to register authorization callbacks.\n");
    			return 0;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			LOG_ERR("Failed to register authorization info callbacks.\n");
    			return 0;
    		}
    	}
    
    	ficr_static_addr_set();
    
    	err = bt_enable(NULL);
    	if (err) {
    		error();
    	}
    
    	LOG_INF("Bluetooth initialized");
    
    	k_sem_give(&ble_init_ok);
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	err = bt_nus_init(&nus_cb);
    	if (err) {
    		LOG_ERR("Failed to initialize UART service (err: %d)", err);
    		return 0;
    	}
    
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd,
    			      ARRAY_SIZE(sd));
    	if (err) {
    		LOG_ERR("Advertising failed to start (err %d)", err);
    		return 0;
    	}
    
    	hids_service_init();
    	......

    error log:

    00> *** Booting nRF Connect SDK v2.5.0 ***
    00> [00:00:00.000,976] <inf> main: Handheld_A5 app version: v1.1, compliled time: Jan 14 2025 22:35:45
    00> [00:00:00.001,007] <inf> main: Clock has started
    00> 
    00> [00:00:00.267,028] <inf> cw2013: CW2013_ID: (it should be 0x73) 0x73
    00> [00:00:00.274,139] <inf> fs_nvs: 2 Sectors of 4096 bytes
    00> [00:00:00.274,139] <inf> fs_nvs: alloc wra: 0, f50
    00> [00:00:00.274,169] <inf> fs_nvs: data wra: 0, 1bc
    00> [00:00:00.274,658] <inf> user_settings: read user settings ok
    00> [00:00:00.274,719] <inf> user_settings: user settings:
    00>                                         02 00 48 61 6e 64 68 65  6c 64 5f 41 35 00 00 00 |..Handhe ld_A5...
    00>                                         00 00 00 00 00 00 00                             |.......          
    00> [00:00:00.274,993] <inf> main: Get FICR MAC addr is: DD:98:BD:2E:FB:9F (random)
    00> [00:00:00.275,177] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
    00>                 
    
    //when I power on a HID device
    
    00> Hids: Filters matched on UUID 0x1812.
    00> Address: FF:FF:10:AC:2C:17 (public) connectable: yes
    00> Hids: Connected: FF:FF:10:AC:2C:17 (public)
    00> Hids: Security failed: FF:FF:10:AC:2C:17 (public) level 1 err 2
    00> Hids: The discovery procedure succeeded
    00> [00:00:15.025,543] <err> hogp: HID information read error
    00> ERROR: HIDS client preparation failed!
    00> Hids: Security failed: FF:FF:10:AC:2C:17 (public) level 1 err 2
    00> Hids: The service could not be found during the discovery
    00> Hids: Disconnected: FF:FF:10:AC:2C:17 (public) (reason 8)
    00> Hids: client active - releasing
    

  • I have looked into how the host and controller behave with CONFIG_BT_PRIVACY set to y and it seems like you cannot directly use a static address for all advertisements with this setting enabled. The whole point of privacy is to use changing addresses and it does not seem like we have a simple workaround without changing a lot of underlying BLE non application layer files and we might then be in violation of the spec.

  • Okay, thank you. we'll have to think of another way.

    Additionally, may I ask if it is necessary to enable the CONFIG_BT_PRIVACY macro definition when using HIDS? Is it possible to support HIDS functionality without enabling this macro definition?

  •  No, HIDS does not technically needs the privacy option to be enabled. I have not tried it myself though. Without the LE secure connections when you are using bonding in the sample you might need to enable some configs to make sure the bonding infrastructure is working

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

Related