目录
[1 函数功能介绍](#1 函数功能介绍)
[1.1 函数原型和参数和主要参数](#1.1 函数原型和参数和主要参数)
[1.2 主要功能](#1.2 主要功能)
[1.3 扫描参数选择指南](#1.3 扫描参数选择指南)
[2 基本使用方法](#2 基本使用方法)
[2.1 简单扫描示例](#2.1 简单扫描示例)
[2.2 完整的使用流程](#2.2 完整的使用流程)
[3 高级用法](#3 高级用法)
[3.1 被动扫描与主动扫描对比](#3.1 被动扫描与主动扫描对比)
[3.2 使用白名单过滤](#3.2 使用白名单过滤)
[3.3 扫描参数计算和优化](#3.3 扫描参数计算和优化)
[3.4 解析特定广播数据(如iBeacon)](#3.4 解析特定广播数据(如iBeacon))
[4 重要注意事项](#4 重要注意事项)
[4.1 功耗管理](#4.1 功耗管理)
[4.2 回调函数注意事项](#4.2 回调函数注意事项)
[4.3 内存管理](#4.3 内存管理)
[4.4 错误处理](#4.4 错误处理)
[5 常见问题解决](#5 常见问题解决)
概述
bt_le_scan_start 是 Zephyr Bluetooth API 的核心函数之一,用于启动蓝牙低功耗(BLE)扫描。它允许设备作为中心设备(Central)或观察者(Observer)发现周围的蓝牙外围设备。
1 函数功能介绍
1.1 函数原型和参数和主要参数
1) 函数原型
cpp
int bt_le_scan_start(const struct bt_le_scan_param *param,
bt_le_scan_cb_t cb);
2) 主要参数
- )
param- 扫描参数结构体
cpp
struct bt_le_scan_param {
uint8_t type; // 扫描类型:被动或主动
uint8_t options; // 扫描选项(位掩码)
uint16_t interval; // 扫描间隔(单位:0.625ms)
uint16_t window; // 扫描窗口(单位:0.625ms)
uint8_t timeout; // 扫描超时(单位:秒),0=持续扫描
};
-1)扫描类型(type):
cpp#define BT_LE_SCAN_TYPE_PASSIVE 0x00 // 被动扫描 #define BT_LE_SCAN_TYPE_ACTIVE 0x01 // 主动扫描-2) 扫描选项(options):
cpp#define BT_LE_SCAN_OPT_NONE 0x00 // 无选项 #define BT_LE_SCAN_OPT_FILTER_DUPLICATE 0x01 // 过滤重复广播 #define BT_LE_SCAN_OPT_FILTER_WHITELIST 0x02 // 只扫描白名单设备 #define BT_LE_SCAN_OPT_CODED 0x04 // 使用编码PHY(BLE 5.0)
3) cb - 扫描回调函数
cpp
typedef void bt_le_scan_cb_t(const bt_addr_le_t *addr,
int8_t rssi,
uint8_t adv_type,
struct net_buf_simple *buf);
回调参数:
addr:发现的设备地址
rssi:信号强度指示器(dBm)
adv_type:广播类型
buf:广播数据缓冲区
广播类型(adv_type):
cpp
#define BT_GAP_ADV_TYPE_ADV_IND 0x00 // 可连接的非定向广播
#define BT_GAP_ADV_TYPE_ADV_DIRECT_IND 0x01 // 可连接的定向广播
#define BT_GAP_ADV_TYPE_ADV_SCAN_IND 0x02 // 可扫描的非定向广播
#define BT_GAP_ADV_TYPE_ADV_NONCONN_IND 0x03 // 不可连接的非定向广播
#define BT_GAP_ADV_TYPE_SCAN_RSP 0x04 // 扫描响应
1.2 主要功能
bt_le_scan_start 是 Zephyr Bluetooth API 的核心函数之一,用于启动蓝牙低功耗(BLE)扫描。它允许设备作为中心设备(Central)或观察者(Observer)发现周围的蓝牙外围设备。
功能总结如下:
设备发现:扫描并发现周围的 BLE 广播设备
广播数据收集:获取设备的广播数据(如设备名称、服务 UUID、制造商数据等)
连接准备:为后续的连接操作发现目标设备
信标监控:监控 iBeacon、Eddystone 等蓝牙信标
1.3 扫描参数选择指南

2 基本使用方法
2.1 简单扫描示例
cpp
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
/* 扫描回调函数 */
static void scan_cb(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
char addr_str[BT_ADDR_LE_STR_LEN];
// 转换地址为字符串
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
// 打印设备信息
printk("发现设备: %s, RSSI: %d, 广播类型: 0x%02x\n",
addr_str, rssi, adv_type);
// 解析广播数据
parse_advertising_data(buf);
}
/* 解析广播数据 */
static void parse_advertising_data(struct net_buf_simple *buf)
{
while (buf->len > 1) {
uint8_t len = net_buf_simple_pull_u8(buf);
uint8_t type = net_buf_simple_pull_u8(buf);
switch (type) {
case BT_DATA_NAME_COMPLETE:
case BT_DATA_NAME_SHORTENED: {
char name[31];
size_t name_len = MIN(len - 1, sizeof(name) - 1);
memcpy(name, buf->data, name_len);
name[name_len] = '\0';
printk("设备名称: %s\n", name);
break;
}
case BT_DATA_UUID16_SOME:
case BT_DATA_UUID16_ALL: {
printk("16位UUID服务: ");
for (int i = 0; i < (len - 1) / 2; i++) {
uint16_t uuid = net_buf_simple_pull_le16(buf);
printk("%04x ", uuid);
}
printk("\n");
break;
}
case BT_DATA_MANUFACTURER_DATA: {
uint16_t company_id = net_buf_simple_pull_le16(buf);
printk("制造商数据,公司ID: 0x%04x\n", company_id);
break;
}
}
// 跳过剩余数据
net_buf_simple_pull(buf, len - 1);
}
}
/* 启动扫描 */
int start_ble_scan(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE, // 主动扫描
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, // 过滤重复
.interval = BT_GAP_SCAN_FAST_INTERVAL, // 快速扫描间隔
.window = BT_GAP_SCAN_FAST_WINDOW, // 快速扫描窗口
.timeout = 30, // 扫描30秒后停止
};
int err = bt_le_scan_start(&scan_param, scan_cb);
if (err) {
printk("启动扫描失败: %d\n", err);
return err;
}
printk("BLE扫描已启动\n");
return 0;
}
/* 停止扫描 */
void stop_ble_scan(void)
{
int err = bt_le_scan_stop();
if (err) {
printk("停止扫描失败: %d\n", err);
} else {
printk("BLE扫描已停止\n");
}
}
2.2 完整的使用流程
cpp
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#define SCAN_DURATION_SECONDS 30
#define TARGET_DEVICE_NAME "MyDevice"
static struct k_timer scan_timer;
static bool found_target = false;
/* 扫描回调 */
static void scan_callback(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
// 检查是否为扫描响应
if (adv_type == BT_GAP_ADV_TYPE_SCAN_RSP) {
printk("收到扫描响应: %s, RSSI: %d\n", addr_str, rssi);
}
// 解析广播数据查找目标设备
check_for_target_device(addr, rssi, buf);
}
/* 检查目标设备 */
static void check_for_target_device(const bt_addr_le_t *addr, int8_t rssi,
struct net_buf_simple *buf)
{
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
// 解析广播数据
while (buf->len > 1) {
uint8_t len = net_buf_simple_pull_u8(buf);
uint8_t type = net_buf_simple_pull_u8(buf);
if (type == BT_DATA_NAME_COMPLETE) {
char name[31];
size_t name_len = MIN(len - 1, sizeof(name) - 1);
memcpy(name, buf->data, name_len);
name[name_len] = '\0';
if (strcmp(name, TARGET_DEVICE_NAME) == 0) {
printk("找到目标设备: %s, 地址: %s, RSSI: %d\n",
name, addr_str, rssi);
found_target = true;
// 停止扫描
bt_le_scan_stop();
}
}
net_buf_simple_pull(buf, len - 1);
}
}
/* 定时器回调:扫描超时 */
static void scan_timeout(struct k_timer *timer)
{
if (!found_target) {
printk("扫描超时,未找到目标设备\n");
bt_le_scan_stop();
}
}
/* 初始化蓝牙 */
int init_bluetooth(void)
{
int err;
err = bt_enable(NULL);
if (err) {
printk("蓝牙初始化失败: %d\n", err);
return err;
}
printk("蓝牙已初始化\n");
return 0;
}
/* 主函数 */
int main(void)
{
int err;
// 初始化蓝牙
err = init_bluetooth();
if (err) {
return 0;
}
// 初始化定时器
k_timer_init(&scan_timer, scan_timeout, NULL);
// 设置扫描参数
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE,
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
.timeout = 0, // 手动控制超时
};
// 启动扫描
printk("开始扫描目标设备...\n");
err = bt_le_scan_start(&scan_param, scan_callback);
if (err) {
printk("启动扫描失败: %d\n", err);
return 0;
}
// 启动超时定时器
k_timer_start(&scan_timer, K_SECONDS(SCAN_DURATION_SECONDS), K_NO_WAIT);
// 等待扫描完成
while (!found_target) {
k_sleep(K_MSEC(100));
}
printk("扫描完成\n");
return 0;
}
3 高级用法
3.1 被动扫描与主动扫描对比
cpp
/* 被动扫描配置(低功耗) */
void start_passive_scan(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_PASSIVE, // 被动扫描
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
.interval = BT_GAP_SCAN_SLOW_INTERVAL_1, // 慢速扫描
.window = BT_GAP_SCAN_SLOW_WINDOW_1,
.timeout = 0, // 持续扫描
};
bt_le_scan_start(&scan_param, scan_cb);
printk("被动扫描已启动(低功耗模式)\n");
}
/* 主动扫描配置(快速发现) */
void start_active_scan(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE, // 主动扫描
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
.interval = BT_GAP_SCAN_FAST_INTERVAL, // 快速扫描
.window = BT_GAP_SCAN_FAST_WINDOW,
.timeout = 10, // 10秒后自动停止
};
bt_le_scan_start(&scan_param, scan_cb);
printk("主动扫描已启动(快速发现模式)\n");
}
3.2 使用白名单过滤
cpp
/* 设置白名单并扫描 */
void start_whitelist_scan(void)
{
int err;
// 定义白名单设备地址
bt_addr_le_t whitelist[] = {
{BT_ADDR_LE_RANDOM, {{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}},
{BT_ADDR_LE_PUBLIC, {{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}},
};
// 清除现有白名单
bt_le_whitelist_clear();
// 添加设备到白名单
for (int i = 0; i < ARRAY_SIZE(whitelist); i++) {
err = bt_le_whitelist_add(&whitelist[i]);
if (err) {
printk("添加白名单失败 [%d]: %d\n", i, err);
}
}
// 设置白名单扫描参数
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_ACTIVE,
.options = BT_LE_SCAN_OPT_FILTER_WHITELIST | // 只扫描白名单
BT_LE_SCAN_OPT_FILTER_DUPLICATE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
.timeout = 0,
};
err = bt_le_scan_start(&scan_param, scan_cb);
if (err) {
printk("白名单扫描启动失败: %d\n", err);
} else {
printk("白名单扫描已启动\n");
}
}
3.3 扫描参数计算和优化
cpp
/* 计算扫描占空比和功耗 */
void calculate_scan_parameters(void)
{
// 计算实际时间(单位:毫秒)
// 时间 = 参数值 × 0.625ms
uint16_t interval_ms = BT_GAP_SCAN_FAST_INTERVAL * 625 / 1000; // 60ms
uint16_t window_ms = BT_GAP_SCAN_FAST_WINDOW * 625 / 1000; // 30ms
float duty_cycle = (float)window_ms / interval_ms * 100; // 50%
printk("扫描参数:\n");
printk(" 间隔: %dms\n", interval_ms);
printk(" 窗口: %dms\n", window_ms);
printk(" 占空比: %.1f%%\n", duty_cycle);
// 估计功耗(示例值,实际值取决于硬件)
float current_active = 10.0f; // 扫描时电流(mA)
float current_idle = 0.1f; // 空闲时电流(mA)
float avg_current = (duty_cycle / 100) * current_active +
((100 - duty_cycle) / 100) * current_idle;
printk(" 估计平均电流: %.2fmA\n", avg_current);
}
/* 根据应用需求选择扫描参数 */
struct bt_le_scan_param get_optimal_scan_params(enum scan_requirement req)
{
struct bt_le_scan_param param = {0};
switch (req) {
case REQUIREMENT_FAST_DISCOVERY:
// 快速发现:高占空比
param.type = BT_LE_SCAN_TYPE_ACTIVE;
param.interval = 0x0060; // 60ms
param.window = 0x0060; // 60ms (100%占空比)
param.timeout = 10;
break;
case REQUIREMENT_LOW_POWER:
// 低功耗:低占空比
param.type = BT_LE_SCAN_TYPE_PASSIVE;
param.interval = 0x1000; // 2560ms
param.window = 0x0012; // 11.25ms (~0.44%占空比)
param.timeout = 0;
break;
case REQUIREMENT_BACKGROUND:
// 后台扫描:平衡模式
param.type = BT_LE_SCAN_TYPE_PASSIVE;
param.interval = 0x0800; // 1280ms
param.window = 0x0018; // 15ms (~1.17%占空比)
param.timeout = 0;
param.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE;
break;
}
return param;
}
3.4 解析特定广播数据(如iBeacon)
cpp
/* iBeacon数据结构 */
struct ibeacon_data {
uint8_t flags[3];
uint8_t length;
uint8_t type;
uint16_t company_id;
uint16_t beacon_type;
uint8_t proximity_uuid[16];
uint16_t major;
uint16_t minor;
int8_t tx_power;
};
/* 解析iBeacon数据 */
static void parse_ibeacon(const bt_addr_le_t *addr, int8_t rssi,
struct net_buf_simple *buf)
{
struct ibeacon_data *ibeacon;
while (buf->len > 1) {
uint8_t len = net_buf_simple_pull_u8(buf);
uint8_t type = net_buf_simple_pull_u8(buf);
if (type == BT_DATA_MANUFACTURER_DATA && len >= 25) {
// 检查是否是iBeacon(Apple公司ID)
uint16_t company_id = net_buf_simple_pull_le16(buf);
if (company_id == 0x004C) { // Apple公司ID
uint16_t beacon_type = net_buf_simple_pull_le16(buf);
if (beacon_type == 0x0215) { // iBeacon类型
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
// 提取UUID
uint8_t uuid[16];
for (int i = 0; i < 16; i++) {
uuid[i] = net_buf_simple_pull_u8(buf);
}
// 提取Major和Minor
uint16_t major = net_buf_simple_pull_le16(buf);
uint16_t minor = net_buf_simple_pull_le16(buf);
// 提取发射功率
int8_t tx_power = net_buf_simple_pull_u8(buf);
// 计算距离(简化模型)
float distance = calculate_distance(rssi, tx_power);
printk("iBeacon发现:\n");
printk(" 地址: %s\n", addr_str);
printk(" Major: %u, Minor: %u\n", major, minor);
printk(" RSSI: %d, TX Power: %d\n", rssi, tx_power);
printk(" 估计距离: %.2f米\n", distance);
}
}
}
net_buf_simple_pull(buf, len - 1);
}
}
4 重要注意事项
4.1 功耗管理
cpp
/* 错误的做法:持续高占空比扫描 */
void bad_power_management(void)
{
struct bt_le_scan_param bad_param = {
.interval = 0x0060, // 60ms
.window = 0x0060, // 60ms (100%占空比)
.timeout = 0, // 持续扫描
};
// 这会快速耗尽电池!
}
/* 正确的做法:间歇扫描 */
void good_power_management(void)
{
struct k_work_delayable scan_work;
// 工作函数:执行短时间扫描
static void scan_work_handler(struct k_work *work)
{
struct bt_le_scan_param param = {
.type = BT_LE_SCAN_TYPE_PASSIVE,
.interval = 0x0060,
.window = 0x0030, // 30ms (50%占空比)
.timeout = 3, // 只扫描3秒
};
bt_le_scan_start(¶m, scan_cb);
// 安排下一次扫描(例如30秒后)
k_work_schedule(&scan_work, K_SECONDS(30));
}
}
4.2 回调函数注意事项
cpp
/* 错误的做法:在回调中进行耗时操作 */
void bad_scan_callback(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
// 错误:可能阻塞系统工作队列
k_sleep(K_SECONDS(1));
// 错误:执行复杂计算
perform_complex_calculation();
// 错误:进行I/O操作
write_to_filesystem();
}
/* 正确的做法:快速处理,延迟复杂操作 */
static struct k_workqueue *app_workq;
static struct k_work deferred_work;
void good_scan_callback(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct net_buf_simple *buf)
{
// 快速复制数据
struct device_data {
bt_addr_le_t addr;
int8_t rssi;
uint8_t data[32];
size_t data_len;
} *data = k_malloc(sizeof(*data));
if (!data) return;
memcpy(&data->addr, addr, sizeof(bt_addr_le_t));
data->rssi = rssi;
data->data_len = MIN(buf->len, sizeof(data->data));
memcpy(data->data, buf->data, data->data_len);
// 将复杂处理推迟到工作队列
k_work_submit_to_queue(app_workq, &deferred_work);
}
4.3 内存管理
cpp
/* 正确处理广播数据缓冲区 */
void handle_adv_data_safely(struct net_buf_simple *buf)
{
// 错误:保存缓冲区指针(缓冲区会被重用)
// static struct net_buf_simple *saved_buf; // 不要这样做!
// 正确:复制需要的数据
static uint8_t saved_data[32];
size_t copy_len = MIN(buf->len, sizeof(saved_data));
memcpy(saved_data, buf->data, copy_len);
// 如果需要处理原始数据,使用pull函数
while (buf->len > 1) {
uint8_t len = net_buf_simple_pull_u8(buf);
uint8_t type = net_buf_simple_pull_u8(buf);
// 处理数据...
net_buf_simple_pull(buf, len - 1);
}
}
4.4 并发和状态管理
cpp
static atomic_t scan_state = ATOMIC_INIT(0);
#define SCAN_STATE_IDLE 0
#define SCAN_STATE_SCANNING 1
#define SCAN_STATE_STOPPING 2
/* 安全的扫描控制 */
int safe_scan_start(const struct bt_le_scan_param *param,
bt_le_scan_cb_t cb)
{
int expected = SCAN_STATE_IDLE;
// 使用原子操作检查状态
if (!atomic_cas(&scan_state, expected, SCAN_STATE_SCANNING)) {
printk("扫描已在进行中\n");
return -EBUSY;
}
int err = bt_le_scan_start(param, cb);
if (err) {
atomic_set(&scan_state, SCAN_STATE_IDLE);
}
return err;
}
void safe_scan_stop(void)
{
atomic_set(&scan_state, SCAN_STATE_STOPPING);
int err = bt_le_scan_stop();
if (err == 0) {
atomic_set(&scan_state, SCAN_STATE_IDLE);
} else {
// 处理错误
}
}
4.4 错误处理
cpp
/* 全面的错误处理 */
int robust_scan_start(const struct bt_le_scan_param *param,
bt_le_scan_cb_t cb)
{
int err;
// 检查蓝牙状态
if (!bt_is_ready()) {
printk("蓝牙未就绪\n");
return -EAGAIN;
}
// 检查参数有效性
if (param->window > param->interval) {
printk("错误:扫描窗口不能大于间隔\n");
return -EINVAL;
}
// 尝试启动扫描
err = bt_le_scan_start(param, cb);
switch (err) {
case 0:
printk("扫描启动成功\n");
break;
case -EALREADY:
printk("扫描已在运行中\n");
// 可以选择先停止再重启
bt_le_scan_stop();
k_sleep(K_MSEC(100));
err = bt_le_scan_start(param, cb);
break;
case -EINVAL:
printk("无效的参数\n");
break;
case -ENOMEM:
printk("内存不足\n");
// 可以尝试释放内存后重试
cleanup_memory();
err = bt_le_scan_start(param, cb);
break;
default:
printk("未知错误: %d\n", err);
break;
}
return err;
}
5 常见问题解决
1) 扫描不到设备
cpp
void troubleshoot_scan_issues(void)
{
printk("扫描问题排查:\n");
// 1. 检查蓝牙状态
if (!bt_is_ready()) {
printk(" - 蓝牙未初始化或未就绪\n");
return;
}
// 2. 检查扫描参数
printk(" - 扫描类型: %s\n",
bt_dev.scan_param.type ? "主动" : "被动");
// 3. 检查硬件限制
if (CONFIG_BT_MAX_CONN <= 0) {
printk(" - 最大连接数配置为0\n");
}
// 4. 建议操作
printk("建议:\n");
printk(" 1. 确认目标设备正在广播\n");
printk(" 2. 尝试不同的扫描间隔/窗口\n");
printk(" 3. 禁用重复过滤选项\n");
printk(" 4. 检查信号强度(可能距离太远)\n");
}
2) 扫描性能优化
cpp
/* 自适应扫描策略 */
struct adaptive_scanner {
uint8_t scan_phase;
uint32_t devices_found;
struct k_work_delayable phase_work;
};
static void adaptive_scan_phase(struct k_work *work)
{
struct adaptive_scanner *scanner =
CONTAINER_OF(work, struct adaptive_scanner, phase_work);
switch (scanner->scan_phase) {
case 0: // 阶段1:快速主动扫描
start_fast_active_scan();
scanner->scan_phase = 1;
k_work_schedule(&scanner->phase_work, K_SECONDS(5));
break;
case 1: // 阶段2:慢速被动扫描
if (scanner->devices_found > 0) {
// 发现设备,保持较慢的扫描
start_slow_passive_scan();
} else {
// 未发现设备,返回快速扫描
scanner->scan_phase = 0;
}
k_work_schedule(&scanner->phase_work, K_SECONDS(30));
break;
}
}
3) 代码组织建议
cpp
/* 推荐的代码结构 */
struct ble_scanner {
struct bt_le_scan_param params;
bt_le_scan_cb_t *callback;
atomic_t state;
struct k_mutex lock;
struct k_workqueue *workq;
struct k_work_delayable scan_work;
struct k_work_delayable timeout_work;
};
// 初始化扫描器
int ble_scanner_init(struct ble_scanner *scanner);
// 启动扫描(带错误处理和重试)
int ble_scanner_start(struct ble_scanner *scanner);
// 停止扫描(安全地)
int ble_scanner_stop(struct ble_scanner *scanner);
// 处理扫描结果
void ble_scanner_process_result(struct ble_scanner *scanner,
const bt_addr_le_t *addr,
int8_t rssi,
uint8_t adv_type,
struct net_buf_simple *buf);