5340 many periodic advertiser sync error -5

the code, i can create one periodic adv, and i can get 45 aoa sample, but when i turn on another tag, i got err -5 from "err = bt_le_per_adv_sync_create(&(obj.sync_create_param), &(obj.sync));". the error like:

how to understand the " <wrn> bt_hci_core: opcode 0x2044 status 0x07". this is my main.c code like:

/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <stddef.h>
#include <errno.h>
#include <zephyr/kernel.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/direction.h>

#include <zephyr/drivers/gpio.h>

// LOG日志模块引入
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
#define LOG_D(format, ...) LOG_DBG(">(%d)" format, __LINE__, ##__VA_ARGS__)
#define LOG_W(format, ...) LOG_WRN(">(%d)" format, __LINE__, ##__VA_ARGS__)
#define LOG_E(format, ...) LOG_ERR(">(%d)" format, __LINE__, ##__VA_ARGS__)

#include "wk_list.h"
#include "uart.h"

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define PEER_NAME_LEN_MAX 30
/* BT Core 5.3 specification allows controller to wait 6 periodic advertising events for
 * synchronization establishment, hence timeout must be longer than that.
 */
#define SYNC_CREATE_TIMEOUT_INTERVAL_NUM 7
/* Maximum length of advertising data represented in hexadecimal format */
#define ADV_DATA_HEX_STR_LEN_MAX (BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN * 2 + 1)

static struct bt_le_per_adv_sync *sync;
// 标签MAC地址
static bt_addr_le_t per_addr;
static volatile bool per_adv_found;
static bool scan_enabled;
// 周期性广播对象的SID
static uint8_t per_sid;
static uint32_t sync_create_timeout_ms;

static K_SEM_DEFINE(sem_per_adv, 0, 1);
static K_SEM_DEFINE(sem_per_sync, 0, 1);
static K_SEM_DEFINE(sem_per_sync_lost, 0, 1);

// LED模块引入
#define LED_SLEEP_TIME_MS 1000
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);

// BTN模块引入
#define BUTTON_0_NODE DT_ALIAS(boot_button0)
#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios)
static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios);
#else
#error "button must be declared in device tree as 'mcuboot_button0'"
#endif

// 使能天线切换开关(接收端AoA)
#if defined(CONFIG_BT_DF_CTE_RX_AOA)
/* Example sequence of antenna switch patterns for antenna matrix designed by
 * Nordic. For more information about antenna switch patterns see README.rst.
 */
// Nordic官方参数.
// static const uint8_t ant_patterns[] = {0x2, 0x0, 0x5, 0x6, 0x1, 0x4, 0xC, 0x9, 0xE, 0xD, 0x8, 0xA};
// 吾控参数.默认在数组[0],即天线9上接收扩展广播,当周期性广播后面有CTE时,就顺序切换天线1~天线8
const static uint8_t ant_patterns[] = {0x04, 0x0B, 0x0C, 0x0E, 0x00, 0x02, 0x07, 0x08, 0x0A};
#endif /* CONFIG_BT_DF_CTE_RX_AOA */

/**
 * @brief 周期性广播间隔转毫秒
 *
 * @param interval
 * @return uint32_t
 */
static inline uint32_t adv_interval_to_ms(uint16_t interval)
{
	return interval * 5 / 4;
}

/**
 * @brief phy类型
 *
 * @param phy
 * @return const char*
 */
static const char *phy2str(uint8_t phy)
{
	switch (phy)
	{
	case 0:
		return "No packets";
	case BT_GAP_LE_PHY_1M:
		return "LE 1M";
	case BT_GAP_LE_PHY_2M:
		return "LE 2M";
	case BT_GAP_LE_PHY_CODED:
		return "LE Coded";
	default:
		return "Unknown";
	}
}

/**
 * @brief CTE类型
 *
 * @param type
 * @return const char*
 */
static const char *cte_type2str(uint8_t type)
{
	switch (type)
	{
	case BT_DF_CTE_TYPE_AOA:
		return "AOA";
	case BT_DF_CTE_TYPE_AOD_1US:
		return "AOD 1 [us]";
	case BT_DF_CTE_TYPE_AOD_2US:
		return "AOD 2 [us]";
	case BT_DF_CTE_TYPE_NONE:
		return "";
	default:
		return "Unknown";
	}
}

/**
 * @brief 包状态
 *
 * @param status
 * @return const char*
 */
static const char *packet_status2str(uint8_t status)
{
	switch (status)
	{
	case BT_DF_CTE_CRC_OK:
		return "CRC OK";
	case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME:
		return "CRC not OK, CTE Info OK";
	case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER:
		return "CRC not OK, Sampled other way";
	case BT_DF_CTE_INSUFFICIENT_RESOURCES:
		return "No resources";
	default:
		return "Unknown";
	}
}

/**
 * @brief 解析广播数据(三段式)
 *
 * @param data
 * @param user_data
 * @return true
 * @return false
 */
static bool data_cb(struct bt_data *data, void *user_data)
{
	char *name = user_data;
	uint8_t len;

	switch (data->type)
	{
	case BT_DATA_NAME_SHORTENED:
	case BT_DATA_NAME_COMPLETE:
		len = MIN(data->data_len, PEER_NAME_LEN_MAX - 1);
		memcpy(name, data->data, len);
		name[len] = '\0';
		return false;
	default:
		return true;
	}
}

/**
 * @brief 周期性广播同步完成后的回调函数(如果标签在基站附近,理论上只需要同步一次即可,也就是回调执行一次,后面就是收数据/关连接/IQ采样行为)
 *
 * @param sync
 * @param info
 */
static void sync_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info)
{
	char le_addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));

	LOG_D("sync_cb[%u]: [DEVICE]: %s synced, "
		  "Interval 0x%04x (%u ms), PHY %s\n",
		  bt_le_per_adv_sync_get_index(sync), le_addr, info->interval, adv_interval_to_ms(info->interval), phy2str(info->phy));
	// 同步完成给出信号量(主函数中接收信号量,并使能CTE接收)
	k_sem_give(&sem_per_sync);
}

// 对象同步丢失FIFO
static K_FIFO_DEFINE(fifo_sync_lost_obj_data);
struct sync_lost_data_t
{
	// 对象
	struct bt_le_per_adv_sync *sync_obj;
	// 对象地址
	uint8_t addr[BT_ADDR_LE_STR_LEN];
};
/**
 * @brief 关闭周期性同步完成(标签断电/离开这个区域了)
 *
 * @param sync
 * @param info
 */
static void term_cb(struct bt_le_per_adv_sync *sync, const struct bt_le_per_adv_sync_term_info *info)
{
	struct sync_lost_data_t *sync_lost_data = k_malloc(sizeof(struct sync_lost_data_t));
	if (sync_lost_data)
	{
		sync_lost_data->sync_obj = sync;
		memcpy(sync_lost_data->addr, info->addr->a.val, BT_ADDR_SIZE);
	}
	// 关闭完成给出信号量(主函数中接收信号量,并删除该同步对象)
	k_fifo_put(&fifo_sync_lost_obj_data, sync_lost_data);
}

/**
 * @brief 周期性广播接收数据完成
 *
 * @param sync
 * @param info
 * @param buf
 */
static void recv_cb(struct bt_le_per_adv_sync *sync, const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf)
{
	static char data_str[ADV_DATA_HEX_STR_LEN_MAX];
	char le_addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
	// LOG_D("recv_cb[%u]: [DEVICE]: %s, tx_power %i, RSSI %i, CTE %s, data length %u, data: %s\n", bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power, info->rssi, cte_type2str(info->cte_type), buf->len, data_str);
}

/**
 * @brief IQ采样完成
 *
 * @param sync
 * @param report
 */
static void cte_recv_cb(struct bt_le_per_adv_sync *sync, struct bt_df_per_adv_sync_iq_samples_report const *report)
{
	LOG_D("cte_recv_cb[%u]: samples count %d, cte type %s, slot durations: %u [us], packet status %s, RSSI %i\n", bt_le_per_adv_sync_get_index(sync), report->sample_count, cte_type2str(report->cte_type), report->slot_durations, packet_status2str(report->packet_status), report->rssi);
}

// 周期性广播同步回调
static struct bt_le_per_adv_sync_cb sync_callbacks = {
	.synced = sync_cb,			  /* 同步已成功 */
	.term = term_cb,			  /* 同步已关闭(本机关闭/远程请求关闭/远距离丢数据引起的关闭) */
	.recv = recv_cb,			  /* 数据已提取 */
	.cte_report_cb = cte_recv_cb, /*IQ采样已成功*/
};

/**
 * @brief 扫描回调函数
 *
 * @param info
 * @param buf
 */
static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
{
	char le_addr[BT_ADDR_LE_STR_LEN];
	char name[PEER_NAME_LEN_MAX];

	(void)memset(name, 0, sizeof(name));

	// 提取标签的名称
	bt_data_parse(buf, data_cb, name);
	// 提取标签的地址
	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));

	// LOG_D("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
	// 	   "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
	// 	   "SID: %u\n",
	// 	   le_addr, info->adv_type, info->tx_power, info->rssi, name,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
	// 	   phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
	// 	   info->sid);
	// LOG_D("[DEVICE]: %s\r\n", le_addr);


	// 有间隔则说明是周期性广播
	if (/*!per_adv_found && */ info->interval)
	{
		/* 记录新来的标签MAC,插入到list,如果长时间无周期性广播,则删除它 */
		gpio_pin_toggle_dt(&led0);
		// LOG_D("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
		// 	   "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
		// 	   "SID: %u\n",
		// 	   le_addr, info->adv_type, info->tx_power, info->rssi, name,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
		// 	   phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
		// 	   info->sid);

		// 同步超时时间
		sync_create_timeout_ms = adv_interval_to_ms(info->interval) * SYNC_CREATE_TIMEOUT_INTERVAL_NUM;
		per_adv_found = true;
		per_sid = info->sid;
		bt_addr_le_copy(&per_addr, info->addr);
		// 给出信号量,立即开始同步
		k_sem_give(&sem_per_adv);
	}
}

/**
 * @brief 发现有了周期性广播,就创建一个东西(obj)来处理周期性广播同步
 *
 */
static void create_sync(void)
{
	struct bt_le_per_adv_sync_param sync_create_param;
	int err;

	LOG_D("Creating Periodic Advertising Sync...");
	// 标签地址拷贝
	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
	// 需要有CTE才同步(没有CTE则不同步)
	sync_create_param.options = 0;
	// 广播者的set id
	sync_create_param.sid = per_sid;
	// 通过“最大事件跳过”这个参数,扫描设备可以在成功接收到一个周期性广播事件后,选择跳过一定数量的连续周期性广播事件,以达到节省功耗或提高扫描效率的目的
	sync_create_param.skip = 0;
	// 同步超时100ms
	sync_create_param.timeout = 0x64; // 0xa;
	// 创建周期性广播同步对象,用于同步周期性广播的上报.
	err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
}

// 扫描回调
static struct bt_le_scan_cb scan_callbacks = {
	.recv = scan_recv,
};

/**
 * @brief 删除处理周期性广播同步的obj
 *
 * @return int
 */
static int delete_sync(void)
{
	int err;

	LOG_D("Deleting Periodic Advertising Sync...");
	// 删除周期性广播同步对象
	err = bt_le_per_adv_sync_delete(sync);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return err;
	}
	LOG_D("success\n");

	return 0;
}

/**
 * @brief 使能cte
 *
 */
static void enable_cte_rx(void)
{
	int err;

	const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
		.max_cte_count = 5, /* CTE次数,与标签对应上即可 */
		/* BT_DF_CTE_TYPE_AOA   BT_DF_CTE_TYPE_ALL */
		.cte_types = BT_DF_CTE_TYPE_ALL,					/* 支持aoa/aod1us/aod2us三种类型 */
		.slot_durations = BT_DF_ANTENNA_SWITCHING_SLOT_2US, /* 开关切换使用2us槽 */
		.num_ant_ids = ARRAY_SIZE(ant_patterns),			/* 天线数量 */
		.ant_ids = ant_patterns,							/* 天线数组 */
	};

	LOG_D("%s():enable receiving of CTE.\r\n", __func__);
	// 使能接收,采样CTE信号
	err = bt_df_per_adv_sync_cte_rx_enable(sync, &cte_rx_params);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return;
	}
	LOG_D("success. CTE receive enabled.\n");
}

/**
 * @brief 扫描初始化
 *
 * @return int
 */
static int scan_init(void)
{
	LOG_D("Scan callbacks register...");
	// 注册扫描回调函数(primary channel)
	bt_le_scan_cb_register(&scan_callbacks);
	LOG_D("success.\n");

	LOG_D("Periodic Advertising callbacks register...");
	// 注册周期性广播回调函数(secondary channel)
	bt_le_per_adv_sync_cb_register(&sync_callbacks);
	LOG_D("success.\n");

	return 0;
}

/**
 * @brief 使能扫描
 *
 * @return int
 */
static int scan_enable(void)
{
	struct bt_le_scan_param param = {
		.type = BT_LE_SCAN_TYPE_ACTIVE, /*扫描,并request额外信息*/
		.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
		/*BT_LE_SCAN_OPT_NONE*/ /*不过滤*/
		/*BT_LE_SCAN_OPT_FILTER_DUPLICATE*/
		.interval = BT_GAP_SCAN_FAST_INTERVAL, /* 扫描间隔60ms */
		.window = BT_GAP_SCAN_FAST_WINDOW,	   /* 扫描窗30ms */
		.timeout = 0U,
	};

	int err;

	if (!scan_enabled)
	{
		LOG_D("Start scanning...");
		err = bt_le_scan_start(&param, NULL);
		if (err)
		{
			LOG_D("failed (err %d)\n", err);
			return err;
		}
		LOG_D("success\n");
		scan_enabled = true;
	}

	return 0;
}

static void scan_disable(void)
{
	int err;

	LOG_D("Scan disable...");
	err = bt_le_scan_stop();
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return;
	}
	LOG_D("Success.\n");

	scan_enabled = false;
}

/**
 * @brief 判定是否应该进入升级模式(button0开机就被按下)
 *
 * @return true -进入升级模式
 * @return false -不进入升级模式
 */
static bool is_enter_boot_mode(void)
{
	int pin_active;

	if (!device_is_ready(button0.port))
	{
		return false;
	}

	gpio_pin_configure_dt(&button0, GPIO_INPUT);
	pin_active = gpio_pin_get_dt(&button0);

	LOG_DBG("0button0 = %d.", pin_active);

	if (pin_active)
	{
		k_sleep(K_MSEC(50));
		LOG_DBG("button0 = %d.", pin_active);
		if (pin_active == gpio_pin_get_dt(&button0))
			return true;
		else
			return false;
	}
	return false;
}

int main(void)
{
	/* 延时等待片外外设起来 */
	k_msleep(1000);

	int err;

	if (!gpio_is_ready_dt(&led0) || !gpio_is_ready_dt(&led1))
	{
		return 0;
	}

	gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&button0, GPIO_INPUT);

	gpio_pin_set_dt(&led0, GPIO_ACTIVE_HIGH);
	gpio_pin_set_dt(&led1, GPIO_ACTIVE_HIGH);

	// 获取构建信息
	//  memset(bulid_msg, 0, sizeof(bulid_msg));
	//  sprintf(bulid_msg, "BR,%04d%02d%02d-%02d%02d%02d,%s\r\n", OS_YEAR, OS_MONTH, OS_DAY, OS_HOUR, OS_MINUTE, OS_SECOND, FIREWARE_VERSION);
	//  usart1SendStringDma(bulid_msg);

	LOG_INF("hello %s, build time:" __DATE__ " " __TIME__ "\n", CONFIG_BOARD);

	/* 检查是否是升级模式 */
	if (gpio_pin_get_dt(&button0))
	{
		gpio_pin_set_dt(&led1, GPIO_ACTIVE_LOW);
		LOG_INF("enter boot mode.");
		extern void wk_dfu_uart_thread_create(void);
		wk_dfu_uart_thread_create();
		return 0;
	}

	gpio_pin_set_dt(&led0, GPIO_ACTIVE_LOW);
	LOG_INF("enter application mode.");

	// 初始化串口
	uart_init();
	// 创建接收线程
	extern void uart_thread_create(void);
	uart_thread_create();

	uint8_t data[10] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30};
	for (int i = 0; i < 100; i++)
	{
		uart_hex_print(data, sizeof(data));
		uart_print("hello app0 %d, build time:" __DATE__ " " __TIME__ "\r\n", i, CONFIG_BOARD);
	}

	k_msleep(1000);

	LOG_D("Starting Connectionless Locator Demo\n");
	LOG_D("Bluetooth initialization...");
	err = bt_enable(NULL);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
	}
	LOG_D("success\n");

	// 扫描初始化(处理扫描回调(primary)/处理周期性广播回调(secondary))
	scan_init();
	scan_enable();

	while (true)
	{
		k_msleep(100);
		gpio_pin_toggle_dt(&led1);
	}
}

/**
 * @brief 周期性广播对象创建
 *
 */
void create_sync_thread(void)
{
	int err;
	k_msleep(100);

	while (1)
	{
		// 等待周期性广播信号量(可能会丢对象)
		err = k_sem_take(&sem_per_adv, K_FOREVER);
		if (err)
		{
			LOG_D("failed (err %d)\n", err);
			continue;
		}

		// 临时对象
		struct per_adv_obj obj;

		/* 遍历链表确认是否已经存在该对象 */
		// 提取对象地址
		memcpy(obj.mac.addr, per_addr.a.val, BT_ADDR_SIZE);
		// 遍历
		err = wk_list_search_per_adv_obj(obj);
		if (!err)
		{
			// LOG_D("obj already exist continue.");
			continue;
		}
		LOG_D("new obj comming.");
		// 周期性广播对象的参数
		struct bt_le_per_adv_sync_param sync_create_param;
		// 标签地址拷贝
		bt_addr_le_copy(&(obj.sync_create_param.addr), &per_addr);
		// 需要有CTE才同步(没有CTE则不同%E6%AD%A5)
		obj.sync_create_param.options = 0;
		// 广播者的set id
		obj.sync_create_param.sid = per_sid;
		// 通过“最大事件跳过”这个参数,扫描设备可以在成功接收到一个周期性广播事件后,选择跳过一定数量的连续周期性广播事件,以达到节省功耗或提高扫描效率的目的
		obj.sync_create_param.skip = 0;
		// 同步超时100ms
		obj.sync_create_param.timeout = 0x64; // 0xa;
		// 创建周期性广播同步对象,用于同步周期性广播的上报.
		err = bt_le_per_adv_sync_create(&(obj.sync_create_param), &(obj.sync));
		if (err)
		{
			LOG_D("sync create failed (err %d)\n", err);
			continue;
		}

		/* 等待周期性广播成功 */
		err = k_sem_take(&sem_per_sync, K_MSEC(sync_create_timeout_ms));
		if (err)
		{
			// 删除周期性广播同步对象
			bt_le_per_adv_sync_delete(obj.sync);
			continue;
		}
		LOG_D("success. Periodic sync established.\n");

		/* 使能CTE */
		const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
			.max_cte_count = 5, /* CTE次数,与标签对应上即可 */
			/* BT_DF_CTE_TYPE_AOA   BT_DF_CTE_TYPE_ALL */
			.cte_types = BT_DF_CTE_TYPE_ALL,					/* 支持aoa/aod1us/aod2us三种类型 */
			.slot_durations = BT_DF_ANTENNA_SWITCHING_SLOT_2US, /* 开关切换使用2us槽 */
			.num_ant_ids = ARRAY_SIZE(ant_patterns),			/* 天线数量 */
			.ant_ids = ant_patterns,							/* 天线数组 */
		};
		// 使能接收,采样CTE信号
		err = bt_df_per_adv_sync_cte_rx_enable(obj.sync, &cte_rx_params);
		if (err)
		{
			LOG_D("enable cet rx failed (err %d)\n", err);
			continue;
		}

		/* 将对象添加到链表 */
		wk_list_add_per_adv_obj(obj);
		// 遍历链表
		wk_list_foreach_per_adv_obj();
	}
}
K_THREAD_DEFINE(create_sync_thread_id, 2024, create_sync_thread, NULL, NULL, NULL, 9, 0, 0);

/**
 * @brief 周期性广播对象删除
 *
 */
void delete_sync_thread(void)
{
	int err;
	k_msleep(100);

	while (1)
	{
		// 一直等待获取同步关闭的对象(标签断电/离开这个区域了)
		struct sync_lost_data_t *sync_lost_obj = k_fifo_get(&fifo_sync_lost_obj_data, K_FOREVER);
		// 删除周期性广播同步对象
		err = bt_le_per_adv_sync_delete(sync_lost_obj->sync_obj);
		LOG_D("bt_le_per_adv_sync_delete err = %d", err);

		// 临时对象
		struct per_adv_obj obj;
		// 提取对象地址
		memcpy(obj.mac.addr, sync_lost_obj->addr, BT_ADDR_SIZE);
		// 释放内存
		k_free(sync_lost_obj);
		// 删除链表
		err = wk_list_del_per_adv_obj(obj);
		LOG_D("wk_list_del_per_adv_obj err = %d", err);
	}
}
K_THREAD_DEFINE(delete_sync_thread_id, 2024, delete_sync_thread, NULL, NULL, NULL, 9, 0, 0);

how can i write the code for many tags.

Related