Zephyr RTOS 下 bt_le_scan_start 函数详解

目录

概述

[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)发现周围的蓝牙外围设备。

功能总结如下:

  1. 设备发现:扫描并发现周围的 BLE 广播设备

  2. 广播数据收集:获取设备的广播数据(如设备名称、服务 UUID、制造商数据等)

  3. 连接准备:为后续的连接操作发现目标设备

  4. 信标监控:监控 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(&param, 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);
相关推荐
背包旅行码农1 年前
Ubuntu2404 下搭建 Zephyr 开发环境
zephyr rtos
代码讲故事3 年前
免费开源使用的几款红黑网络流量工具,自动化的多功能网络侦查工具、超级关键词URL采集工具、Burpsuite被动扫描流量转发插件
网络流量·网络侦查·关键词·采集工具·被动扫描·流量转发