software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,523 @@
/*
* 自然写互动课堂教学管理网关软件 V1.0
* ble_manager.c - BLE多连接管理器
*
* 功能说明:
* 1. 基于BlueZ D-Bus接口的BLE多设备管理
* 2. 自动扫描与连接自然写点阵笔(最多60支)
* 3. GATT服务发现与特征值通知订阅
* 4. BLE数据接收与分发
* 5. 断线自动重连机制
* 6. BLE适配器状态监控
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <syslog.h>
/* BlueZ D-Bus头文件 */
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
/* 模块头文件 */
#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 或 0x07128位服务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管理器已清理");
}