Accelerated Address Resolver (AAR) not working with known data

Hello Everyone,

I am currently building a presence detection application using the nRF52840. I want to be able to detect both Android and Apple devices. Currently the application is working for Android by detecting BLE iBeacons and comparing the UUID to a known list.

However, since Apple devices do not support iBeacons and use random resolvable addresses a different approach was needed. I have come up with the following solution:

If a packet with address type BT_ADDR_LE_RANDOM_ID or BT_ADDR_LE_RANDOM is found then i want to resolve the address using the Accelerated Address Resolver (AAR) peripheral.
I already obtained the requierd IRKs for this and they are stored in a uint8_t irk[16]. However when i run the AAR with one of addresses it never matches one of the IRKs, altough i'm sure that both the MAC address and the IRK match.
I even tried calling the the resolve function manually in the startup function with known data, but this doesn't work either. Maybe you can help out and spot the error?


Please see my code below:

#include <zephyr/types.h>
#include <stddef.h>
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/gpio.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/sys/byteorder.h>

#include <hal/nrf_aar.h>
#include <hal/nrf_nvmc.h>

#define N 2

static void start_scan(void);

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static const struct gpio_dt_spec led_green = GPIO_DT_SPEC_GET(DT_ALIAS(led1_green), gpios);
static const struct gpio_dt_spec led_red = GPIO_DT_SPEC_GET(DT_ALIAS(led1_red), gpios);
static const struct gpio_dt_spec led_blue = GPIO_DT_SPEC_GET(DT_ALIAS(led1_blue), gpios);

struct scan_result
{
	bt_addr_le_t *addr;
	int8_t rssi;
};


uint8_t uuid[18] = {00}; // All privacy sensitive data is zero, but for testing i used real values


static const uint8_t irks[3][16] = {
	{00},
	{00},
	{00},
};

uint8_t ipad[6] = {0};

uint8_t scratch_data[16];


void resolve_address_init()
{
	nrf_aar_enable(NRF_AAR_BASE);
	nrf_aar_scratch_pointer_set(NRF_AAR_BASE, &scratch_data);

	// Set up IRK pointer and number
	nrf_aar_irk_pointer_set(NRF_AAR_BASE, &irks);
	nrf_aar_irk_number_set(NRF_AAR_BASE, 3);
}

bool resolve_address(uint8_t const *addr_ptr)
{
	// Set up address pointer
	nrf_aar_addr_pointer_set(NRF_AAR_BASE, addr_ptr);

	// Start address resolution procedure
	nrf_aar_task_trigger(NRF_AAR_BASE, NRF_AAR_TASK_START);

	// Wait for resolution result
	while (!nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_END))
		;

	// Check if address was resolved
	if (nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_RESOLVED))
	{
		// Get index of matching IRK
		uint8_t irk_index = nrf_aar_resolution_status_get(NRF_AAR);

		// Clear RESOLVED event
		nrf_aar_event_clear(NRF_AAR_BASE, NRF_AAR_EVENT_RESOLVED);
		return true;
	}
	else if (nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_NOTRESOLVED))
	{
		// Clear NOTRESOLVED event
		nrf_aar_event_clear(NRF_AAR_BASE, NRF_AAR_EVENT_NOTRESOLVED);
		return false;
	}
}

static bool eir_found(struct bt_data *data, void *user_data)
{
	// Check the datat type
	if (data->type != BT_DATA_MANUFACTURER_DATA)
	{
		return true;
	}

	struct scan_result *res = user_data;
	bt_addr_le_t *addr = res->addr;

	// Random address type, resolution needed
	if (addr->type == BT_ADDR_LE_RANDOM_ID || addr->type == BT_ADDR_LE_RANDOM)
	{

		nrf_aar_addr_pointer_set(NRF_AAR_BASE, &addr->a.val);
		nrf_aar_task_trigger(NRF_AAR_BASE, NRF_AAR_TASK_START);

		// Wait for resolution result
		while (!nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_END))
			;

		// Check if address was resolved
		if (nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_RESOLVED))
		{
			// Get index of matching IRK
			uint8_t irk_index = nrf_aar_resolution_status_get(NRF_AAR_BASE);
			// Clear RESOLVED event
			nrf_aar_event_clear(NRF_AAR_BASE, NRF_AAR_EVENT_RESOLVED);
			gpio_pin_set_dt(&led_red, 1);
			return false;
		}
		else if (nrf_aar_event_check(NRF_AAR_BASE, NRF_AAR_EVENT_NOTRESOLVED))
		{
			// Clear NOTRESOLVED event
			nrf_aar_event_clear(NRF_AAR_BASE, NRF_AAR_EVENT_NOTRESOLVED);
			return true;
		}
	}

	// Compare received data with known iBeacon UUID
	if (memcmp(&data->data[4], &uuid, sizeof(uuid) - 4) == 0)
	{
		gpio_pin_set_dt(&led, 1);
		k_msleep(200);
		gpio_pin_set_dt(&led, 0);
		k_msleep(100);

		uint8_t rssi_1m = data->data[24];
		int16_t r = 0xFF00 + rssi_1m;

		if (res->rssi > r)
		{
			gpio_pin_set_dt(&led_blue, 1);
		}
		else
		{
			gpio_pin_set_dt(&led_blue, 0);
		}

		return false;
	}

	return true;
}

static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
{
	if (type == BT_GAP_ADV_TYPE_ADV_SCAN_IND || type == BT_GAP_ADV_TYPE_ADV_IND)
	{
		struct scan_result res = {
			.addr = addr,
			.rssi = rssi,
		};

		bt_data_parse(ad, eir_found, &res);
	}
}

static void start_scan(void)
{
	int err;

	struct bt_le_scan_param scan_param = {
		.type = BT_LE_SCAN_TYPE_PASSIVE,
		.options = BT_LE_SCAN_OPT_NONE,
		.interval = BT_GAP_SCAN_FAST_INTERVAL,
		.window = BT_GAP_SCAN_FAST_WINDOW,
	};

	err = bt_le_scan_start(&scan_param, device_found);
	if (err)
	{
		printk("Scanning failed to start (err %d)\n", err);
		return;
	}

	printk("Scanning successfully started\n");
}

void main(void)
{
	int err;
	err = bt_enable(NULL);

	gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&led_blue, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&led_green, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&led_red, GPIO_OUTPUT_ACTIVE);

	gpio_pin_set_dt(&led, 0);
	gpio_pin_set_dt(&led_blue, 1);
	gpio_pin_set_dt(&led_green, 0);
	gpio_pin_set_dt(&led_red, 0);

	resolve_address_init();

	uint8_t addr_1[6] = {00};
	uint8_t addr_2[6] = {00};

	// Not working either
	if (resolve_address(addr_1) || resolve_address(addr_3))
	{
		gpio_pin_set_dt(&led_green, 1);
	}


	k_msleep(1000);
	gpio_pin_set_dt(&led_blue, 0);
	start_scan();
}

Parents Reply Children
  • Thank you very much for you response, i think i already understand the problem of my code. As stated in you answer, the AAR cannot be used separately as it is also used by the softdevice at the same time.

    However i do think that i have found another solution to my problem. I think a whitelist needs to be implemented in the start_scan function so only known devices are processed by my code. Now i have already found information on how to implement this whitelist with a list of known mac addresses, however i cannot find any information on how to add a array of hardcoded IRKs to the whitelist. Can you maybe provide some information on this?

    Thanks in advance!

Related