--- /dev/null
+/**
+ * @file bt_scan_test.cpp
+ * @brief 蓝牙扫描测试程序
+ * @description 扫描蓝牙设备并打印MAC地址和RSSI值
+ */
+
+#include "custom_utilscpp.h"
+#include "debug_print.h"
+#include "securec.h"
+#include "media_thread_adapt.h"
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 蓝牙GAP相关头文件
+#include "bts_br_gap.h"
+#include "bts_def.h"
+
+// 蓝牙设备信息结构
+typedef struct {
+ uint8_t addr[BD_ADDR_LEN]; // MAC地址
+ int rssi; // RSSI值
+ char name[BD_NAME_LEN]; // 设备名称
+ bool has_name; // 是否已获取名称
+ bool has_rssi; // 是否已获取RSSI
+ bool is_new_device; // 是否是新发现的设备(用于控制打印)
+} bt_device_info_t;
+
+// 蓝牙扫描测试上下文
+typedef struct {
+ bool is_running; // 扫描是否正在运行
+ bt_device_info_t* devices; // 扫描到的设备列表
+ uint32_t device_count; // 设备数量
+ uint32_t device_capacity; // 设备列表容量
+ MediaMutexHandle mutex; // 互斥锁
+
+ // 回调函数指针(保存原始回调,以便恢复)
+ gap_discovery_result_callback original_discovery_callback;
+ gap_read_remote_rssi_event_callback original_rssi_callback;
+ gap_discovery_state_changed_callback original_state_callback;
+ gap_remote_name_changed_callback original_name_callback;
+} BtScanTestContext;
+
+static BtScanTestContext g_bt_scan_ctx = {0};
+
+// 前向声明
+static void BtScanDiscoveryResultCallback(const bd_addr_t *bd_addr);
+static void BtScanReadRemoteRssiCallback(const bd_addr_t *bd_addr, int rssi, int status);
+static void BtScanDiscoveryStateChangedCallback(int status);
+static void BtScanRemoteNameChangedCallback(const bd_addr_t *bd_addr, const unsigned char *deviceName, unsigned char length);
+static int BtScanAddOrUpdateDevice(const bd_addr_t *bd_addr, int rssi, const char *name, bool has_name);
+static void BtScanPrintDevices(void);
+
+/**
+ * @brief 添加或更新设备信息
+ */
+static int BtScanAddOrUpdateDevice(const bd_addr_t *bd_addr, int rssi, const char *name, bool has_name)
+{
+ if (bd_addr == NULL) {
+ return -1;
+ }
+
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+
+ // 查找是否已存在该设备
+ int found_index = -1;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ found_index = i;
+ break;
+ }
+ }
+
+ if (found_index >= 0) {
+ // 更新现有设备
+ bt_device_info_t *device = &g_bt_scan_ctx.devices[found_index];
+ if (rssi != 0) {
+ device->rssi = rssi;
+ device->has_rssi = true;
+ }
+ if (has_name && name != NULL) {
+ strncpy_s(device->name, sizeof(device->name), name, sizeof(device->name) - 1);
+ device->has_name = true;
+ }
+ } else {
+ // 添加新设备
+ if (g_bt_scan_ctx.device_count >= g_bt_scan_ctx.device_capacity) {
+ // 扩容
+ uint32_t new_capacity = (g_bt_scan_ctx.device_capacity == 0) ? 32 : g_bt_scan_ctx.device_capacity * 2;
+ bt_device_info_t *new_devices = (bt_device_info_t*)realloc(g_bt_scan_ctx.devices,
+ new_capacity * sizeof(bt_device_info_t));
+ if (new_devices == NULL) {
+ PRINT("[BtScan] Failed to reallocate device list\r\n");
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return -1;
+ }
+ g_bt_scan_ctx.devices = new_devices;
+ g_bt_scan_ctx.device_capacity = new_capacity;
+ }
+
+ bt_device_info_t *device = &g_bt_scan_ctx.devices[g_bt_scan_ctx.device_count];
+ memset_s(device, sizeof(bt_device_info_t), 0, sizeof(bt_device_info_t));
+ memcpy_s(device->addr, BD_ADDR_LEN, bd_addr->addr, BD_ADDR_LEN);
+ device->rssi = rssi;
+ device->has_rssi = (rssi != 0);
+ if (has_name && name != NULL) {
+ strncpy_s(device->name, sizeof(device->name), name, sizeof(device->name) - 1);
+ device->has_name = true;
+ } else {
+ device->name[0] = '\0';
+ device->has_name = false;
+ }
+ g_bt_scan_ctx.device_count++;
+ }
+
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return 0;
+}
+
+/**
+ * @brief 打印扫描到的设备列表
+ */
+static void BtScanPrintDevices(void)
+{
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+
+ if (g_bt_scan_ctx.device_count == 0) {
+ PRINT("[BtScan] No devices found\r\n");
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return;
+ }
+
+ PRINT("[BtScan] Found %u device(s):\r\n", g_bt_scan_ctx.device_count);
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ bt_device_info_t *device = &g_bt_scan_ctx.devices[i];
+ PRINT("[BtScan] Device[%u]: MAC=%02X:%02X:%02X:%02X:%02X:%02X, RSSI=%d dBm",
+ i + 1,
+ device->addr[5], device->addr[4], device->addr[3],
+ device->addr[2], device->addr[1], device->addr[0],
+ device->has_rssi ? device->rssi : 0);
+
+ if (device->has_name && strlen(device->name) > 0) {
+ PRINT(", Name=%s", device->name);
+ }
+ PRINT("\r\n");
+ }
+
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+}
+
+/**
+ * @brief 蓝牙设备发现回调
+ */
+static void BtScanDiscoveryResultCallback(const bd_addr_t *bd_addr)
+{
+ if (bd_addr == NULL || !g_bt_scan_ctx.is_running) {
+ return;
+ }
+
+ // 检查是否是新设备,以及是否已有名称
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ bool is_new = true;
+ bool has_name_already = false;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ is_new = false;
+ has_name_already = g_bt_scan_ctx.devices[i].has_name;
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ if (is_new) {
+ PRINT("[BtScan] New device discovered: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0]);
+ }
+
+ // 添加设备(暂时没有名称和RSSI)
+ BtScanAddOrUpdateDevice(bd_addr, 0, NULL, false);
+
+ // 尝试获取设备名称(只在设备没有名称时才获取和打印)
+ if (!has_name_already) {
+ unsigned char nameLen = BD_NAME_LEN;
+ unsigned char deviceName[BD_NAME_LEN] = {0};
+ bool getNameRet = gap_get_device_name(bd_addr, deviceName, &nameLen);
+ if (getNameRet && nameLen > 0) {
+ PRINT("[BtScan] Device name: %s\r\n", deviceName);
+ BtScanAddOrUpdateDevice(bd_addr, 0, (const char*)deviceName, true);
+ }
+ }
+
+ // 请求RSSI值(只在设备还没有RSSI时请求)
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ bool need_rssi = true;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ if (g_bt_scan_ctx.devices[i].has_rssi) {
+ need_rssi = false;
+ }
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ if (need_rssi) {
+ gap_read_remote_rssi_value(bd_addr);
+ }
+
+ // 调用原始回调(如果存在)
+ if (g_bt_scan_ctx.original_discovery_callback != NULL) {
+ g_bt_scan_ctx.original_discovery_callback(bd_addr);
+ }
+}
+
+/**
+ * @brief 蓝牙RSSI读取回调
+ */
+static void BtScanReadRemoteRssiCallback(const bd_addr_t *bd_addr, int rssi, int status)
+{
+ if (bd_addr == NULL || !g_bt_scan_ctx.is_running) {
+ return;
+ }
+
+ if (status == 0) {
+ // 检查RSSI是否有显著变化(只在新设备或RSSI变化超过5dBm时打印)
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ bool should_print = false;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ if (!g_bt_scan_ctx.devices[i].has_rssi ||
+ abs(g_bt_scan_ctx.devices[i].rssi - rssi) > 5) {
+ should_print = true;
+ }
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ if (should_print) {
+ printf("fac:[BtScan] Device: %02X:%02X:%02X:%02X:%02X:%02X, RSSI=%d dBm\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
+ rssi);
+ }
+
+ // 更新设备RSSI
+ BtScanAddOrUpdateDevice(bd_addr, rssi, NULL, false);
+ }
+ // 不打印RSSI读取失败的信息,避免日志过多
+
+ // 调用原始回调(如果存在)
+ if (g_bt_scan_ctx.original_rssi_callback != NULL) {
+ g_bt_scan_ctx.original_rssi_callback(bd_addr, rssi, status);
+ }
+}
+
+/**
+ * @brief 蓝牙扫描状态变化回调
+ */
+static void BtScanDiscoveryStateChangedCallback(int status)
+{
+ PRINT("[BtScan] Discovery state changed: %d\r\n", status);
+
+ if (g_bt_scan_ctx.is_running) {
+ // 只在扫描完成或状态变化时打印设备列表
+ if (status == 0 || status == 1) { // 扫描完成或开始
+ BtScanPrintDevices();
+ }
+
+ // 如果扫描结束,自动重新启动扫描(持续扫描)
+ if (status == 0) { // 扫描完成
+ PRINT("[BtScan] Scan completed, restarting discovery...\r\n");
+ usleep(500000); // 等待500ms后重新启动
+ gap_br_start_discovery();
+ }
+ }
+
+ // 调用原始回调(如果存在)
+ if (g_bt_scan_ctx.original_state_callback != NULL) {
+ g_bt_scan_ctx.original_state_callback(status);
+ }
+}
+
+/**
+ * @brief 蓝牙设备名称变化回调
+ */
+static void BtScanRemoteNameChangedCallback(const bd_addr_t *bd_addr, const unsigned char *deviceName, unsigned char length)
+{
+ if (bd_addr == NULL || !g_bt_scan_ctx.is_running) {
+ return;
+ }
+
+ if (deviceName != NULL && length > 0) {
+ char name[BD_NAME_LEN] = {0};
+ strncpy_s(name, sizeof(name), (const char*)deviceName,
+ (length < sizeof(name)) ? length : sizeof(name) - 1);
+
+ // 检查设备是否已有名称,避免重复打印
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ bool has_name = false;
+ bool name_changed = false;
+ for (uint32_t i = 0; i < g_bt_scan_ctx.device_count; i++) {
+ if (memcmp(g_bt_scan_ctx.devices[i].addr, bd_addr->addr, BD_ADDR_LEN) == 0) {
+ has_name = g_bt_scan_ctx.devices[i].has_name;
+ if (has_name && strcmp(g_bt_scan_ctx.devices[i].name, name) != 0) {
+ name_changed = true;
+ }
+ break;
+ }
+ }
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ // 只在设备没有名称或名称发生变化时打印
+ if (!has_name) {
+ PRINT("[BtScan] Device name: %02X:%02X:%02X:%02X:%02X:%02X, Name=%s\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
+ name);
+ } else if (name_changed) {
+ PRINT("[BtScan] Device name changed: %02X:%02X:%02X:%02X:%02X:%02X, New Name=%s\r\n",
+ bd_addr->addr[5], bd_addr->addr[4], bd_addr->addr[3],
+ bd_addr->addr[2], bd_addr->addr[1], bd_addr->addr[0],
+ name);
+ }
+
+ // 更新设备名称
+ BtScanAddOrUpdateDevice(bd_addr, 0, name, true);
+ }
+
+ // 调用原始回调(如果存在)
+ if (g_bt_scan_ctx.original_name_callback != NULL) {
+ g_bt_scan_ctx.original_name_callback(bd_addr, deviceName, length);
+ }
+}
+
+/**
+ * @brief 启动蓝牙扫描测试
+ * @return 0 成功, -1 失败
+ */
+int custom_bt_scan_test_start(void)
+{
+ PRINT("[BtScan] Starting Bluetooth scan test...\r\n");
+
+ // 先启用蓝牙栈(使用 enable_bt_stack,对应 AT^BTENABLE 指令的功能)
+ // extern errcode_t enable_bt_stack(void);
+
+ PRINT("[BtScan] Enabling Bluetooth stack (same as AT^BTENABLE)...\r\n");
+ // errcode_t bt_enable_ret = enable_bt_stack();
+ // if (bt_enable_ret != ERRCODE_SUCC && bt_enable_ret != 0) {
+ // PRINT("[BtScan] Warning: enable_bt_stack returned %d (0x%X)\r\n",
+ // bt_enable_ret, (unsigned int)bt_enable_ret);
+ // PRINT("[BtScan] Note: You may need to run AT^BTENABLE first\r\n");
+ // } else {
+ // PRINT("[BtScan] Bluetooth stack enabled successfully\r\n");
+ // }
+
+ // 等待蓝牙栈初始化完成
+ // usleep(2000000); // 2秒,确保蓝牙栈完全初始化
+ PRINT("[BtScan] Waiting for Bluetooth stack ready...\r\n");
+
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+
+ if (g_bt_scan_ctx.is_running) {
+ PRINT("[BtScan] Scan already running\r\n");
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return -1;
+ }
+
+ // 初始化互斥锁
+ if (g_bt_scan_ctx.mutex == NULL) {
+ g_bt_scan_ctx.mutex = MediaMutexCreate(NULL);
+ if (g_bt_scan_ctx.mutex == NULL) {
+ PRINT("[BtScan] Failed to create mutex\r\n");
+ return -1;
+ }
+ }
+
+ // 清空设备列表
+ if (g_bt_scan_ctx.devices != NULL) {
+ free(g_bt_scan_ctx.devices);
+ g_bt_scan_ctx.devices = NULL;
+ }
+ g_bt_scan_ctx.device_count = 0;
+ g_bt_scan_ctx.device_capacity = 0;
+
+ // 注册回调函数
+ gap_call_backs_t callbacks = {0};
+
+ // 保存原始回调(如果已注册)
+ // 注意:这里假设回调已经通过其他方式注册,我们需要获取并保存它们
+ // 由于无法直接获取已注册的回调,我们直接设置我们的回调
+ callbacks.discovery_result_callback = BtScanDiscoveryResultCallback;
+ callbacks.read_remote_rssi_event_callback = BtScanReadRemoteRssiCallback;
+ callbacks.discovery_state_changed_callback = BtScanDiscoveryStateChangedCallback;
+ callbacks.remote_name_changed_callback = BtScanRemoteNameChangedCallback;
+
+ // 注册回调函数(返回值0表示成功)
+ int ret = gap_register_callbacks(&callbacks);
+ if (ret != 0) {
+ PRINT("[BtScan] Failed to register callbacks: %d\r\n", ret);
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return -1;
+ }
+
+ // 检查是否已经在扫描,如果是则先停止
+ bool is_discovering = is_bt_discovering(BT_TRANSPORT_BR_EDR);
+ if (is_discovering) {
+ PRINT("[BtScan] Bluetooth is already discovering, canceling first...\r\n");
+ gap_br_cancel_discovery();
+ // 等待一小段时间让扫描完全停止
+ usleep(200000); // 200ms
+ }
+
+ // 设置扫描参数(扫描所有设备类型,最多20个设备)
+ // 参考 custom_factory_bt_scan_start 的实现
+ errcode_t err = gap_br_set_inquiry_paramters(0, 20);
+ if (err != ERRCODE_SUCC) {
+ PRINT("[BtScan] Warning: Failed to set inquiry parameters: %d (0x%X)\r\n",
+ err, (unsigned int)err);
+ // 继续尝试启动扫描(参考其他代码实现,即使设置参数失败也继续)
+ } else {
+ PRINT("[BtScan] Inquiry parameters set successfully\r\n");
+ }
+
+ // 启动扫描(参考 custom_factory_bt_scan_start 的实现)
+ bool scan_ret = gap_br_start_discovery();
+ if (!scan_ret) {
+ PRINT("[BtScan] Failed to start discovery\r\n");
+ PRINT("[BtScan] Note: This may indicate Bluetooth stack is not fully ready\r\n");
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return -1;
+ }
+
+ PRINT("[BtScan] Discovery started successfully\r\n");
+
+ g_bt_scan_ctx.is_running = true;
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ PRINT("[BtScan] Bluetooth scan started successfully\r\n");
+ PRINT("[BtScan] Scanning for devices...\r\n");
+
+ return 0;
+}
+
+/**
+ * @brief 停止蓝牙扫描测试
+ * @return 0 成功, -1 失败
+ */
+int custom_bt_scan_test_stop(void)
+{
+ PRINT("[BtScan] Stopping Bluetooth scan test...\r\n");
+
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+
+ if (!g_bt_scan_ctx.is_running) {
+ PRINT("[BtScan] Scan not running\r\n");
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return 0;
+ }
+
+ // 停止扫描
+ bool ret = gap_br_cancel_discovery();
+ if (!ret) {
+ PRINT("[BtScan] Failed to cancel discovery\r\n");
+ }
+
+ // 打印最终结果
+ PRINT("[BtScan] Final scan results:\r\n");
+ BtScanPrintDevices();
+
+ // 清理设备列表
+ if (g_bt_scan_ctx.devices != NULL) {
+ free(g_bt_scan_ctx.devices);
+ g_bt_scan_ctx.devices = NULL;
+ }
+ g_bt_scan_ctx.device_count = 0;
+ g_bt_scan_ctx.device_capacity = 0;
+
+ g_bt_scan_ctx.is_running = false;
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+
+ PRINT("[BtScan] Bluetooth scan stopped\r\n");
+
+ return 0;
+}
+
+/**
+ * @brief 获取扫描测试状态
+ * @return true 正在运行, false 未运行
+ */
+bool custom_bt_scan_test_is_running(void)
+{
+ MediaMutexLock(g_bt_scan_ctx.mutex);
+ bool is_running = g_bt_scan_ctx.is_running;
+ MediaMutexUnLock(g_bt_scan_ctx.mutex);
+ return is_running;
+}
+
+/**
+ * @brief 初始化蓝牙扫描测试模块
+ */
+void custom_bt_scan_test_init(void)
+{
+ if (g_bt_scan_ctx.mutex == NULL) {
+ g_bt_scan_ctx.mutex = MediaMutexCreate(NULL);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+