/* * 自然写互动课堂教学管理网关软件 V1.0 * ble_manager.c - BLE多连接管理器 * * 功能说明: * 1. 基于BlueZ D-Bus接口的BLE多设备管理 * 2. 自动扫描与连接自然写点阵笔(最多60支) * 3. GATT服务发现与特征值通知订阅 * 4. BLE数据接收与分发 * 5. 断线自动重连机制 * 6. BLE适配器状态监控 */ #include #include #include #include #include #include #include /* BlueZ D-Bus头文件 */ #include #include #include /* 模块头文件 */ #include "ble_manager.h" #include "ring_buffer.h" /* ========== 常量定义 ========== */ /* 自然写笔GATT服务UUID */ #define PEN_SERVICE_UUID "0000ffe0-0000-1000-8000-00805f9b34fb" /* 笔迹数据特征值UUID */ #define STROKE_CHAR_UUID "0000ffe1-0000-1000-8000-00805f9b34fb" /* 最大同时连接设备数 */ #define MAX_BLE_CONNECTIONS 60 /* 扫描间隔(毫秒) */ #define SCAN_INTERVAL_MS 10000 /* 重连延迟(秒) */ #define RECONNECT_DELAY_SEC 5 /* ========== 数据结构 ========== */ /* BLE设备连接信息 */ typedef struct { char mac_address[18]; /* MAC地址 "AA:BB:CC:DD:EE:FF" */ char device_name[64]; /* 设备名称 */ int connection_handle; /* 连接句柄 */ int is_connected; /* 是否已连接 */ int is_subscribed; /* 是否已订阅通知 */ int gatt_handle; /* GATT特征值句柄 */ int rssi; /* 信号强度 */ unsigned long last_data_time; /* 最后收到数据的时间 */ int reconnect_attempts; /* 重连尝试次数 */ char bound_student_id[32]; /* 绑定的学生ID */ } BLEDevice; /* BLE管理器状态 */ typedef struct { int hci_dev_id; /* HCI设备ID */ int hci_socket; /* HCI套接字 */ int is_scanning; /* 是否正在扫描 */ int is_active; /* 管理器是否活跃 */ BLEDevice devices[MAX_BLE_CONNECTIONS]; /* 设备列表 */ int device_count; /* 已连接设备数 */ pthread_mutex_t mutex; /* 线程安全锁 */ pthread_t scan_thread; /* 扫描线程 */ pthread_t recv_thread; /* 数据接收线程 */ int event_pipe[2]; /* 事件通知管道 */ } BLEManager; /* ========== 静态变量 ========== */ static BLEManager g_ble; /* 数据回调函数指针 */ static void (*g_data_callback)(const char *mac, const uint8_t *data, int len) = NULL; /* ========== 初始化 ========== */ /** * 初始化BLE管理器 * 打开HCI设备,配置扫描参数 * * @return 0成功, -1失败 */ int ble_manager_init(void) { memset(&g_ble, 0, sizeof(g_ble)); pthread_mutex_init(&g_ble.mutex, NULL); /* 创建事件通知管道 */ if (pipe(g_ble.event_pipe) < 0) { syslog(LOG_ERR, "BLE: 创建事件管道失败: %s", strerror(errno)); return -1; } /* 打开默认HCI蓝牙适配器 */ g_ble.hci_dev_id = hci_get_route(NULL); if (g_ble.hci_dev_id < 0) { syslog(LOG_ERR, "BLE: 未找到蓝牙适配器"); return -1; } g_ble.hci_socket = hci_open_dev(g_ble.hci_dev_id); if (g_ble.hci_socket < 0) { syslog(LOG_ERR, "BLE: 打开HCI设备失败: %s", strerror(errno)); return -1; } g_ble.is_active = 1; /* 启动扫描线程 */ pthread_create(&g_ble.scan_thread, NULL, scan_thread_func, NULL); /* 启动数据接收线程 */ pthread_create(&g_ble.recv_thread, NULL, recv_thread_func, NULL); syslog(LOG_INFO, "BLE管理器初始化完成,适配器ID=%d", g_ble.hci_dev_id); return 0; } /* ========== 设备扫描 ========== */ /** * 扫描线程函数 * 周期性扫描BLE设备,发现新的自然写点阵笔后自动连接 */ static void *scan_thread_func(void *arg) { (void)arg; syslog(LOG_INFO, "BLE: 扫描线程启动"); while (g_ble.is_active) { /* 检查是否还有连接名额 */ pthread_mutex_lock(&g_ble.mutex); int current_count = g_ble.device_count; pthread_mutex_unlock(&g_ble.mutex); if (current_count < MAX_BLE_CONNECTIONS) { /* 执行LE扫描 */ perform_le_scan(); } /* 检查需要重连的设备 */ check_reconnect(); /* 扫描间隔 */ usleep(SCAN_INTERVAL_MS * 1000); } syslog(LOG_INFO, "BLE: 扫描线程退出"); return NULL; } /** * 执行BLE低功耗扫描 * 使用HCI LE扫描命令搜索附近的BLE设备 */ static void perform_le_scan(void) { /* 设置LE扫描参数 */ uint8_t scan_type = 0x01; /* 主动扫描 */ uint16_t scan_interval = 0x0010; /* 扫描间隔 */ uint16_t scan_window = 0x0010; /* 扫描窗口 */ uint8_t own_type = 0x00; /* 公共地址 */ uint8_t filter = 0x00; /* 不过滤 */ int ret = hci_le_set_scan_parameters(g_ble.hci_socket, scan_type, scan_interval, scan_window, own_type, filter, 1000); if (ret < 0) { syslog(LOG_WARNING, "BLE: 设置扫描参数失败"); return; } /* 启动扫描 */ ret = hci_le_set_scan_enable(g_ble.hci_socket, 0x01, 0x00, 1000); if (ret < 0) { syslog(LOG_WARNING, "BLE: 启动扫描失败"); return; } g_ble.is_scanning = 1; /* 扫描持续3秒 */ struct hci_filter flt; hci_filter_clear(&flt); hci_filter_set_ptype(HCI_EVENT_PKT, &flt); hci_filter_set_event(EVT_LE_META_EVENT, &flt); setsockopt(g_ble.hci_socket, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)); /* 读取扫描结果 */ uint8_t buf[256]; int scan_duration_ms = 3000; int elapsed = 0; while (elapsed < scan_duration_ms && g_ble.is_active) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; /* 100ms超时 */ fd_set rfds; FD_ZERO(&rfds); FD_SET(g_ble.hci_socket, &rfds); ret = select(g_ble.hci_socket + 1, &rfds, NULL, NULL, &tv); if (ret > 0) { int len = read(g_ble.hci_socket, buf, sizeof(buf)); if (len > 0) { process_scan_result(buf, len); } } elapsed += 100; } /* 停止扫描 */ hci_le_set_scan_enable(g_ble.hci_socket, 0x00, 0x00, 1000); g_ble.is_scanning = 0; } /** * 处理扫描结果 * 解析广播包,筛选包含自然写服务UUID的设备 */ static void process_scan_result(const uint8_t *data, int len) { if (len < 14) return; /* 解析HCI LE Meta事件 */ evt_le_meta_event *meta = (evt_le_meta_event *)(data + 1 + HCI_EVENT_HDR_SIZE); if (meta->subevent != 0x02) return; /* 非广播报告 */ le_advertising_info *info = (le_advertising_info *)(meta->data + 1); /* 提取MAC地址 */ char mac[18]; ba2str(&info->bdaddr, mac); /* 检查是否已连接 */ if (find_device_by_mac(mac) >= 0) { return; /* 已连接,跳过 */ } /* 检查广播数据中是否包含自然写服务UUID */ if (check_service_uuid(info->data, info->length)) { syslog(LOG_INFO, "BLE: 发现自然写笔 %s", mac); /* 尝试连接 */ connect_device(mac); } } /** * 检查广播数据中是否包含指定服务UUID */ static int check_service_uuid(const uint8_t *ad_data, int ad_len) { int offset = 0; while (offset < ad_len) { uint8_t field_len = ad_data[offset]; if (field_len == 0) break; uint8_t field_type = ad_data[offset + 1]; /* 0x06 或 0x07:128位服务UUID列表 */ if ((field_type == 0x06 || field_type == 0x07) && field_len >= 17) { /* 比较UUID(简化:只比较前4字节特征值) */ if (ad_data[offset + 2] == 0xFB && ad_data[offset + 3] == 0x34 && ad_data[offset + 4] == 0x9B && ad_data[offset + 5] == 0x5F) { return 1; /* 匹配自然写服务UUID */ } } offset += field_len + 1; } return 0; } /* ========== 设备连接 ========== */ /** * 连接到指定MAC地址的BLE设备 */ static int connect_device(const char *mac) { pthread_mutex_lock(&g_ble.mutex); if (g_ble.device_count >= MAX_BLE_CONNECTIONS) { pthread_mutex_unlock(&g_ble.mutex); return -1; } /* 查找空闲槽位 */ int slot = -1; int i; for (i = 0; i < MAX_BLE_CONNECTIONS; i++) { if (!g_ble.devices[i].is_connected) { slot = i; break; } } if (slot < 0) { pthread_mutex_unlock(&g_ble.mutex); return -1; } /* 解析MAC地址 */ bdaddr_t bdaddr; str2ba(mac, &bdaddr); /* 创建LE连接 */ uint16_t handle = 0; int ret = hci_le_create_conn(g_ble.hci_socket, 0x0060, /* scan interval */ 0x0030, /* scan window */ 0x00, /* initiator filter */ 0x00, /* peer addr type: public */ bdaddr, /* peer address */ 0x00, /* own addr type */ 0x0028, /* min conn interval */ 0x0038, /* max conn interval */ 0x0000, /* latency */ 0x002A, /* supervision timeout */ 0x0000, /* min CE length */ 0x0000, /* max CE length */ &handle, 10000); if (ret < 0) { syslog(LOG_WARNING, "BLE: 连接 %s 失败: %s", mac, strerror(errno)); pthread_mutex_unlock(&g_ble.mutex); return -1; } /* 填充设备信息 */ BLEDevice *dev = &g_ble.devices[slot]; strncpy(dev->mac_address, mac, sizeof(dev->mac_address) - 1); dev->connection_handle = handle; dev->is_connected = 1; dev->reconnect_attempts = 0; dev->last_data_time = time(NULL); g_ble.device_count++; pthread_mutex_unlock(&g_ble.mutex); syslog(LOG_INFO, "BLE: 已连接 %s (handle=%d, 总数=%d)", mac, handle, g_ble.device_count); /* 发现GATT服务并订阅通知 */ discover_and_subscribe(dev); return 0; } /* ========== GATT服务发现 ========== */ /** * 发现GATT服务并订阅笔迹数据通知 */ static void discover_and_subscribe(BLEDevice *dev) { /* 简化实现:直接使用已知的特征值句柄 */ /* 实际产品中需要完整的GATT服务发现流程 */ dev->gatt_handle = 0x0025; /* 笔迹数据特征值句柄 */ /* 写入CCCD描述符启用通知(句柄+1是CCCD) */ uint8_t enable_notify[] = {0x01, 0x00}; struct bt_att_pdu pdu; pdu.opcode = BT_ATT_OP_WRITE_REQ; pdu.handle = dev->gatt_handle + 1; memcpy(pdu.data, enable_notify, 2); /* 发送ATT写请求 */ /* hci_send_cmd(...) - 简化 */ dev->is_subscribed = 1; syslog(LOG_INFO, "BLE: 已订阅 %s 的笔迹通知", dev->mac_address); } /* ========== 数据接收 ========== */ /** * 数据接收线程 * 持续读取HCI事件,解析GATT通知中的笔迹数据 */ static void *recv_thread_func(void *arg) { (void)arg; uint8_t buf[256]; syslog(LOG_INFO, "BLE: 数据接收线程启动"); while (g_ble.is_active) { int len = read(g_ble.hci_socket, buf, sizeof(buf)); if (len <= 0) { usleep(1000); continue; } /* 解析HCI事件 */ uint8_t event_type = buf[1]; if (event_type == HCI_EVENT_PKT) { /* GATT通知数据 */ process_gatt_notification(buf, len); } else if (event_type == EVT_DISCONN_COMPLETE) { /* 连接断开事件 */ process_disconnect_event(buf, len); } } syslog(LOG_INFO, "BLE: 数据接收线程退出"); return NULL; } /** * 处理GATT通知(笔迹数据) */ static void process_gatt_notification(const uint8_t *data, int len) { if (len < 10) return; /* 提取连接句柄 */ uint16_t handle = data[4] | (data[5] << 8); /* 查找对应设备 */ BLEDevice *dev = find_device_by_handle(handle); if (dev == NULL) return; /* 提取笔迹数据载荷 */ const uint8_t *payload = data + 9; int payload_len = len - 9; dev->last_data_time = time(NULL); /* 将数据放入环形缓冲区(供协议转换器消费) */ ring_buffer_write_with_header(dev->mac_address, payload, payload_len); /* 调用外部回调 */ if (g_data_callback) { g_data_callback(dev->mac_address, payload, payload_len); } } /* ========== 辅助函数 ========== */ static int find_device_by_mac(const char *mac) { int i; for (i = 0; i < MAX_BLE_CONNECTIONS; i++) { if (g_ble.devices[i].is_connected && strcmp(g_ble.devices[i].mac_address, mac) == 0) { return i; } } return -1; } static BLEDevice *find_device_by_handle(uint16_t handle) { int i; for (i = 0; i < MAX_BLE_CONNECTIONS; i++) { if (g_ble.devices[i].is_connected && g_ble.devices[i].connection_handle == handle) { return &g_ble.devices[i]; } } return NULL; } static void check_reconnect(void) { int i; time_t now = time(NULL); for (i = 0; i < MAX_BLE_CONNECTIONS; i++) { BLEDevice *dev = &g_ble.devices[i]; if (!dev->is_connected && dev->mac_address[0] != '\0' && dev->reconnect_attempts < 10) { if (now - dev->last_data_time > RECONNECT_DELAY_SEC) { syslog(LOG_INFO, "BLE: 尝试重连 %s (第%d次)", dev->mac_address, dev->reconnect_attempts + 1); connect_device(dev->mac_address); dev->reconnect_attempts++; } } } } /* ========== 外部接口 ========== */ int ble_manager_get_fd(void) { return g_ble.event_pipe[0]; } int ble_manager_is_active(void) { return g_ble.is_active; } int ble_manager_get_connected_count(void) { return g_ble.device_count; } void ble_manager_process_events(void) { uint8_t dummy; read(g_ble.event_pipe[0], &dummy, 1); } void ble_manager_set_data_callback(void (*cb)(const char *, const uint8_t *, int)) { g_data_callback = cb; } void ble_manager_cleanup(void) { g_ble.is_active = 0; pthread_join(g_ble.scan_thread, NULL); pthread_join(g_ble.recv_thread, NULL); /* 断开所有设备 */ int i; for (i = 0; i < MAX_BLE_CONNECTIONS; i++) { if (g_ble.devices[i].is_connected) { hci_disconnect(g_ble.hci_socket, g_ble.devices[i].connection_handle, 0x13, 1000); } } close(g_ble.hci_socket); close(g_ble.event_pipe[0]); close(g_ble.event_pipe[1]); pthread_mutex_destroy(&g_ble.mutex); syslog(LOG_INFO, "BLE管理器已清理"); }