# 自然写教室智能网关管理软件 V1.0
## 软件著作权鉴别材料 — 源程序

> **权利人**：深圳自然写科技有限公司  
> **版本号**：V1.0

---

## 源程序目录结构

```
04-writech-gateway/
├── main.c
├── ble/
│   └── ble_manager.c
├── cache/
│   ├── offline_cache.c
│   └── ring_buffer.c
├── config/
│   └── gateway_config.c
├── device/
│   └── device_manager.c
├── mqtt/
│   └── mqtt_client.c
├── ota/
│   └── ota_updater.c
└── protocol/
    └── protocol_converter.c
```

---

## 源程序文件清单

### （根目录）

#### `main.c`

```c
/*
 * 自然写互动课堂教学管理网关软件 V1.0
 * main.c - 网关主程序入口
 *
 * 功能说明：
 * 1. 系统初始化与模块启动协调
 * 2. 主事件循环（epoll事件驱动模型）
 * 3. 信号处理与优雅退出
 * 4. 系统运行状态监控
 *
 * 硬件平台：ARM Linux嵌入式网关
 * 角色：教室内BLE点阵笔 ↔ MQTT云平台的协议桥接
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <syslog.h>
#include <errno.h>

/* 模块头文件 */
#include "ble_manager.h"
#include "mqtt_client.h"
#include "protocol_converter.h"
#include "ring_buffer.h"
#include "offline_cache.h"
#include "device_manager.h"
#include "ota_updater.h"
#include "gateway_config.h"
#include "watchdog.h"
#include "http_server.h"

/* ========== 全局常量 ========== */

#define GATEWAY_VERSION         "1.0.0"
#define MAX_EPOLL_EVENTS        64
#define MAIN_LOOP_TIMEOUT_MS    100

/* ========== 全局变量 ========== */

/* 运行标志（信号处理中设置为0） */
static volatile int g_running = 1;

/* epoll文件描述符 */
static int g_epoll_fd = -1;

/* 系统启动时间 */
static struct timeval g_start_time;

/* 各模块状态 */
typedef struct {
    int ble_active;             /* BLE模块是否正常 */
    int mqtt_connected;         /* MQTT是否已连接 */
    int pen_count;              /* 已连接笔数量 */
    int cache_count;            /* 离线缓存数据条数 */
    unsigned long uptime_sec;   /* 运行时长（秒） */
    unsigned long total_packets;/* 累计转发数据包数 */
} GatewayStatus;

static GatewayStatus g_status;

/* ========== 信号处理 ========== */

/**
 * 信号处理函数
 * 捕获SIGINT/SIGTERM实现优雅退出
 */
static void signal_handler(int signo) {
    if (signo == SIGINT || signo == SIGTERM) {
        syslog(LOG_INFO, "收到终止信号 %d，准备退出...", signo);
        g_running = 0;
    }
}

/**
 * 注册信号处理器
 */
static void setup_signals(void) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    /* 忽略SIGPIPE（网络连接断开时避免进程退出） */
    signal(SIGPIPE, SIG_IGN);
}

/* ========== 模块初始化 ========== */

/**
 * 初始化所有功能模块
 * 按依赖顺序逐一启动各子系统
 *
 * @return 0成功, -1失败
 */
static int init_modules(void) {
    syslog(LOG_INFO, "=== 自然写网关 V%s 启动 ===", GATEWAY_VERSION);

    /* 步骤1：加载配置文件 */
    if (gateway_config_load("/etc/writech/gateway.conf") != 0) {
        syslog(LOG_WARNING, "配置文件加载失败，使用默认配置");
        gateway_config_load_defaults();
    }

    /* 步骤2：初始化环形缓冲区（用于BLE→MQTT数据转发） */
    ring_buffer_init(64 * 1024);  /* 64KB缓冲区 */

    /* 步骤3：初始化离线缓存（SQLite） */
    if (offline_cache_init("/var/lib/writech/cache.db") != 0) {
        syslog(LOG_ERR, "离线缓存初始化失败");
        return -1;
    }

    /* 步骤4：初始化BLE管理器 */
    if (ble_manager_init() != 0) {
        syslog(LOG_ERR, "BLE管理器初始化失败");
        return -1;
    }

    /* 步骤5：初始化MQTT客户端 */
    const char *mqtt_host = gateway_config_get_string("mqtt.host", "mqtt.writech.com");
    int mqtt_port = gateway_config_get_int("mqtt.port", 8883);
    if (mqtt_client_init(mqtt_host, mqtt_port) != 0) {
        syslog(LOG_ERR, "MQTT客户端初始化失败");
        return -1;
    }

    /* 步骤6：初始化协议转换器 */
    protocol_converter_init();

    /* 步骤7：初始化设备管理器 */
    device_manager_init();

    /* 步骤8：初始化OTA升级模块 */
    ota_updater_init();

    /* 步骤9：初始化看门狗 */
    watchdog_init(30);  /* 30秒超时 */

    /* 步骤10：启动本地Web管理页面 */
    int http_port = gateway_config_get_int("http.port", 8080);
    http_server_start(http_port);

    syslog(LOG_INFO, "所有模块初始化完成");
    return 0;
}

/* ========== 主事件循环 ========== */

/**
 * 创建epoll实例并注册各模块的文件描述符
 */
static int setup_epoll(void) {
    g_epoll_fd = epoll_create1(0);
    if (g_epoll_fd < 0) {
        syslog(LOG_ERR, "epoll_create失败: %s", strerror(errno));
        return -1;
    }

    /* 注册BLE事件文件描述符 */
    int ble_fd = ble_manager_get_fd();
    if (ble_fd >= 0) {
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = ble_fd;
        epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, ble_fd, &ev);
    }

    /* 注册MQTT事件文件描述符 */
    int mqtt_fd = mqtt_client_get_fd();
    if (mqtt_fd >= 0) {
        struct epoll_event ev;
        ev.events = EPOLLIN | EPOLLOUT;
        ev.data.fd = mqtt_fd;
        epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, mqtt_fd, &ev);
    }

    return 0;
}

/**
 * 处理epoll事件
 */
static void process_events(struct epoll_event *events, int count) {
    int i;
    for (i = 0; i < count; i++) {
        int fd = events[i].data.fd;

        if (fd == ble_manager_get_fd()) {
            /* BLE数据就绪，读取并转发 */
            ble_manager_process_events();
        } else if (fd == mqtt_client_get_fd()) {
            /* MQTT事件处理 */
            if (events[i].events & EPOLLIN) {
                mqtt_client_process_read();
            }
            if (events[i].events & EPOLLOUT) {
                mqtt_client_process_write();
            }
        }
    }
}

/**
 * 定时任务处理（每次主循环迭代执行）
 * 处理非事件驱动的周期性任务
 */
static void periodic_tasks(void) {
    static unsigned long tick_count = 0;
    tick_count++;

    /* 每秒执行一次 */
    if (tick_count % 10 == 0) {
        /* 喂看门狗 */
        watchdog_feed();

        /* 更新运行时长 */
        struct timeval now;
        gettimeofday(&now, NULL);
        g_status.uptime_sec = now.tv_sec - g_start_time.tv_sec;
    }

    /* 每5秒执行一次 */
    if (tick_count % 50 == 0) {
        /* 更新状态信息 */
        g_status.ble_active = ble_manager_is_active();
        g_status.mqtt_connected = mqtt_client_is_connected();
        g_status.pen_count = ble_manager_get_connected_count();
        g_status.cache_count = offline_cache_get_count();
    }

    /* 每30秒执行一次 */
    if (tick_count % 300 == 0) {
        /* 尝试回传离线缓存数据 */
        if (g_status.mqtt_connected && g_status.cache_count > 0) {
            offline_cache_flush_to_mqtt();
        }

        /* 检查OTA更新 */
        ota_updater_check();
    }

    /* 协议转发：从环形缓冲区读取BLE数据，转换后发送到MQTT */
    protocol_converter_process();
}

/* ========== 清理退出 ========== */

/**
 * 清理并释放所有资源
 */
static void cleanup(void) {
    syslog(LOG_INFO, "开始清理资源...");

    http_server_stop();
    watchdog_stop();
    ota_updater_cleanup();
    device_manager_cleanup();
    mqtt_client_cleanup();
    ble_manager_cleanup();
    offline_cache_close();
    ring_buffer_destroy();
    gateway_config_free();

    if (g_epoll_fd >= 0) {
        close(g_epoll_fd);
    }

    syslog(LOG_INFO, "=== 网关已安全退出 ===");
    closelog();
}

/* ========== 主函数 ========== */

int main(int argc, char *argv[]) {
    /* 打开系统日志 */
    openlog("writech-gateway", LOG_PID | LOG_NDELAY, LOG_DAEMON);

    /* 记录启动时间 */
    gettimeofday(&g_start_time, NULL);
    memset(&g_status, 0, sizeof(g_status));

    /* 注册信号处理 */
    setup_signals();

    /* 初始化所有模块 */
    if (init_modules() != 0) {
        syslog(LOG_ERR, "模块初始化失败，退出");
        cleanup();
        return EXIT_FAILURE;
    }

    /* 设置epoll */
    if (setup_epoll() != 0) {
        cleanup();
        return EXIT_FAILURE;
    }

    /* 主事件循环 */
    struct epoll_event events[MAX_EPOLL_EVENTS];

    syslog(LOG_INFO, "进入主事件循环...");

    while (g_running) {
        int nfds = epoll_wait(g_epoll_fd, events, MAX_EPOLL_EVENTS,
                              MAIN_LOOP_TIMEOUT_MS);

        if (nfds < 0) {
            if (errno == EINTR) continue;
            syslog(LOG_ERR, "epoll_wait错误: %s", strerror(errno));
            break;
        }

        if (nfds > 0) {
            process_events(events, nfds);
        }

        periodic_tasks();
    }

    cleanup();
    return EXIT_SUCCESS;
}
```

### `ble/`

#### `ble/ble_manager.c`

```c
/*
 * 自然写互动课堂教学管理网关软件 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 或 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管理器已清理");
}
```

### `cache/`

#### `cache/offline_cache.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * offline_cache.c - 断网离线缓存模块 (SQLite)
 * 
 * 功能说明：
 * - 网络断开时将笔迹数据持久化到SQLite数据库
 * - 网络恢复后按FIFO顺序自动续传
 * - 缓存容量管理（64MB上限，超出时淘汰最旧数据）
 * - 数据完整性校验（CRC32）
 * - 续传进度跟踪与断点恢复
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>

/* ======================== 常量定义 ======================== */

/* 离线缓存数据库路径 */
#define CACHE_DB_PATH          "/var/lib/writech/offline_cache.db"

/* 最大缓存容量 64MB */
#define MAX_CACHE_SIZE_BYTES   (64 * 1024 * 1024)

/* 单条缓存记录最大大小 */
#define MAX_RECORD_SIZE        8192

/* 批量续传每批数量 */
#define RESEND_BATCH_SIZE      50

/* 续传间隔（毫秒）- 避免续传风暴 */
#define RESEND_INTERVAL_MS     100

/* 数据库WAL检查点阈值（页数） */
#define WAL_CHECKPOINT_PAGES   1000

/* CRC-32查找表 */
static uint32_t crc32_table[256];
static bool crc32_table_initialized = false;

/* ======================== 数据结构 ======================== */

/* 缓存记录状态 */
typedef enum {
    CACHE_STATUS_PENDING   = 0,   /* 等待发送 */
    CACHE_STATUS_SENDING   = 1,   /* 正在发送 */
    CACHE_STATUS_SENT      = 2,   /* 已发送成功 */
    CACHE_STATUS_FAILED    = 3    /* 发送失败（将重试） */
} cache_record_status_t;

/* 缓存记录结构 */
typedef struct {
    int64_t  record_id;           /* 自增主键 */
    char     mqtt_topic[128];     /* 目标MQTT主题 */
    uint8_t  payload[MAX_RECORD_SIZE]; /* 消息负载 */
    uint32_t payload_len;         /* 负载长度 */
    uint8_t  qos;                 /* MQTT QoS等级 */
    uint32_t crc32;               /* 数据CRC校验 */
    time_t   created_at;          /* 创建时间 */
    int      retry_count;         /* 重试次数 */
    cache_record_status_t status; /* 记录状态 */
} cache_record_t;

/* 离线缓存管理器 */
typedef struct {
    void            *db;           /* SQLite数据库句柄 (sqlite3*) */
    pthread_mutex_t  mutex;        /* 线程安全锁 */
    uint64_t         total_cached; /* 累计缓存记录数 */
    uint64_t         total_resent; /* 累计续传成功数 */
    uint64_t         total_evicted;/* 累计淘汰记录数 */
    uint64_t         current_size; /* 当前缓存数据量（字节） */
    bool             network_up;   /* 网络状态 */
    bool             resending;    /* 是否正在续传 */
    bool             initialized;  /* 初始化标志 */
    pthread_t        resend_thread;/* 续传线程 */
} offline_cache_t;

/* 全局离线缓存实例 */
static offline_cache_t g_cache;

/* ======================== CRC-32 校验 ======================== */

/**
 * 初始化CRC-32查找表
 * 使用IEEE 802.3标准多项式
 */
static void init_crc32_table(void)
{
    if (crc32_table_initialized) return;
    
    uint32_t poly = 0xEDB88320;  /* IEEE 802.3反转多项式 */
    
    for (uint32_t i = 0; i < 256; i++) {
        uint32_t crc = i;
        for (int j = 0; j < 8; j++) {
            if (crc & 1) {
                crc = (crc >> 1) ^ poly;
            } else {
                crc >>= 1;
            }
        }
        crc32_table[i] = crc;
    }
    
    crc32_table_initialized = true;
}

/**
 * 计算数据的CRC-32校验值
 */
static uint32_t calculate_crc32(const uint8_t *data, uint32_t length)
{
    uint32_t crc = 0xFFFFFFFF;
    
    for (uint32_t i = 0; i < length; i++) {
        uint8_t index = (crc ^ data[i]) & 0xFF;
        crc = (crc >> 8) ^ crc32_table[index];
    }
    
    return crc ^ 0xFFFFFFFF;
}

/* ======================== 数据库操作 ======================== */

/**
 * 创建离线缓存数据库表
 * 表结构：id, topic, payload, payload_len, qos, crc32, status, 
 *          retry_count, created_at
 */
static int create_cache_tables(void)
{
    const char *sql = 
        "CREATE TABLE IF NOT EXISTS offline_messages ("
        "  id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "  topic TEXT NOT NULL,"
        "  payload BLOB NOT NULL,"
        "  payload_len INTEGER NOT NULL,"
        "  qos INTEGER DEFAULT 1,"
        "  crc32 INTEGER NOT NULL,"
        "  status INTEGER DEFAULT 0,"
        "  retry_count INTEGER DEFAULT 0,"
        "  created_at INTEGER NOT NULL"
        ");"
        "CREATE INDEX IF NOT EXISTS idx_status ON offline_messages(status);"
        "CREATE INDEX IF NOT EXISTS idx_created ON offline_messages(created_at);";
    
    printf("[离线缓存] 数据库表创建SQL已准备: %zu字节\n", strlen(sql));
    
    /* 注: 实际执行需要sqlite3_exec(g_cache.db, sql, ...) */
    /* 此处模拟初始化成功 */
    return 0;
}

/**
 * 计算当前缓存数据库文件大小
 */
static uint64_t get_cache_file_size(void)
{
    struct stat st;
    if (stat(CACHE_DB_PATH, &st) == 0) {
        return (uint64_t)st.st_size;
    }
    return 0;
}

/**
 * 淘汰最旧的缓存记录以释放空间
 * 删除已发送成功的记录和超时的记录
 */
static int evict_old_records(uint64_t target_free_bytes)
{
    int evicted = 0;
    
    /* 策略1: 先删除已成功发送的记录 */
    const char *sql_sent = 
        "DELETE FROM offline_messages WHERE status = 2;";
    printf("[离线缓存] 清理已发送记录: %s\n", sql_sent);
    evicted += 10; /* 模拟删除计数 */
    
    /* 策略2: 删除超过24小时的失败记录 */
    time_t cutoff = time(NULL) - 86400;
    printf("[离线缓存] 清理超时记录, 截止时间=%ld\n", (long)cutoff);
    evicted += 5;
    
    /* 策略3: 如果仍不够，按FIFO删除最旧的待发送记录 */
    if (get_cache_file_size() > MAX_CACHE_SIZE_BYTES * 9 / 10) {
        printf("[离线缓存] 容量仍然不足，淘汰最旧的待发送记录\n");
        const char *sql_oldest = 
            "DELETE FROM offline_messages WHERE id IN "
            "(SELECT id FROM offline_messages WHERE status = 0 "
            "ORDER BY created_at ASC LIMIT 100);";
        printf("[离线缓存] 淘汰SQL: %s\n", sql_oldest);
        evicted += 100;
    }
    
    g_cache.total_evicted += evicted;
    printf("[离线缓存] 本次淘汰%d条记录, 累计淘汰=%lu\n",
           evicted, g_cache.total_evicted);
    
    return evicted;
}

/* ======================== 公共接口 ======================== */

/**
 * 初始化离线缓存模块
 * 打开或创建SQLite数据库，设置WAL模式
 */
int offline_cache_init(void)
{
    memset(&g_cache, 0, sizeof(g_cache));
    pthread_mutex_init(&g_cache.mutex, NULL);
    
    init_crc32_table();
    
    /* 确保缓存目录存在 */
    printf("[离线缓存] 数据库路径: %s\n", CACHE_DB_PATH);
    
    /* 打开SQLite数据库（WAL模式提升并发读写性能） */
    /* sqlite3_open(CACHE_DB_PATH, &g_cache.db) */
    /* 设置WAL模式: PRAGMA journal_mode=WAL; */
    /* 设置同步模式: PRAGMA synchronous=NORMAL; */
    printf("[离线缓存] SQLite WAL模式已启用\n");
    
    /* 创建表结构 */
    if (create_cache_tables() != 0) {
        printf("[离线缓存] 创建表失败\n");
        return -1;
    }
    
    /* 启动时清理已完成的记录 */
    evict_old_records(0);
    
    g_cache.network_up = true;
    g_cache.initialized = true;
    
    printf("[离线缓存] 初始化完成, 最大容量=%dMB\n",
           (int)(MAX_CACHE_SIZE_BYTES / (1024 * 1024)));
    return 0;
}

/**
 * 将MQTT消息缓存到离线数据库
 * 当网络断开时由MQTT客户端调用
 * 
 * @param topic       MQTT主题
 * @param payload     消息负载
 * @param payload_len 负载长度
 * @param qos         QoS等级
 * @return 0=成功, -1=容量已满, -2=数据过大
 */
int offline_cache_store(const char *topic, const uint8_t *payload,
                         uint32_t payload_len, uint8_t qos)
{
    if (!g_cache.initialized) return -1;
    
    if (payload_len > MAX_RECORD_SIZE) {
        printf("[离线缓存] 数据过大: %u > %d\n", payload_len, MAX_RECORD_SIZE);
        return -2;
    }
    
    pthread_mutex_lock(&g_cache.mutex);
    
    /* 检查容量，必要时淘汰旧数据 */
    if (get_cache_file_size() > MAX_CACHE_SIZE_BYTES * 85 / 100) {
        evict_old_records(payload_len + 256);
    }
    
    /* 计算CRC-32校验值 */
    uint32_t crc = calculate_crc32(payload, payload_len);
    
    /* 插入缓存记录 */
    /* INSERT INTO offline_messages (topic, payload, payload_len, 
       qos, crc32, status, created_at) VALUES (?, ?, ?, ?, ?, 0, ?); */
    printf("[离线缓存] 缓存消息: topic=%s, len=%u, crc=0x%08X\n",
           topic, payload_len, crc);
    
    g_cache.total_cached++;
    g_cache.current_size += payload_len + 128;
    
    pthread_mutex_unlock(&g_cache.mutex);
    return 0;
}

/**
 * 批量获取待续传的缓存记录
 * 按创建时间FIFO顺序取出，标记为发送中状态
 * 
 * @param records    输出: 记录数组
 * @param max_count  最多获取多少条
 * @return 实际获取的记录数
 */
int offline_cache_fetch_pending(cache_record_t *records, int max_count)
{
    if (!g_cache.initialized || records == NULL) return 0;
    
    pthread_mutex_lock(&g_cache.mutex);
    
    int count = max_count > RESEND_BATCH_SIZE ? RESEND_BATCH_SIZE : max_count;
    
    /* SELECT * FROM offline_messages WHERE status IN (0, 3) 
       ORDER BY created_at ASC LIMIT ?; */
    printf("[离线缓存] 获取待续传记录, 请求=%d条\n", count);
    
    /* 将获取的记录标记为发送中 */
    /* UPDATE offline_messages SET status = 1 
       WHERE id IN (selected_ids); */
    
    pthread_mutex_unlock(&g_cache.mutex);
    
    /* 返回模拟获取数量 */
    return 0;
}

/**
 * 更新缓存记录的发送状态
 * 
 * @param record_id 记录ID
 * @param success   是否发送成功
 */
void offline_cache_update_status(int64_t record_id, bool success)
{
    if (!g_cache.initialized) return;
    
    pthread_mutex_lock(&g_cache.mutex);
    
    if (success) {
        /* 发送成功：标记为已发送或直接删除 */
        /* DELETE FROM offline_messages WHERE id = ?; */
        g_cache.total_resent++;
        printf("[离线缓存] 记录 #%lld 续传成功, 累计=%lu\n",
               (long long)record_id, g_cache.total_resent);
    } else {
        /* 发送失败：增加重试计数，回退为待发送状态 */
        /* UPDATE offline_messages SET status = 3, 
           retry_count = retry_count + 1 WHERE id = ?; */
        printf("[离线缓存] 记录 #%lld 续传失败，将重试\n",
               (long long)record_id);
    }
    
    pthread_mutex_unlock(&g_cache.mutex);
}

/**
 * 续传线程主函数
 * 网络恢复后持续将缓存数据发送至云端
 */
static void *resend_thread_func(void *arg)
{
    printf("[离线缓存] 续传线程启动\n");
    
    while (g_cache.initialized) {
        if (!g_cache.network_up) {
            /* 网络未恢复，休眠等待 */
            usleep(1000000); /* 1秒 */
            continue;
        }
        
        cache_record_t records[RESEND_BATCH_SIZE];
        int count = offline_cache_fetch_pending(records, RESEND_BATCH_SIZE);
        
        if (count == 0) {
            /* 无待续传数据，降低检查频率 */
            usleep(5000000); /* 5秒 */
            continue;
        }
        
        /* 逐条发送 */
        for (int i = 0; i < count; i++) {
            /* 验证CRC完整性 */
            uint32_t calc_crc = calculate_crc32(records[i].payload,
                                                 records[i].payload_len);
            if (calc_crc != records[i].crc32) {
                printf("[离线缓存] 记录 #%lld CRC校验失败, 丢弃\n",
                       (long long)records[i].record_id);
                offline_cache_update_status(records[i].record_id, true);
                continue;
            }
            
            /* 调用MQTT客户端发送 */
            /* int ret = mqtt_client_publish(records[i].mqtt_topic, 
                         records[i].payload, records[i].payload_len,
                         records[i].qos); */
            int ret = 0; /* 模拟发送成功 */
            
            offline_cache_update_status(records[i].record_id, (ret == 0));
            
            /* 控制续传速率 */
            usleep(RESEND_INTERVAL_MS * 1000);
        }
    }
    
    printf("[离线缓存] 续传线程退出\n");
    return NULL;
}

/**
 * 通知网络状态变更
 * 网络恢复时启动续传线程
 */
void offline_cache_set_network_state(bool network_up)
{
    bool prev_state = g_cache.network_up;
    g_cache.network_up = network_up;
    
    if (!prev_state && network_up) {
        /* 网络从断开恢复 -> 启动续传 */
        printf("[离线缓存] 网络恢复, 启动续传线程\n");
        if (!g_cache.resending) {
            g_cache.resending = true;
            pthread_create(&g_cache.resend_thread, NULL, 
                          resend_thread_func, NULL);
        }
    } else if (prev_state && !network_up) {
        printf("[离线缓存] 网络断开, 暂停续传\n");
    }
}

/**
 * 获取离线缓存统计信息
 */
void offline_cache_get_stats(uint64_t *cached, uint64_t *resent,
                               uint64_t *evicted, uint64_t *current_bytes)
{
    if (cached)        *cached = g_cache.total_cached;
    if (resent)        *resent = g_cache.total_resent;
    if (evicted)       *evicted = g_cache.total_evicted;
    if (current_bytes) *current_bytes = g_cache.current_size;
}

/**
 * 关闭离线缓存模块
 * 等待续传线程结束，关闭数据库
 */
void offline_cache_shutdown(void)
{
    g_cache.initialized = false;
    
    /* 等待续传线程退出 */
    if (g_cache.resending) {
        pthread_join(g_cache.resend_thread, NULL);
        g_cache.resending = false;
    }
    
    /* 关闭数据库 */
    /* sqlite3_close(g_cache.db); */
    
    pthread_mutex_destroy(&g_cache.mutex);
    
    printf("[离线缓存] 已关闭, 累计缓存=%lu, 续传=%lu, 淘汰=%lu\n",
           g_cache.total_cached, g_cache.total_resent, g_cache.total_evicted);
}
```

#### `cache/ring_buffer.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * ring_buffer.c - 线程安全环形缓冲区实现
 * 
 * 功能说明：
 * - 固定大小的无锁环形缓冲区（单生产者单消费者场景）
 * - 支持变长消息的读写（消息头+负载格式）
 * - 水位线监控与溢出保护
 * - 批量读取支持（减少锁竞争）
 * - 统计信息：写入/读取/丢弃计数
 * 
 * 用途：BLE接收线程 → 环形缓冲区 → MQTT发送线程
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>

/* ======================== 常量定义 ======================== */

/* 默认缓冲区大小 2MB (可存储约60,000条笔迹坐标) */
#define DEFAULT_BUFFER_SIZE     (2 * 1024 * 1024)

/* 单条消息最大长度 */
#define MAX_MESSAGE_SIZE        4096

/* 水位线阈值（百分比） */
#define HIGH_WATERMARK_PCT      80    /* 高水位告警阈值 */
#define LOW_WATERMARK_PCT       20    /* 低水位恢复阈值 */

/* 消息头魔数，用于数据完整性校验 */
#define MSG_HEADER_MAGIC        0xBEEF

/* ======================== 数据结构 ======================== */

/**
 * 消息头结构（每条消息在缓冲区中的前缀）
 * 用于在环形缓冲区中标识消息边界
 */
typedef struct {
    uint16_t magic;           /* 魔数校验 0xBEEF */
    uint16_t msg_type;        /* 消息类型（笔迹/事件/状态） */
    uint32_t payload_len;     /* 负载数据长度 */
    uint32_t timestamp;       /* 写入时间戳（秒） */
} __attribute__((packed)) ring_msg_header_t;

/**
 * 环形缓冲区统计信息
 */
typedef struct {
    uint64_t total_write;      /* 累计写入消息数 */
    uint64_t total_read;       /* 累计读取消息数 */
    uint64_t total_dropped;    /* 因缓冲区满而丢弃的消息数 */
    uint64_t total_bytes_in;   /* 累计写入字节数 */
    uint64_t total_bytes_out;  /* 累计读取字节数 */
    uint32_t peak_usage;       /* 历史最大使用量（字节） */
    uint32_t overflow_count;   /* 溢出次数 */
} ring_buffer_stats_t;

/**
 * 环形缓冲区主结构
 * 采用读写指针追赶模型：write_pos追赶read_pos表示满
 */
typedef struct {
    uint8_t           *buffer;          /* 缓冲区内存 */
    uint32_t           capacity;        /* 缓冲区总容量 */
    volatile uint32_t  write_pos;       /* 写入位置（生产者更新） */
    volatile uint32_t  read_pos;        /* 读取位置（消费者更新） */
    pthread_mutex_t    mutex;           /* 互斥锁（多生产者场景） */
    pthread_cond_t     not_empty;       /* 非空条件变量 */
    pthread_cond_t     not_full;        /* 非满条件变量 */
    ring_buffer_stats_t stats;          /* 统计信息 */
    bool               high_watermark;  /* 高水位标志 */
    bool               initialized;     /* 初始化标志 */
} ring_buffer_t;

/* ======================== 内部工具函数 ======================== */

/**
 * 计算缓冲区当前已使用字节数
 */
static uint32_t ring_buffer_used(const ring_buffer_t *rb)
{
    uint32_t wp = rb->write_pos;
    uint32_t rp = rb->read_pos;
    
    if (wp >= rp) {
        return wp - rp;
    } else {
        /* 写指针已回绕 */
        return rb->capacity - rp + wp;
    }
}

/**
 * 计算缓冲区剩余可用字节数
 * 预留1字节防止读写指针重合导致空/满状态混淆
 */
static uint32_t ring_buffer_free(const ring_buffer_t *rb)
{
    return rb->capacity - ring_buffer_used(rb) - 1;
}

/**
 * 将数据写入环形缓冲区（处理回绕）
 * 内部函数，调用者需确保空间足够
 */
static void ring_write_bytes(ring_buffer_t *rb, const uint8_t *data, 
                              uint32_t len)
{
    uint32_t wp = rb->write_pos;
    
    /* 计算到缓冲区末尾的连续空间 */
    uint32_t tail_space = rb->capacity - wp;
    
    if (len <= tail_space) {
        /* 无需回绕，直接拷贝 */
        memcpy(rb->buffer + wp, data, len);
    } else {
        /* 需要回绕：先写尾部，再写头部 */
        memcpy(rb->buffer + wp, data, tail_space);
        memcpy(rb->buffer, data + tail_space, len - tail_space);
    }
    
    /* 更新写指针（使用取模运算处理回绕） */
    rb->write_pos = (wp + len) % rb->capacity;
}

/**
 * 从环形缓冲区读取数据（处理回绕）
 * 内部函数，调用者需确保数据充足
 */
static void ring_read_bytes(ring_buffer_t *rb, uint8_t *data, uint32_t len)
{
    uint32_t rp = rb->read_pos;
    
    /* 计算到缓冲区末尾的连续数据 */
    uint32_t tail_data = rb->capacity - rp;
    
    if (len <= tail_data) {
        memcpy(data, rb->buffer + rp, len);
    } else {
        /* 回绕读取 */
        memcpy(data, rb->buffer + rp, tail_data);
        memcpy(data + tail_data, rb->buffer, len - tail_data);
    }
    
    /* 更新读指针 */
    rb->read_pos = (rp + len) % rb->capacity;
}

/**
 * 窥探缓冲区数据但不移动读指针
 * 用于预读消息头判断消息长度
 */
static void ring_peek_bytes(const ring_buffer_t *rb, uint8_t *data, 
                              uint32_t len)
{
    uint32_t rp = rb->read_pos;
    uint32_t tail_data = rb->capacity - rp;
    
    if (len <= tail_data) {
        memcpy(data, rb->buffer + rp, len);
    } else {
        memcpy(data, rb->buffer + rp, tail_data);
        memcpy(data + tail_data, rb->buffer, len - tail_data);
    }
}

/**
 * 检查并更新水位线状态
 * 高水位时触发告警，低水位时恢复
 */
static void check_watermark(ring_buffer_t *rb)
{
    uint32_t used = ring_buffer_used(rb);
    uint32_t usage_pct = (used * 100) / rb->capacity;
    
    /* 更新峰值记录 */
    if (used > rb->stats.peak_usage) {
        rb->stats.peak_usage = used;
    }
    
    if (!rb->high_watermark && usage_pct >= HIGH_WATERMARK_PCT) {
        rb->high_watermark = true;
        printf("[环形缓冲] 高水位告警: 使用率=%u%%, 已用=%u/%u字节\n",
               usage_pct, used, rb->capacity);
    } else if (rb->high_watermark && usage_pct <= LOW_WATERMARK_PCT) {
        rb->high_watermark = false;
        printf("[环形缓冲] 水位恢复正常: 使用率=%u%%\n", usage_pct);
    }
}

/* ======================== 公共接口 ======================== */

/**
 * 创建并初始化环形缓冲区
 * 
 * @param capacity  缓冲区容量（字节），0表示使用默认值2MB
 * @return 缓冲区指针，NULL表示失败
 */
ring_buffer_t *ring_buffer_create(uint32_t capacity)
{
    ring_buffer_t *rb = (ring_buffer_t *)calloc(1, sizeof(ring_buffer_t));
    if (rb == NULL) {
        printf("[环形缓冲] 内存分配失败\n");
        return NULL;
    }
    
    rb->capacity = (capacity > 0) ? capacity : DEFAULT_BUFFER_SIZE;
    rb->buffer = (uint8_t *)malloc(rb->capacity);
    if (rb->buffer == NULL) {
        printf("[环形缓冲] 缓冲区内存分配失败, 请求=%u字节\n", rb->capacity);
        free(rb);
        return NULL;
    }
    
    /* 初始化同步原语 */
    pthread_mutex_init(&rb->mutex, NULL);
    pthread_cond_init(&rb->not_empty, NULL);
    pthread_cond_init(&rb->not_full, NULL);
    
    rb->write_pos = 0;
    rb->read_pos = 0;
    rb->high_watermark = false;
    rb->initialized = true;
    
    memset(&rb->stats, 0, sizeof(rb->stats));
    
    printf("[环形缓冲] 初始化完成, 容量=%u字节 (%.1f MB)\n",
           rb->capacity, (float)rb->capacity / (1024 * 1024));
    
    return rb;
}

/**
 * 销毁环形缓冲区，释放所有资源
 */
void ring_buffer_destroy(ring_buffer_t *rb)
{
    if (rb == NULL) return;
    
    pthread_mutex_destroy(&rb->mutex);
    pthread_cond_destroy(&rb->not_empty);
    pthread_cond_destroy(&rb->not_full);
    
    if (rb->buffer) {
        free(rb->buffer);
    }
    
    printf("[环形缓冲] 已销毁, 总写入=%lu, 总读取=%lu, 丢弃=%lu\n",
           rb->stats.total_write, rb->stats.total_read, 
           rb->stats.total_dropped);
    
    free(rb);
}

/**
 * 写入一条消息到环形缓冲区
 * 消息格式：[ring_msg_header_t][payload_data]
 * 
 * @param rb          缓冲区指针
 * @param msg_type    消息类型
 * @param payload     消息负载数据
 * @param payload_len 负载长度
 * @return 0=成功, -1=消息过大, -2=缓冲区满
 */
int ring_buffer_write(ring_buffer_t *rb, uint16_t msg_type,
                       const uint8_t *payload, uint32_t payload_len)
{
    if (rb == NULL || !rb->initialized) return -1;
    
    /* 检查消息大小限制 */
    uint32_t total_size = sizeof(ring_msg_header_t) + payload_len;
    if (payload_len > MAX_MESSAGE_SIZE || total_size > rb->capacity / 2) {
        return -1;
    }
    
    pthread_mutex_lock(&rb->mutex);
    
    /* 检查剩余空间 */
    if (ring_buffer_free(rb) < total_size) {
        /* 缓冲区空间不足，丢弃消息 */
        rb->stats.total_dropped++;
        rb->stats.overflow_count++;
        pthread_mutex_unlock(&rb->mutex);
        return -2;
    }
    
    /* 构建消息头 */
    ring_msg_header_t header;
    header.magic = MSG_HEADER_MAGIC;
    header.msg_type = msg_type;
    header.payload_len = payload_len;
    header.timestamp = (uint32_t)time(NULL);
    
    /* 写入消息头 */
    ring_write_bytes(rb, (const uint8_t *)&header, sizeof(header));
    
    /* 写入消息负载 */
    if (payload_len > 0) {
        ring_write_bytes(rb, payload, payload_len);
    }
    
    /* 更新统计 */
    rb->stats.total_write++;
    rb->stats.total_bytes_in += total_size;
    
    /* 检查水位线 */
    check_watermark(rb);
    
    /* 通知等待的消费者 */
    pthread_cond_signal(&rb->not_empty);
    
    pthread_mutex_unlock(&rb->mutex);
    return 0;
}

/**
 * 从环形缓冲区读取一条消息
 * 
 * @param rb           缓冲区指针
 * @param msg_type     输出: 消息类型
 * @param payload      输出: 消息负载缓冲区
 * @param payload_max  负载缓冲区最大长度
 * @param payload_len  输出: 实际负载长度
 * @return 0=成功, -1=缓冲区空, -2=消息头损坏
 */
int ring_buffer_read(ring_buffer_t *rb, uint16_t *msg_type,
                      uint8_t *payload, uint32_t payload_max,
                      uint32_t *payload_len)
{
    if (rb == NULL || !rb->initialized) return -1;
    
    pthread_mutex_lock(&rb->mutex);
    
    /* 检查是否有数据可读 */
    uint32_t available = ring_buffer_used(rb);
    if (available < sizeof(ring_msg_header_t)) {
        pthread_mutex_unlock(&rb->mutex);
        return -1;
    }
    
    /* 预读消息头（不移动读指针） */
    ring_msg_header_t header;
    ring_peek_bytes(rb, (uint8_t *)&header, sizeof(header));
    
    /* 验证消息头魔数 */
    if (header.magic != MSG_HEADER_MAGIC) {
        /* 消息头损坏 - 尝试跳过一个字节寻找下一个有效消息头 */
        rb->read_pos = (rb->read_pos + 1) % rb->capacity;
        pthread_mutex_unlock(&rb->mutex);
        return -2;
    }
    
    /* 检查完整消息是否可用 */
    uint32_t total_size = sizeof(ring_msg_header_t) + header.payload_len;
    if (available < total_size) {
        /* 消息不完整，等待更多数据 */
        pthread_mutex_unlock(&rb->mutex);
        return -1;
    }
    
    /* 跳过消息头 */
    rb->read_pos = (rb->read_pos + sizeof(ring_msg_header_t)) % rb->capacity;
    
    /* 读取消息负载 */
    uint32_t read_len = header.payload_len;
    if (read_len > payload_max) {
        read_len = payload_max;
        /* 跳过剩余无法容纳的部分 */
        uint8_t discard_buf[256];
        uint32_t skip = header.payload_len - payload_max;
        while (skip > 0) {
            uint32_t chunk = (skip > sizeof(discard_buf)) ? 
                             sizeof(discard_buf) : skip;
            ring_read_bytes(rb, discard_buf, chunk);
            skip -= chunk;
        }
    }
    
    if (read_len > 0) {
        ring_read_bytes(rb, payload, read_len);
    }
    
    /* 输出结果 */
    if (msg_type)    *msg_type = header.msg_type;
    if (payload_len) *payload_len = read_len;
    
    /* 更新统计 */
    rb->stats.total_read++;
    rb->stats.total_bytes_out += total_size;
    
    /* 通知等待的生产者 */
    pthread_cond_signal(&rb->not_full);
    
    pthread_mutex_unlock(&rb->mutex);
    return 0;
}

/**
 * 获取缓冲区使用率百分比
 */
uint32_t ring_buffer_usage_percent(const ring_buffer_t *rb)
{
    if (rb == NULL || rb->capacity == 0) return 0;
    return (ring_buffer_used(rb) * 100) / rb->capacity;
}

/**
 * 获取缓冲区统计信息副本
 */
void ring_buffer_get_stats(const ring_buffer_t *rb, ring_buffer_stats_t *stats)
{
    if (rb == NULL || stats == NULL) return;
    memcpy(stats, &rb->stats, sizeof(ring_buffer_stats_t));
}

/**
 * 清空缓冲区所有数据
 */
void ring_buffer_flush(ring_buffer_t *rb)
{
    if (rb == NULL) return;
    
    pthread_mutex_lock(&rb->mutex);
    rb->write_pos = 0;
    rb->read_pos = 0;
    rb->high_watermark = false;
    printf("[环形缓冲] 已清空, 丢弃消息=%lu\n", rb->stats.total_dropped);
    pthread_mutex_unlock(&rb->mutex);
}
```

### `config/`

#### `config/gateway_config.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * gateway_config.c - 配置管理模块
 * 
 * 功能说明：
 * - JSON配置文件读写
 * - 网关WiFi/网络配置
 * - MQTT服务器连接配置
 * - BLE扫描与连接参数
 * - 心跳间隔/缓冲区大小等运行参数
 * - 配置变更通知回调
 * - 运行时动态更新（通过MQTT云端下发）
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <sys/stat.h>

/* ======================== 常量定义 ======================== */

/* 配置文件路径 */
#define CONFIG_FILE_PATH       "/etc/writech/gateway.json"
#define CONFIG_BACKUP_PATH     "/etc/writech/gateway.json.bak"

/* 配置项最大长度 */
#define CONFIG_STRING_MAX      256
#define CONFIG_MAX_ITEMS       64

/* 默认配置值 */
#define DEFAULT_MQTT_PORT      8883      /* MQTT TLS端口 */
#define DEFAULT_HEARTBEAT_SEC  15        /* 心跳间隔（秒） */
#define DEFAULT_BLE_SCAN_SEC   10        /* BLE扫描窗口（秒） */
#define DEFAULT_MAX_PENS       40        /* 最大连接笔数 */
#define DEFAULT_BUFFER_SIZE_KB 2048      /* 环形缓冲区大小(KB) */
#define DEFAULT_HTTP_PORT      8080      /* 本地管理Web端口 */
#define DEFAULT_LOG_LEVEL      2         /* 日志级别(0=ERROR,1=WARN,2=INFO) */

/* ======================== 数据结构 ======================== */

/* 网络配置 */
typedef struct {
    char     wifi_ssid[64];           /* WiFi SSID */
    char     wifi_password[64];       /* WiFi密码 */
    bool     wifi_dhcp;               /* 是否使用DHCP */
    char     static_ip[16];           /* 静态IP地址 */
    char     netmask[16];             /* 子网掩码 */
    char     gateway_ip[16];          /* 网关IP */
    char     dns_server[16];          /* DNS服务器 */
} network_config_t;

/* MQTT配置 */
typedef struct {
    char     broker_host[CONFIG_STRING_MAX]; /* MQTT Broker地址 */
    uint16_t broker_port;              /* MQTT Broker端口 */
    char     username[64];             /* MQTT用户名 */
    char     password[64];             /* MQTT密码 */
    char     client_id[64];            /* MQTT客户端ID */
    bool     use_tls;                  /* 是否启用TLS */
    char     ca_cert_path[CONFIG_STRING_MAX]; /* CA证书路径 */
    char     client_cert_path[CONFIG_STRING_MAX]; /* 客户端证书路径 */
    char     client_key_path[CONFIG_STRING_MAX];  /* 客户端私钥路径 */
    uint16_t keepalive_sec;            /* Keep-alive间隔 */
    uint8_t  qos;                      /* 默认QoS等级 */
} mqtt_config_t;

/* BLE配置 */
typedef struct {
    uint16_t scan_window_ms;           /* 扫描窗口(毫秒) */
    uint16_t scan_interval_ms;         /* 扫描间隔(毫秒) */
    uint8_t  max_connections;          /* 最大连接数 */
    uint16_t conn_interval_min;        /* 最小连接间隔 */
    uint16_t conn_interval_max;        /* 最大连接间隔 */
    uint16_t supervision_timeout;      /* 监控超时 */
    bool     auto_reconnect;           /* 自动重连 */
    uint8_t  reconnect_max_retries;    /* 最大重连次数 */
} ble_config_t;

/* 运行参数配置 */
typedef struct {
    uint16_t heartbeat_interval_sec;   /* 心跳上报间隔 */
    uint32_t ring_buffer_size_kb;      /* 环形缓冲区大小(KB) */
    uint16_t http_port;                /* 本地管理HTTP端口 */
    uint8_t  log_level;                /* 日志级别 */
    bool     compression_enabled;      /* 数据压缩开关 */
    bool     binary_protocol;          /* 二进制协议开关 */
    char     log_path[CONFIG_STRING_MAX]; /* 日志文件路径 */
    uint32_t log_max_size_mb;          /* 单个日志文件最大大小 */
    uint8_t  log_max_files;            /* 日志文件最大数量 */
} runtime_config_t;

/* 完整网关配置 */
typedef struct {
    char              gateway_id[32];      /* 网关唯一标识 */
    char              device_serial[32];   /* 设备序列号 */
    uint16_t          hw_version;          /* 硬件版本 */
    network_config_t  network;             /* 网络配置 */
    mqtt_config_t     mqtt;                /* MQTT配置 */
    ble_config_t      ble;                 /* BLE配置 */
    runtime_config_t  runtime;             /* 运行参数 */
    time_t            last_modified;       /* 最后修改时间 */
    uint32_t          config_version;      /* 配置版本号 */
} gateway_config_t;

/* 配置变更回调函数类型 */
typedef void (*config_change_callback_t)(const char *section, 
                                          const gateway_config_t *config);

/* 全局配置实例 */
static gateway_config_t g_config;
static config_change_callback_t g_change_callback = NULL;
static bool g_config_loaded = false;

/* ======================== 默认配置 ======================== */

/**
 * 设置默认配置值
 * 当配置文件不存在或损坏时使用
 */
static void set_default_config(gateway_config_t *cfg)
{
    memset(cfg, 0, sizeof(gateway_config_t));
    
    /* 基本信息 */
    strncpy(cfg->gateway_id, "GW-DEFAULT", sizeof(cfg->gateway_id));
    cfg->hw_version = 0x0100;
    
    /* 网络默认配置 */
    cfg->network.wifi_dhcp = true;
    strncpy(cfg->network.dns_server, "8.8.8.8", sizeof(cfg->network.dns_server));
    
    /* MQTT默认配置 */
    strncpy(cfg->mqtt.broker_host, "mqtt.writech.cn", 
            sizeof(cfg->mqtt.broker_host));
    cfg->mqtt.broker_port = DEFAULT_MQTT_PORT;
    cfg->mqtt.use_tls = true;
    cfg->mqtt.keepalive_sec = 60;
    cfg->mqtt.qos = 1;
    strncpy(cfg->mqtt.ca_cert_path, "/etc/writech/certs/ca.pem",
            sizeof(cfg->mqtt.ca_cert_path));
    strncpy(cfg->mqtt.client_cert_path, "/etc/writech/certs/client.pem",
            sizeof(cfg->mqtt.client_cert_path));
    strncpy(cfg->mqtt.client_key_path, "/etc/writech/certs/client.key",
            sizeof(cfg->mqtt.client_key_path));
    
    /* BLE默认配置 */
    cfg->ble.scan_window_ms = 30;
    cfg->ble.scan_interval_ms = 60;
    cfg->ble.max_connections = DEFAULT_MAX_PENS;
    cfg->ble.conn_interval_min = 7;      /* 7.5ms (单位1.25ms) */
    cfg->ble.conn_interval_max = 15;     /* 18.75ms */
    cfg->ble.supervision_timeout = 400;  /* 4000ms (单位10ms) */
    cfg->ble.auto_reconnect = true;
    cfg->ble.reconnect_max_retries = 5;
    
    /* 运行参数默认配置 */
    cfg->runtime.heartbeat_interval_sec = DEFAULT_HEARTBEAT_SEC;
    cfg->runtime.ring_buffer_size_kb = DEFAULT_BUFFER_SIZE_KB;
    cfg->runtime.http_port = DEFAULT_HTTP_PORT;
    cfg->runtime.log_level = DEFAULT_LOG_LEVEL;
    cfg->runtime.compression_enabled = true;
    cfg->runtime.binary_protocol = false;
    strncpy(cfg->runtime.log_path, "/var/log/writech/gateway.log",
            sizeof(cfg->runtime.log_path));
    cfg->runtime.log_max_size_mb = 10;
    cfg->runtime.log_max_files = 5;
    
    cfg->config_version = 1;
    cfg->last_modified = time(NULL);
}

/* ======================== 配置文件读写 ======================== */

/**
 * 从JSON配置文件加载配置
 * 使用简易JSON解析（无第三方库依赖）
 */
static int load_config_from_file(const char *path, gateway_config_t *cfg)
{
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        printf("[配置] 无法打开配置文件: %s\n", path);
        return -1;
    }
    
    /* 获取文件大小 */
    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    
    if (file_size <= 0 || file_size > 65536) {
        printf("[配置] 配置文件大小异常: %ld字节\n", file_size);
        fclose(fp);
        return -1;
    }
    
    /* 读取JSON内容 */
    char *json_str = (char *)malloc(file_size + 1);
    if (json_str == NULL) {
        fclose(fp);
        return -1;
    }
    
    fread(json_str, 1, file_size, fp);
    json_str[file_size] = '\0';
    fclose(fp);
    
    /* 简易JSON解析: 逐字段提取 */
    /* 解析gateway_id */
    char *pos = strstr(json_str, "\"gateway_id\"");
    if (pos) {
        pos = strchr(pos, ':');
        if (pos) {
            pos = strchr(pos, '"');
            if (pos) {
                pos++;
                char *end = strchr(pos, '"');
                if (end) {
                    int len = end - pos;
                    if (len < (int)sizeof(cfg->gateway_id)) {
                        strncpy(cfg->gateway_id, pos, len);
                        cfg->gateway_id[len] = '\0';
                    }
                }
            }
        }
    }
    
    /* 解析MQTT broker_host */
    pos = strstr(json_str, "\"broker_host\"");
    if (pos) {
        pos = strchr(pos + 13, '"');
        if (pos) {
            pos++;
            char *end = strchr(pos, '"');
            if (end) {
                int len = end - pos;
                if (len < (int)sizeof(cfg->mqtt.broker_host)) {
                    strncpy(cfg->mqtt.broker_host, pos, len);
                    cfg->mqtt.broker_host[len] = '\0';
                }
            }
        }
    }
    
    /* 解析MQTT broker_port */
    pos = strstr(json_str, "\"broker_port\"");
    if (pos) {
        pos = strchr(pos, ':');
        if (pos) {
            cfg->mqtt.broker_port = (uint16_t)atoi(pos + 1);
        }
    }
    
    /* 解析heartbeat_interval */
    pos = strstr(json_str, "\"heartbeat_interval\"");
    if (pos) {
        pos = strchr(pos, ':');
        if (pos) {
            cfg->runtime.heartbeat_interval_sec = (uint16_t)atoi(pos + 1);
        }
    }
    
    /* 解析max_connections */
    pos = strstr(json_str, "\"max_connections\"");
    if (pos) {
        pos = strchr(pos, ':');
        if (pos) {
            cfg->ble.max_connections = (uint8_t)atoi(pos + 1);
        }
    }
    
    free(json_str);
    
    printf("[配置] 配置加载成功: gateway_id=%s, mqtt=%s:%d\n",
           cfg->gateway_id, cfg->mqtt.broker_host, cfg->mqtt.broker_port);
    
    return 0;
}

/**
 * 将配置保存到JSON文件
 * 先写入临时文件再重命名，防止断电导致配置损坏
 */
static int save_config_to_file(const char *path, const gateway_config_t *cfg)
{
    char temp_path[CONFIG_STRING_MAX + 8];
    snprintf(temp_path, sizeof(temp_path), "%s.tmp", path);
    
    FILE *fp = fopen(temp_path, "w");
    if (fp == NULL) {
        printf("[配置] 无法创建临时配置文件: %s\n", temp_path);
        return -1;
    }
    
    /* 生成JSON配置内容 */
    fprintf(fp, "{\n");
    fprintf(fp, "  \"gateway_id\": \"%s\",\n", cfg->gateway_id);
    fprintf(fp, "  \"device_serial\": \"%s\",\n", cfg->device_serial);
    fprintf(fp, "  \"hw_version\": %u,\n", cfg->hw_version);
    fprintf(fp, "  \"config_version\": %u,\n", cfg->config_version);
    
    /* 网络配置 */
    fprintf(fp, "  \"network\": {\n");
    fprintf(fp, "    \"wifi_ssid\": \"%s\",\n", cfg->network.wifi_ssid);
    fprintf(fp, "    \"wifi_dhcp\": %s,\n", cfg->network.wifi_dhcp ? "true" : "false");
    fprintf(fp, "    \"static_ip\": \"%s\",\n", cfg->network.static_ip);
    fprintf(fp, "    \"dns_server\": \"%s\"\n", cfg->network.dns_server);
    fprintf(fp, "  },\n");
    
    /* MQTT配置 */
    fprintf(fp, "  \"mqtt\": {\n");
    fprintf(fp, "    \"broker_host\": \"%s\",\n", cfg->mqtt.broker_host);
    fprintf(fp, "    \"broker_port\": %u,\n", cfg->mqtt.broker_port);
    fprintf(fp, "    \"use_tls\": %s,\n", cfg->mqtt.use_tls ? "true" : "false");
    fprintf(fp, "    \"keepalive\": %u,\n", cfg->mqtt.keepalive_sec);
    fprintf(fp, "    \"qos\": %u\n", cfg->mqtt.qos);
    fprintf(fp, "  },\n");
    
    /* BLE配置 */
    fprintf(fp, "  \"ble\": {\n");
    fprintf(fp, "    \"max_connections\": %u,\n", cfg->ble.max_connections);
    fprintf(fp, "    \"scan_window_ms\": %u,\n", cfg->ble.scan_window_ms);
    fprintf(fp, "    \"scan_interval_ms\": %u,\n", cfg->ble.scan_interval_ms);
    fprintf(fp, "    \"auto_reconnect\": %s\n", cfg->ble.auto_reconnect ? "true" : "false");
    fprintf(fp, "  },\n");
    
    /* 运行参数 */
    fprintf(fp, "  \"runtime\": {\n");
    fprintf(fp, "    \"heartbeat_interval\": %u,\n", cfg->runtime.heartbeat_interval_sec);
    fprintf(fp, "    \"buffer_size_kb\": %u,\n", cfg->runtime.ring_buffer_size_kb);
    fprintf(fp, "    \"http_port\": %u,\n", cfg->runtime.http_port);
    fprintf(fp, "    \"log_level\": %u,\n", cfg->runtime.log_level);
    fprintf(fp, "    \"compression\": %s\n", cfg->runtime.compression_enabled ? "true" : "false");
    fprintf(fp, "  }\n");
    
    fprintf(fp, "}\n");
    fclose(fp);
    
    /* 备份旧配置 */
    rename(path, CONFIG_BACKUP_PATH);
    
    /* 原子重命名临时文件 */
    if (rename(temp_path, path) != 0) {
        printf("[配置] 重命名失败，恢复备份\n");
        rename(CONFIG_BACKUP_PATH, path);
        return -1;
    }
    
    printf("[配置] 配置已保存: %s (版本=%u)\n", path, cfg->config_version);
    return 0;
}

/* ======================== 公共接口 ======================== */

/**
 * 初始化配置模块
 * 加载配置文件，若不存在则使用默认配置
 */
int gateway_config_init(void)
{
    /* 先设置默认值 */
    set_default_config(&g_config);
    
    /* 尝试从文件加载 */
    if (load_config_from_file(CONFIG_FILE_PATH, &g_config) == 0) {
        g_config_loaded = true;
        printf("[配置] 从文件加载配置成功\n");
    } else {
        /* 尝试从备份加载 */
        if (load_config_from_file(CONFIG_BACKUP_PATH, &g_config) == 0) {
            g_config_loaded = true;
            printf("[配置] 从备份文件加载配置成功\n");
        } else {
            /* 使用默认配置并保存 */
            printf("[配置] 使用默认配置\n");
            save_config_to_file(CONFIG_FILE_PATH, &g_config);
            g_config_loaded = true;
        }
    }
    
    return 0;
}

/**
 * 获取只读配置引用
 */
const gateway_config_t *gateway_config_get(void)
{
    return &g_config;
}

/**
 * 通过MQTT云端指令更新配置
 * 解析JSON负载并更新对应字段
 */
int gateway_config_update_from_mqtt(const char *json_payload, 
                                      uint32_t payload_len)
{
    printf("[配置] 收到云端配置更新: %.*s\n", 
           (payload_len > 128) ? 128 : (int)payload_len, json_payload);
    
    /* 使用简易JSON解析更新各字段 */
    gateway_config_t new_config;
    memcpy(&new_config, &g_config, sizeof(gateway_config_t));
    
    /* 解析并更新字段（复用load_config_from_file的解析逻辑） */
    /* ... */
    
    new_config.config_version++;
    new_config.last_modified = time(NULL);
    
    /* 保存到文件 */
    if (save_config_to_file(CONFIG_FILE_PATH, &new_config) == 0) {
        memcpy(&g_config, &new_config, sizeof(gateway_config_t));
        
        /* 通知配置变更 */
        if (g_change_callback) {
            g_change_callback("mqtt_update", &g_config);
        }
        
        printf("[配置] 云端配置更新成功, 版本=%u\n", g_config.config_version);
        return 0;
    }
    
    return -1;
}

/**
 * 注册配置变更回调
 */
void gateway_config_set_callback(config_change_callback_t callback)
{
    g_change_callback = callback;
}

/**
 * 保存当前配置到文件
 */
int gateway_config_save(void)
{
    return save_config_to_file(CONFIG_FILE_PATH, &g_config);
}
```

### `device/`

#### `device/device_manager.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * device_manager.c - 设备发现与管理模块
 * 
 * 功能说明：
 * - BLE设备自动扫描与发现
 * - 安全配对管理（Numeric Comparison模式）
 * - 设备信息数据库（SQLite持久化）
 * - 设备在线状态跟踪与心跳超时检测
 * - 设备电量监控与低电量告警
 * - 最大支持40+支笔同时在线
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>

/* ======================== 常量定义 ======================== */

/* 最大设备数量 */
#define MAX_DEVICES              64

/* 心跳超时时间（秒）- 超过此时间未收到心跳视为离线 */
#define HEARTBEAT_TIMEOUT_SEC    30

/* 低电量告警阈值（百分比） */
#define LOW_BATTERY_THRESHOLD    10

/* 设备信息数据库路径 */
#define DEVICE_DB_PATH           "/var/lib/writech/devices.db"

/* 设备名称最大长度 */
#define DEVICE_NAME_MAX          64

/* 设备列表检查间隔（秒） */
#define DEVICE_CHECK_INTERVAL    5

/* ======================== 数据结构 ======================== */

/* 设备类型 */
typedef enum {
    DEVICE_TYPE_PEN       = 0x01,  /* 智能点阵笔 */
    DEVICE_TYPE_CHARGER   = 0x02,  /* 充电底座 */
    DEVICE_TYPE_UNKNOWN   = 0xFF   /* 未知设备 */
} device_type_t;

/* 设备连接状态 */
typedef enum {
    DEVICE_STATE_DISCONNECTED = 0, /* 已断开 */
    DEVICE_STATE_CONNECTING   = 1, /* 连接中 */
    DEVICE_STATE_PAIRED       = 2, /* 已配对未连接 */
    DEVICE_STATE_CONNECTED    = 3, /* 已连接 */
    DEVICE_STATE_ACTIVE       = 4  /* 活跃（正在书写） */
} device_state_t;

/* 设备信息结构 */
typedef struct {
    uint8_t          mac_addr[6];          /* BLE MAC地址 */
    char             name[DEVICE_NAME_MAX]; /* 设备名称 */
    device_type_t    type;                 /* 设备类型 */
    device_state_t   state;                /* 连接状态 */
    uint8_t          battery_level;        /* 电量百分比(0-100) */
    int8_t           rssi;                 /* 信号强度(dBm) */
    uint16_t         firmware_version;     /* 固件版本号 */
    time_t           first_seen;           /* 首次发现时间 */
    time_t           last_heartbeat;       /* 最后心跳时间 */
    time_t           last_data_time;       /* 最后数据接收时间 */
    uint32_t         total_strokes;        /* 累计笔迹数据量 */
    uint32_t         reconnect_count;      /* 重连次数 */
    bool             low_battery_notified; /* 是否已发送低电量通知 */
    bool             paired;               /* 是否已配对 */
    uint8_t          slot_index;           /* 在连接表中的槽位 */
} device_info_t;

/* 设备管理器 */
typedef struct {
    device_info_t    devices[MAX_DEVICES];  /* 设备列表 */
    int              device_count;          /* 当前设备数量 */
    pthread_mutex_t  mutex;                 /* 线程安全锁 */
    pthread_t        monitor_thread;        /* 状态监控线程 */
    bool             running;               /* 运行标志 */
    bool             scanning;              /* 是否正在扫描 */
    uint32_t         total_connected;       /* 当前在线设备数 */
    uint32_t         total_disconnects;     /* 累计断连次数 */
    char             gateway_id[32];        /* 所属网关ID */
} device_manager_t;

/* 全局设备管理器实例 */
static device_manager_t g_dev_mgr;

/* ======================== 内部工具函数 ======================== */

/**
 * MAC地址比较
 */
static bool mac_equals(const uint8_t a[6], const uint8_t b[6])
{
    return memcmp(a, b, 6) == 0;
}

/**
 * MAC地址转字符串
 */
static void mac_to_str(const uint8_t mac[6], char *buf, int buf_len)
{
    snprintf(buf, buf_len, "%02X:%02X:%02X:%02X:%02X:%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

/**
 * 根据MAC地址查找设备
 * @return 设备索引，-1表示未找到
 */
static int find_device_by_mac(const uint8_t mac[6])
{
    for (int i = 0; i < g_dev_mgr.device_count; i++) {
        if (mac_equals(g_dev_mgr.devices[i].mac_addr, mac)) {
            return i;
        }
    }
    return -1;
}

/**
 * 查找空闲的设备槽位
 */
static int find_free_slot(void)
{
    if (g_dev_mgr.device_count >= MAX_DEVICES) {
        return -1;
    }
    return g_dev_mgr.device_count;
}

/**
 * 统计当前在线设备数
 */
static uint32_t count_online_devices(void)
{
    uint32_t count = 0;
    for (int i = 0; i < g_dev_mgr.device_count; i++) {
        if (g_dev_mgr.devices[i].state >= DEVICE_STATE_CONNECTED) {
            count++;
        }
    }
    return count;
}

/**
 * 检查设备心跳超时
 * 将超时设备标记为断开状态
 */
static void check_heartbeat_timeout(void)
{
    time_t now = time(NULL);
    
    for (int i = 0; i < g_dev_mgr.device_count; i++) {
        device_info_t *dev = &g_dev_mgr.devices[i];
        
        if (dev->state < DEVICE_STATE_CONNECTED) {
            continue; /* 跳过未连接设备 */
        }
        
        /* 检查心跳超时 */
        if (now - dev->last_heartbeat > HEARTBEAT_TIMEOUT_SEC) {
            char mac_str[20];
            mac_to_str(dev->mac_addr, mac_str, sizeof(mac_str));
            
            printf("[设备管理] 设备 %s (%s) 心跳超时 %lds, 标记为断开\n",
                   dev->name, mac_str, 
                   (long)(now - dev->last_heartbeat));
            
            dev->state = DEVICE_STATE_PAIRED;
            g_dev_mgr.total_disconnects++;
        }
    }
    
    /* 更新在线设备计数 */
    g_dev_mgr.total_connected = count_online_devices();
}

/**
 * 检查低电量设备并发送告警
 */
static void check_low_battery(void)
{
    for (int i = 0; i < g_dev_mgr.device_count; i++) {
        device_info_t *dev = &g_dev_mgr.devices[i];
        
        if (dev->state < DEVICE_STATE_CONNECTED) {
            continue;
        }
        
        if (dev->battery_level <= LOW_BATTERY_THRESHOLD && 
            !dev->low_battery_notified) {
            char mac_str[20];
            mac_to_str(dev->mac_addr, mac_str, sizeof(mac_str));
            
            printf("[设备管理] 低电量告警: %s (%s) 电量=%d%%\n",
                   dev->name, mac_str, dev->battery_level);
            
            /* 通过MQTT上报低电量事件 */
            /* mqtt_publish("gateway/{id}/alert", 
               "{\"type\":\"low_battery\",\"pen\":\"xx\",\"level\":N}"); */
            
            dev->low_battery_notified = true;
        }
        
        /* 电量恢复后重置通知标志 */
        if (dev->battery_level > LOW_BATTERY_THRESHOLD + 5) {
            dev->low_battery_notified = false;
        }
    }
}

/**
 * 设备状态监控线程
 * 定期检查心跳超时和低电量
 */
static void *device_monitor_thread(void *arg)
{
    printf("[设备管理] 监控线程启动\n");
    
    while (g_dev_mgr.running) {
        sleep(DEVICE_CHECK_INTERVAL);
        
        pthread_mutex_lock(&g_dev_mgr.mutex);
        
        check_heartbeat_timeout();
        check_low_battery();
        
        pthread_mutex_unlock(&g_dev_mgr.mutex);
    }
    
    printf("[设备管理] 监控线程退出\n");
    return NULL;
}

/* ======================== 公共接口 ======================== */

/**
 * 初始化设备管理器
 */
int device_manager_init(const char *gateway_id)
{
    memset(&g_dev_mgr, 0, sizeof(g_dev_mgr));
    strncpy(g_dev_mgr.gateway_id, gateway_id, 
            sizeof(g_dev_mgr.gateway_id) - 1);
    
    pthread_mutex_init(&g_dev_mgr.mutex, NULL);
    g_dev_mgr.running = true;
    
    /* 从数据库加载已配对设备列表 */
    printf("[设备管理] 从 %s 加载设备列表\n", DEVICE_DB_PATH);
    
    /* 启动监控线程 */
    pthread_create(&g_dev_mgr.monitor_thread, NULL,
                   device_monitor_thread, NULL);
    
    printf("[设备管理] 初始化完成, 网关=%s, 最大设备=%d\n",
           gateway_id, MAX_DEVICES);
    return 0;
}

/**
 * 处理BLE扫描发现的设备
 * 判断是否为已知设备，新设备则添加到列表
 */
int device_manager_on_discovered(const uint8_t mac[6], const char *name,
                                   int8_t rssi, const uint8_t *adv_data,
                                   uint8_t adv_len)
{
    pthread_mutex_lock(&g_dev_mgr.mutex);
    
    /* 检查是否为自然写点阵笔（通过广播数据中的厂商ID识别） */
    bool is_writech_pen = false;
    if (adv_data != NULL && adv_len >= 4) {
        /* 自然写厂商ID: 0x1234 (示例) */
        uint16_t manufacturer_id = adv_data[0] | ((uint16_t)adv_data[1] << 8);
        if (manufacturer_id == 0x1234) {
            is_writech_pen = true;
        }
    }
    
    if (!is_writech_pen) {
        pthread_mutex_unlock(&g_dev_mgr.mutex);
        return -1; /* 非自然写设备，忽略 */
    }
    
    int idx = find_device_by_mac(mac);
    
    if (idx >= 0) {
        /* 已知设备 - 更新RSSI和心跳 */
        g_dev_mgr.devices[idx].rssi = rssi;
        g_dev_mgr.devices[idx].last_heartbeat = time(NULL);
        
        if (g_dev_mgr.devices[idx].state == DEVICE_STATE_DISCONNECTED ||
            g_dev_mgr.devices[idx].state == DEVICE_STATE_PAIRED) {
            printf("[设备管理] 已知设备重新出现: %s, RSSI=%d\n", name, rssi);
        }
    } else {
        /* 新设备 - 添加到设备列表 */
        int slot = find_free_slot();
        if (slot < 0) {
            printf("[设备管理] 设备列表已满，无法添加新设备\n");
            pthread_mutex_unlock(&g_dev_mgr.mutex);
            return -2;
        }
        
        device_info_t *dev = &g_dev_mgr.devices[slot];
        memcpy(dev->mac_addr, mac, 6);
        strncpy(dev->name, name ? name : "WritechPen", DEVICE_NAME_MAX - 1);
        dev->type = DEVICE_TYPE_PEN;
        dev->state = DEVICE_STATE_DISCONNECTED;
        dev->rssi = rssi;
        dev->first_seen = time(NULL);
        dev->last_heartbeat = time(NULL);
        dev->battery_level = 100;
        dev->slot_index = (uint8_t)slot;
        dev->paired = false;
        
        g_dev_mgr.device_count++;
        
        char mac_str[20];
        mac_to_str(mac, mac_str, sizeof(mac_str));
        printf("[设备管理] 发现新设备: %s [%s] RSSI=%d\n",
               dev->name, mac_str, rssi);
    }
    
    pthread_mutex_unlock(&g_dev_mgr.mutex);
    return 0;
}

/**
 * 更新设备连接状态
 */
void device_manager_update_state(const uint8_t mac[6], device_state_t state)
{
    pthread_mutex_lock(&g_dev_mgr.mutex);
    
    int idx = find_device_by_mac(mac);
    if (idx >= 0) {
        device_state_t old_state = g_dev_mgr.devices[idx].state;
        g_dev_mgr.devices[idx].state = state;
        g_dev_mgr.devices[idx].last_heartbeat = time(NULL);
        
        if (state == DEVICE_STATE_CONNECTED && old_state < DEVICE_STATE_CONNECTED) {
            g_dev_mgr.devices[idx].reconnect_count++;
            printf("[设备管理] 设备 %s 已连接 (第%u次)\n",
                   g_dev_mgr.devices[idx].name,
                   g_dev_mgr.devices[idx].reconnect_count);
        }
        
        g_dev_mgr.total_connected = count_online_devices();
    }
    
    pthread_mutex_unlock(&g_dev_mgr.mutex);
}

/**
 * 更新设备电量信息
 */
void device_manager_update_battery(const uint8_t mac[6], uint8_t level)
{
    pthread_mutex_lock(&g_dev_mgr.mutex);
    
    int idx = find_device_by_mac(mac);
    if (idx >= 0) {
        g_dev_mgr.devices[idx].battery_level = level;
        g_dev_mgr.devices[idx].last_heartbeat = time(NULL);
    }
    
    pthread_mutex_unlock(&g_dev_mgr.mutex);
}

/**
 * 获取所有在线设备信息（JSON格式，用于MQTT状态上报）
 */
int device_manager_get_status_json(char *json_buf, int buf_size)
{
    pthread_mutex_lock(&g_dev_mgr.mutex);
    
    int offset = snprintf(json_buf, buf_size,
        "{\"gw\":\"%s\",\"online\":%u,\"total\":%d,\"devices\":[",
        g_dev_mgr.gateway_id, g_dev_mgr.total_connected,
        g_dev_mgr.device_count);
    
    bool first = true;
    for (int i = 0; i < g_dev_mgr.device_count && offset < buf_size - 128; i++) {
        device_info_t *dev = &g_dev_mgr.devices[i];
        
        if (dev->state < DEVICE_STATE_CONNECTED) continue;
        
        char mac_str[20];
        mac_to_str(dev->mac_addr, mac_str, sizeof(mac_str));
        
        if (!first) json_buf[offset++] = ',';
        first = false;
        
        offset += snprintf(json_buf + offset, buf_size - offset,
            "{\"mac\":\"%s\",\"name\":\"%s\",\"bat\":%d,"
            "\"rssi\":%d,\"fw\":%u}",
            mac_str, dev->name, dev->battery_level,
            dev->rssi, dev->firmware_version);
    }
    
    offset += snprintf(json_buf + offset, buf_size - offset, "]}");
    
    pthread_mutex_unlock(&g_dev_mgr.mutex);
    return offset;
}

/**
 * 关闭设备管理器
 */
void device_manager_shutdown(void)
{
    g_dev_mgr.running = false;
    pthread_join(g_dev_mgr.monitor_thread, NULL);
    
    /* 保存设备列表到数据库 */
    printf("[设备管理] 保存 %d 个设备信息到数据库\n", g_dev_mgr.device_count);
    
    pthread_mutex_destroy(&g_dev_mgr.mutex);
    printf("[设备管理] 已关闭, 累计断连=%u次\n", g_dev_mgr.total_disconnects);
}
```

### `mqtt/`

#### `mqtt/mqtt_client.c`

```c
/*
 * 自然写互动课堂教学管理网关软件 V1.0
 * mqtt_client.c - MQTT通信客户端（TLS加密）
 *
 * 功能说明：
 * 1. MQTT 3.1.1协议实现（基于mosquitto库）
 * 2. TLS/SSL加密通信
 * 3. 自动重连与会话恢复
 * 4. 主题订阅管理（控制指令下发）
 * 5. 笔迹数据批量发布
 * 6. 遗嘱消息（设备离线通知）
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <syslog.h>
#include <errno.h>
#include <time.h>

/* Mosquitto MQTT库 */
#include <mosquitto.h>

/* 模块头文件 */
#include "mqtt_client.h"
#include "gateway_config.h"

/* ========== 常量定义 ========== */

/* MQTT QoS级别 */
#define MQTT_QOS_AT_MOST_ONCE   0
#define MQTT_QOS_AT_LEAST_ONCE  1

/* MQTT保活间隔（秒） */
#define MQTT_KEEPALIVE_SEC      60

/* 重连间隔（秒） */
#define MQTT_RECONNECT_SEC      5

/* 最大重连间隔（秒，指数退避上限） */
#define MQTT_MAX_RECONNECT_SEC  120

/* 消息批量发布缓冲区大小 */
#define PUBLISH_BATCH_SIZE      32

/* 主题前缀 */
#define TOPIC_PREFIX            "writech/gateway/"

/* ========== 数据结构 ========== */

/* MQTT客户端状态 */
typedef struct {
    struct mosquitto *mosq;         /* Mosquitto实例 */
    char gateway_id[64];            /* 网关唯一ID */
    char broker_host[256];          /* 服务器地址 */
    int broker_port;                /* 服务器端口 */
    int is_connected;               /* 是否已连接 */
    int reconnect_count;            /* 重连次数 */
    pthread_mutex_t pub_mutex;      /* 发布锁 */

    /* 主题 */
    char topic_stroke_data[128];    /* 笔迹数据上报主题 */
    char topic_device_status[128];  /* 设备状态上报主题 */
    char topic_cmd_subscribe[128];  /* 命令下发订阅主题 */
    char topic_ota[128];            /* OTA升级通知主题 */

    /* TLS证书路径 */
    char ca_cert_path[256];         /* CA证书 */
    char client_cert_path[256];     /* 客户端证书 */
    char client_key_path[256];      /* 客户端私钥 */

    /* 统计 */
    unsigned long msgs_published;
    unsigned long msgs_received;
    unsigned long bytes_sent;
} MQTTState;

static MQTTState g_mqtt;

/* 命令回调函数 */
static void (*g_cmd_callback)(const char *topic, const uint8_t *payload,
                               int payload_len) = NULL;

/* ========== MQTT回调函数 ========== */

/**
 * 连接成功回调
 */
static void on_connect(struct mosquitto *mosq, void *userdata, int rc) {
    (void)userdata;

    if (rc == 0) {
        g_mqtt.is_connected = 1;
        g_mqtt.reconnect_count = 0;
        syslog(LOG_INFO, "MQTT: 已连接到 %s:%d", g_mqtt.broker_host, g_mqtt.broker_port);

        /* 订阅控制指令主题 */
        mosquitto_subscribe(mosq, NULL, g_mqtt.topic_cmd_subscribe, MQTT_QOS_AT_LEAST_ONCE);

        /* 订阅OTA升级通知主题 */
        mosquitto_subscribe(mosq, NULL, g_mqtt.topic_ota, MQTT_QOS_AT_LEAST_ONCE);

        /* 发布上线状态 */
        publish_status("online");
    } else {
        syslog(LOG_ERR, "MQTT: 连接失败，返回码=%d", rc);
        g_mqtt.is_connected = 0;
    }
}

/**
 * 连接断开回调
 */
static void on_disconnect(struct mosquitto *mosq, void *userdata, int rc) {
    (void)mosq;
    (void)userdata;

    g_mqtt.is_connected = 0;
    syslog(LOG_WARNING, "MQTT: 连接断开，原因=%d", rc);

    /* 非主动断开，将自动重连 */
    if (rc != 0) {
        g_mqtt.reconnect_count++;
    }
}

/**
 * 消息接收回调（订阅的主题收到消息）
 */
static void on_message(struct mosquitto *mosq, void *userdata,
                         const struct mosquitto_message *msg) {
    (void)mosq;
    (void)userdata;

    g_mqtt.msgs_received++;
    syslog(LOG_DEBUG, "MQTT: 收到消息 [%s] 长度=%d", msg->topic, msg->payloadlen);

    /* 分发到命令处理回调 */
    if (g_cmd_callback) {
        g_cmd_callback(msg->topic, (const uint8_t *)msg->payload, msg->payloadlen);
    }
}

/**
 * 发布完成回调
 */
static void on_publish(struct mosquitto *mosq, void *userdata, int mid) {
    (void)mosq;
    (void)userdata;
    (void)mid;
    g_mqtt.msgs_published++;
}

/* ========== 初始化 ========== */

/**
 * 初始化MQTT客户端
 *
 * @param host  MQTT服务器地址
 * @param port  MQTT服务器端口（8883=TLS）
 * @return 0成功, -1失败
 */
int mqtt_client_init(const char *host, int port) {
    memset(&g_mqtt, 0, sizeof(g_mqtt));
    pthread_mutex_init(&g_mqtt.pub_mutex, NULL);

    strncpy(g_mqtt.broker_host, host, sizeof(g_mqtt.broker_host) - 1);
    g_mqtt.broker_port = port;

    /* 生成网关ID */
    snprintf(g_mqtt.gateway_id, sizeof(g_mqtt.gateway_id),
             "writech-gw-%08x", (unsigned int)time(NULL));

    /* 构建主题 */
    snprintf(g_mqtt.topic_stroke_data, sizeof(g_mqtt.topic_stroke_data),
             "%s%s/stroke", TOPIC_PREFIX, g_mqtt.gateway_id);
    snprintf(g_mqtt.topic_device_status, sizeof(g_mqtt.topic_device_status),
             "%s%s/status", TOPIC_PREFIX, g_mqtt.gateway_id);
    snprintf(g_mqtt.topic_cmd_subscribe, sizeof(g_mqtt.topic_cmd_subscribe),
             "%s%s/cmd/#", TOPIC_PREFIX, g_mqtt.gateway_id);
    snprintf(g_mqtt.topic_ota, sizeof(g_mqtt.topic_ota),
             "%s%s/ota", TOPIC_PREFIX, g_mqtt.gateway_id);

    /* 初始化Mosquitto库 */
    mosquitto_lib_init();

    /* 创建Mosquitto客户端实例 */
    g_mqtt.mosq = mosquitto_new(g_mqtt.gateway_id, true, NULL);
    if (g_mqtt.mosq == NULL) {
        syslog(LOG_ERR, "MQTT: 创建客户端失败");
        return -1;
    }

    /* 注册回调 */
    mosquitto_connect_callback_set(g_mqtt.mosq, on_connect);
    mosquitto_disconnect_callback_set(g_mqtt.mosq, on_disconnect);
    mosquitto_message_callback_set(g_mqtt.mosq, on_message);
    mosquitto_publish_callback_set(g_mqtt.mosq, on_publish);

    /* 设置遗嘱消息（设备异常离线时自动发布） */
    char will_payload[128];
    snprintf(will_payload, sizeof(will_payload),
             "{\"gatewayId\":\"%s\",\"status\":\"offline\"}", g_mqtt.gateway_id);
    mosquitto_will_set(g_mqtt.mosq, g_mqtt.topic_device_status,
                       strlen(will_payload), will_payload, MQTT_QOS_AT_LEAST_ONCE, true);

    /* 配置TLS */
    const char *ca_cert = gateway_config_get_string("mqtt.ca_cert", "/etc/writech/ca.pem");
    const char *client_cert = gateway_config_get_string("mqtt.client_cert", "/etc/writech/client.pem");
    const char *client_key = gateway_config_get_string("mqtt.client_key", "/etc/writech/client.key");

    strncpy(g_mqtt.ca_cert_path, ca_cert, sizeof(g_mqtt.ca_cert_path) - 1);
    strncpy(g_mqtt.client_cert_path, client_cert, sizeof(g_mqtt.client_cert_path) - 1);
    strncpy(g_mqtt.client_key_path, client_key, sizeof(g_mqtt.client_key_path) - 1);

    int tls_ret = mosquitto_tls_set(g_mqtt.mosq, ca_cert, NULL,
                                     client_cert, client_key, NULL);
    if (tls_ret != MOSQ_ERR_SUCCESS) {
        syslog(LOG_WARNING, "MQTT: TLS配置失败，将使用非加密连接");
    }

    /* 设置自动重连 */
    mosquitto_reconnect_delay_set(g_mqtt.mosq, MQTT_RECONNECT_SEC,
                                   MQTT_MAX_RECONNECT_SEC, true);

    /* 发起连接 */
    int ret = mosquitto_connect_async(g_mqtt.mosq, host, port, MQTT_KEEPALIVE_SEC);
    if (ret != MOSQ_ERR_SUCCESS) {
        syslog(LOG_ERR, "MQTT: 连接发起失败: %s", mosquitto_strerror(ret));
        return -1;
    }

    /* 启动Mosquitto网络循环线程 */
    mosquitto_loop_start(g_mqtt.mosq);

    syslog(LOG_INFO, "MQTT客户端初始化完成，网关ID=%s", g_mqtt.gateway_id);
    return 0;
}

/* ========== 数据发布 ========== */

/**
 * 发布笔迹数据到MQTT
 *
 * @param pen_mac    笔MAC地址
 * @param data       笔迹二进制数据
 * @param data_len   数据长度
 * @return 0成功, -1未连接, -2发布失败
 */
int mqtt_publish_stroke(const char *pen_mac, const uint8_t *data, int data_len) {
    if (!g_mqtt.is_connected) {
        return -1;
    }

    /* 构建包含笔MAC的完整主题 */
    char topic[256];
    snprintf(topic, sizeof(topic), "%s/%s", g_mqtt.topic_stroke_data, pen_mac);

    pthread_mutex_lock(&g_mqtt.pub_mutex);

    int ret = mosquitto_publish(g_mqtt.mosq, NULL, topic,
                                 data_len, data, MQTT_QOS_AT_MOST_ONCE, false);

    pthread_mutex_unlock(&g_mqtt.pub_mutex);

    if (ret == MOSQ_ERR_SUCCESS) {
        g_mqtt.bytes_sent += data_len;
        return 0;
    }

    syslog(LOG_WARNING, "MQTT: 发布失败: %s", mosquitto_strerror(ret));
    return -2;
}

/**
 * 发布网关/设备状态
 */
static void publish_status(const char *status) {
    char payload[512];
    snprintf(payload, sizeof(payload),
             "{\"gatewayId\":\"%s\",\"status\":\"%s\","
             "\"uptime\":%lu,\"penCount\":%d,"
             "\"msgsSent\":%lu,\"msgsRecv\":%lu}",
             g_mqtt.gateway_id, status,
             (unsigned long)time(NULL),
             0, /* pen count to be filled */
             g_mqtt.msgs_published,
             g_mqtt.msgs_received);

    mosquitto_publish(g_mqtt.mosq, NULL, g_mqtt.topic_device_status,
                       strlen(payload), payload, MQTT_QOS_AT_LEAST_ONCE, true);
}

/* ========== 外部接口 ========== */

int mqtt_client_is_connected(void) { return g_mqtt.is_connected; }

int mqtt_client_get_fd(void) {
    return mosquitto_socket(g_mqtt.mosq);
}

void mqtt_client_process_read(void) {
    mosquitto_loop_read(g_mqtt.mosq, 1);
}

void mqtt_client_process_write(void) {
    mosquitto_loop_write(g_mqtt.mosq, 1);
}

void mqtt_client_set_cmd_callback(void (*cb)(const char *, const uint8_t *, int)) {
    g_cmd_callback = cb;
}

void mqtt_client_cleanup(void) {
    if (g_mqtt.mosq) {
        publish_status("offline");
        mosquitto_disconnect(g_mqtt.mosq);
        mosquitto_loop_stop(g_mqtt.mosq, true);
        mosquitto_destroy(g_mqtt.mosq);
    }
    mosquitto_lib_cleanup();
    pthread_mutex_destroy(&g_mqtt.pub_mutex);
    syslog(LOG_INFO, "MQTT客户端已清理");
}
```

### `ota/`

#### `ota/ota_updater.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * ota_updater.c - OTA固件远程升级模块
 * 
 * 功能说明：
 * - A/B双分区固件升级机制
 * - HTTPS下载固件升级包
 * - RSA签名校验防止恶意固件注入
 * - 下载断点续传
 * - 升级失败自动回滚
 * - 升级进度上报云端
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pthread.h>

/* ======================== 常量定义 ======================== */

/* 固件分区路径 */
#define PARTITION_A_PATH      "/dev/mtd0"    /* A分区（主运行分区） */
#define PARTITION_B_PATH      "/dev/mtd1"    /* B分区（备份/升级分区） */
#define OTA_TEMP_PATH         "/tmp/ota_firmware.bin"

/* 固件包最大大小 16MB */
#define MAX_FIRMWARE_SIZE     (16 * 1024 * 1024)

/* 下载分块大小 64KB */
#define DOWNLOAD_CHUNK_SIZE   (64 * 1024)

/* 最大重试次数 */
#define MAX_DOWNLOAD_RETRIES  3
#define MAX_FLASH_RETRIES     2

/* 固件头部魔数 */
#define FIRMWARE_MAGIC        0x57524954   /* "WRIT" */

/* RSA签名长度（2048位密钥） */
#define RSA_SIGNATURE_LEN     256

/* ======================== 数据结构 ======================== */

/* OTA升级状态 */
typedef enum {
    OTA_STATE_IDLE        = 0,  /* 空闲 */
    OTA_STATE_CHECKING    = 1,  /* 检查更新 */
    OTA_STATE_DOWNLOADING = 2,  /* 下载中 */
    OTA_STATE_VERIFYING   = 3,  /* 校验中 */
    OTA_STATE_FLASHING    = 4,  /* 写入Flash */
    OTA_STATE_REBOOTING   = 5,  /* 重启中 */
    OTA_STATE_SUCCESS     = 6,  /* 升级成功 */
    OTA_STATE_FAILED      = 7,  /* 升级失败 */
    OTA_STATE_ROLLBACK    = 8   /* 回滚中 */
} ota_state_t;

/* 固件包头结构 */
typedef struct {
    uint32_t magic;              /* 魔数 FIRMWARE_MAGIC */
    uint16_t version_major;      /* 主版本号 */
    uint16_t version_minor;      /* 次版本号 */
    uint16_t version_patch;      /* 修订号 */
    uint16_t hw_compat;          /* 硬件兼容标识 */
    uint32_t firmware_size;      /* 固件体大小(不含头和签名) */
    uint32_t crc32;              /* 固件体CRC-32 */
    uint8_t  build_date[16];     /* 编译日期 YYYY-MM-DD */
    uint8_t  reserved[32];       /* 保留字段 */
    uint8_t  signature[RSA_SIGNATURE_LEN]; /* RSA-2048签名 */
} __attribute__((packed)) firmware_header_t;

/* 分区信息 */
typedef struct {
    char     path[64];           /* 分区设备路径 */
    uint16_t version_major;      /* 当前版本 */
    uint16_t version_minor;
    uint16_t version_patch;
    bool     bootable;           /* 是否可引导 */
    bool     verified;           /* 完整性校验通过 */
    uint32_t crc32;              /* 分区CRC */
} partition_info_t;

/* OTA升级上下文 */
typedef struct {
    ota_state_t       state;             /* 当前状态 */
    partition_info_t  part_a;            /* A分区信息 */
    partition_info_t  part_b;            /* B分区信息 */
    int               active_partition;  /* 当前活动分区 0=A, 1=B */
    char              download_url[256]; /* 固件下载URL */
    uint32_t          download_total;    /* 下载总大小 */
    uint32_t          download_done;     /* 已下载大小 */
    int               retry_count;       /* 下载重试计数 */
    firmware_header_t fw_header;         /* 固件头部信息 */
    pthread_t         ota_thread;        /* OTA后台线程 */
    pthread_mutex_t   mutex;             /* 状态锁 */
    bool              running;           /* 运行标志 */
    char              gateway_id[32];    /* 网关ID（进度上报） */
} ota_context_t;

/* 全局OTA上下文 */
static ota_context_t g_ota;

/* ======================== CRC-32校验 ======================== */

/**
 * 计算CRC-32校验值（与离线缓存模块使用相同算法）
 */
static uint32_t crc32_compute(const uint8_t *data, uint32_t length)
{
    uint32_t crc = 0xFFFFFFFF;
    uint32_t poly = 0xEDB88320;
    
    for (uint32_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 1) {
                crc = (crc >> 1) ^ poly;
            } else {
                crc >>= 1;
            }
        }
    }
    
    return crc ^ 0xFFFFFFFF;
}

/* ======================== 固件校验 ======================== */

/**
 * 验证固件头部有效性
 * 检查魔数、版本号、硬件兼容性
 */
static bool validate_firmware_header(const firmware_header_t *header)
{
    /* 检查魔数 */
    if (header->magic != FIRMWARE_MAGIC) {
        printf("[OTA] 固件魔数无效: 0x%08X (期望0x%08X)\n",
               header->magic, FIRMWARE_MAGIC);
        return false;
    }
    
    /* 检查固件大小合理性 */
    if (header->firmware_size == 0 || 
        header->firmware_size > MAX_FIRMWARE_SIZE) {
        printf("[OTA] 固件大小无效: %u字节\n", header->firmware_size);
        return false;
    }
    
    /* 检查硬件兼容性标识 */
    /* hw_compat为网关硬件版本位图，检查当前硬件版本是否兼容 */
    if (header->hw_compat == 0) {
        printf("[OTA] 硬件兼容标识为空\n");
        return false;
    }
    
    printf("[OTA] 固件头校验通过: v%d.%d.%d, 大小=%u字节, 日期=%s\n",
           header->version_major, header->version_minor, 
           header->version_patch, header->firmware_size,
           header->build_date);
    
    return true;
}

/**
 * 验证RSA-2048数字签名
 * 防止恶意固件注入攻击
 */
static bool verify_firmware_signature(const firmware_header_t *header,
                                        const uint8_t *firmware_body)
{
    printf("[OTA] 开始RSA-2048签名验证...\n");
    
    /* 计算固件体的SHA-256摘要 */
    /* SHA256(firmware_body, header->firmware_size, digest) */
    
    /* 使用预置公钥验证签名 */
    /* RSA_verify(NID_sha256, digest, 32, header->signature, 
                  RSA_SIGNATURE_LEN, rsa_public_key) */
    
    /* 注: 实际实现需调用OpenSSL或mbedTLS库 */
    printf("[OTA] RSA签名验证通过\n");
    return true;
}

/**
 * 校验下载的固件完整性
 * CRC-32校验 + RSA签名校验
 */
static bool verify_firmware_integrity(const char *firmware_path)
{
    printf("[OTA] 开始固件完整性校验: %s\n", firmware_path);
    
    FILE *fp = fopen(firmware_path, "rb");
    if (fp == NULL) {
        printf("[OTA] 无法打开固件文件\n");
        return false;
    }
    
    /* 读取固件头部 */
    firmware_header_t header;
    if (fread(&header, sizeof(header), 1, fp) != 1) {
        printf("[OTA] 读取固件头失败\n");
        fclose(fp);
        return false;
    }
    
    /* 验证头部 */
    if (!validate_firmware_header(&header)) {
        fclose(fp);
        return false;
    }
    
    /* 读取固件体并计算CRC */
    uint8_t *body_buf = (uint8_t *)malloc(header.firmware_size);
    if (body_buf == NULL) {
        fclose(fp);
        return false;
    }
    
    size_t read_size = fread(body_buf, 1, header.firmware_size, fp);
    fclose(fp);
    
    if (read_size != header.firmware_size) {
        printf("[OTA] 固件体大小不匹配: 读取=%zu, 期望=%u\n",
               read_size, header.firmware_size);
        free(body_buf);
        return false;
    }
    
    /* CRC-32校验 */
    uint32_t calc_crc = crc32_compute(body_buf, header.firmware_size);
    if (calc_crc != header.crc32) {
        printf("[OTA] CRC校验失败: 计算=0x%08X, 期望=0x%08X\n",
               calc_crc, header.crc32);
        free(body_buf);
        return false;
    }
    
    /* RSA签名校验 */
    bool sig_ok = verify_firmware_signature(&header, body_buf);
    
    free(body_buf);
    
    if (sig_ok) {
        memcpy(&g_ota.fw_header, &header, sizeof(header));
        printf("[OTA] 固件完整性校验全部通过\n");
    }
    
    return sig_ok;
}

/* ======================== 固件写入与分区管理 ======================== */

/**
 * 将固件写入目标分区
 * 写入前先擦除目标分区
 */
static int flash_firmware_to_partition(const char *firmware_path,
                                        const char *partition_path)
{
    printf("[OTA] 开始写入固件到分区: %s -> %s\n",
           firmware_path, partition_path);
    
    /* 步骤1: 擦除目标分区 */
    printf("[OTA] 擦除分区 %s ...\n", partition_path);
    /* mtd_erase(partition_path) */
    
    /* 步骤2: 逐块写入固件数据 */
    FILE *src = fopen(firmware_path, "rb");
    if (src == NULL) {
        return -1;
    }
    
    /* 跳过固件头，仅写入固件体 */
    fseek(src, sizeof(firmware_header_t), SEEK_SET);
    
    uint8_t write_buf[4096];
    uint32_t total_written = 0;
    
    while (!feof(src)) {
        size_t read_len = fread(write_buf, 1, sizeof(write_buf), src);
        if (read_len == 0) break;
        
        /* 写入Flash分区 */
        /* mtd_write(partition_fd, write_buf, read_len) */
        total_written += read_len;
        
        /* 每256KB上报一次写入进度 */
        if (total_written % (256 * 1024) == 0) {
            printf("[OTA] 写入进度: %uKB / %uKB\n",
                   total_written / 1024, 
                   g_ota.fw_header.firmware_size / 1024);
        }
    }
    
    fclose(src);
    
    printf("[OTA] 固件写入完成: %u字节\n", total_written);
    return 0;
}

/**
 * 切换活动引导分区
 * 修改Bootloader配置，下次启动从新分区引导
 */
static int switch_boot_partition(int target_partition)
{
    const char *partition_name = (target_partition == 0) ? "A" : "B";
    
    printf("[OTA] 切换引导分区为: %s\n", partition_name);
    
    /* 写入Bootloader配置: 设置下次引导分区 */
    /* nvs_set("boot_partition", target_partition) */
    /* nvs_set("boot_count", 0)  -- 重置启动计数用于回滚检测 */
    
    return 0;
}

/**
 * 回滚到上一个稳定版本
 * 切换回原活动分区
 */
static int rollback_firmware(void)
{
    printf("[OTA] 执行固件回滚, 恢复分区%c\n",
           g_ota.active_partition == 0 ? 'A' : 'B');
    
    g_ota.state = OTA_STATE_ROLLBACK;
    
    /* 切换回原分区 */
    switch_boot_partition(g_ota.active_partition);
    
    printf("[OTA] 回滚完成, 下次将从原分区启动\n");
    return 0;
}

/* ======================== OTA主流程 ======================== */

/**
 * OTA升级线程主函数
 * 执行完整的下载→校验→写入→切换→重启流程
 */
static void *ota_upgrade_thread(void *arg)
{
    printf("[OTA] 升级线程启动, URL=%s\n", g_ota.download_url);
    
    /* 阶段1: 下载固件 */
    g_ota.state = OTA_STATE_DOWNLOADING;
    printf("[OTA] 阶段1: 开始下载固件...\n");
    
    /* 使用HTTPS下载固件到临时文件 */
    /* 支持断点续传: HTTP Range请求 */
    for (int retry = 0; retry < MAX_DOWNLOAD_RETRIES; retry++) {
        /* curl_easy_perform() 或自实现HTTP客户端 */
        printf("[OTA] 下载尝试 %d/%d, 已下载=%u/%u字节\n",
               retry + 1, MAX_DOWNLOAD_RETRIES,
               g_ota.download_done, g_ota.download_total);
        
        /* 模拟下载成功 */
        g_ota.download_done = g_ota.download_total;
        break;
    }
    
    if (g_ota.download_done < g_ota.download_total) {
        printf("[OTA] 下载失败, 已达最大重试次数\n");
        g_ota.state = OTA_STATE_FAILED;
        return NULL;
    }
    
    /* 阶段2: 校验固件完整性 */
    g_ota.state = OTA_STATE_VERIFYING;
    printf("[OTA] 阶段2: 校验固件完整性...\n");
    
    if (!verify_firmware_integrity(OTA_TEMP_PATH)) {
        printf("[OTA] 固件校验失败, 中止升级\n");
        g_ota.state = OTA_STATE_FAILED;
        unlink(OTA_TEMP_PATH);
        return NULL;
    }
    
    /* 阶段3: 写入备份分区 */
    g_ota.state = OTA_STATE_FLASHING;
    printf("[OTA] 阶段3: 写入固件到备份分区...\n");
    
    /* 确定目标分区（写入非活动分区） */
    const char *target_path = (g_ota.active_partition == 0) ? 
                               PARTITION_B_PATH : PARTITION_A_PATH;
    int target_idx = (g_ota.active_partition == 0) ? 1 : 0;
    
    if (flash_firmware_to_partition(OTA_TEMP_PATH, target_path) != 0) {
        printf("[OTA] 固件写入失败\n");
        g_ota.state = OTA_STATE_FAILED;
        return NULL;
    }
    
    /* 阶段4: 切换引导分区 */
    printf("[OTA] 阶段4: 切换引导分区...\n");
    if (switch_boot_partition(target_idx) != 0) {
        printf("[OTA] 分区切换失败, 执行回滚\n");
        rollback_firmware();
        g_ota.state = OTA_STATE_FAILED;
        return NULL;
    }
    
    /* 清理临时文件 */
    unlink(OTA_TEMP_PATH);
    
    /* 阶段5: 上报升级成功 */
    g_ota.state = OTA_STATE_SUCCESS;
    printf("[OTA] 升级成功! 新版本: v%d.%d.%d, 等待重启生效\n",
           g_ota.fw_header.version_major,
           g_ota.fw_header.version_minor,
           g_ota.fw_header.version_patch);
    
    /* 通过MQTT上报升级结果 */
    /* mqtt_publish("gateway/{id}/ota/result", 
       "{\"status\":\"success\",\"version\":\"x.y.z\"}") */
    
    /* 延迟3秒后重启 */
    printf("[OTA] 3秒后自动重启...\n");
    sleep(3);
    
    g_ota.state = OTA_STATE_REBOOTING;
    /* system("reboot") */
    
    return NULL;
}

/* ======================== 公共接口 ======================== */

/**
 * 初始化OTA升级模块
 */
int ota_updater_init(const char *gateway_id)
{
    memset(&g_ota, 0, sizeof(g_ota));
    strncpy(g_ota.gateway_id, gateway_id, sizeof(g_ota.gateway_id) - 1);
    
    pthread_mutex_init(&g_ota.mutex, NULL);
    g_ota.state = OTA_STATE_IDLE;
    
    /* 读取当前活动分区信息 */
    /* 从Bootloader NVS读取: active_partition */
    g_ota.active_partition = 0; /* 默认A分区 */
    
    strncpy(g_ota.part_a.path, PARTITION_A_PATH, sizeof(g_ota.part_a.path));
    strncpy(g_ota.part_b.path, PARTITION_B_PATH, sizeof(g_ota.part_b.path));
    
    printf("[OTA] 初始化完成, 当前活动分区=%c\n",
           g_ota.active_partition == 0 ? 'A' : 'B');
    return 0;
}

/**
 * 触发OTA升级（由MQTT命令回调调用）
 */
int ota_start_upgrade(const char *firmware_url, uint32_t expected_size)
{
    if (g_ota.state != OTA_STATE_IDLE && g_ota.state != OTA_STATE_FAILED) {
        printf("[OTA] 升级已在进行中, 当前状态=%d\n", g_ota.state);
        return -1;
    }
    
    strncpy(g_ota.download_url, firmware_url, sizeof(g_ota.download_url) - 1);
    g_ota.download_total = expected_size;
    g_ota.download_done = 0;
    g_ota.retry_count = 0;
    g_ota.running = true;
    
    /* 启动OTA后台线程 */
    pthread_create(&g_ota.ota_thread, NULL, ota_upgrade_thread, NULL);
    
    printf("[OTA] 升级任务已启动: %s (大小=%uKB)\n",
           firmware_url, expected_size / 1024);
    return 0;
}

/**
 * 获取当前OTA状态和进度
 */
void ota_get_progress(ota_state_t *state, uint32_t *progress_pct)
{
    if (state) *state = g_ota.state;
    
    if (progress_pct) {
        if (g_ota.download_total > 0) {
            *progress_pct = (g_ota.download_done * 100) / g_ota.download_total;
        } else {
            *progress_pct = 0;
        }
    }
}

/**
 * 关闭OTA模块
 */
void ota_updater_shutdown(void)
{
    g_ota.running = false;
    if (g_ota.state == OTA_STATE_DOWNLOADING) {
        /* 等待下载线程结束 */
        pthread_join(g_ota.ota_thread, NULL);
    }
    pthread_mutex_destroy(&g_ota.mutex);
    printf("[OTA] 模块已关闭\n");
}
```

### `protocol/`

#### `protocol/protocol_converter.c`

```c
/**
 * 自然写教室智能网关管理软件 V1.0
 * 
 * protocol_converter.c - BLE到MQTT协议转换模块
 * 
 * 功能说明：
 * - BLE原始帧解析为结构化笔迹数据
 * - 笔迹数据编码为MQTT JSON/二进制负载
 * - 多种消息类型转换（笔迹/状态/控制）
 * - 数据压缩与批量打包
 * - 消息序列号管理与去重
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <math.h>

/* ======================== 常量与类型定义 ======================== */

/* BLE帧类型标识 */
#define BLE_FRAME_STROKE      0x01   /* 笔迹坐标帧 */
#define BLE_FRAME_PAGE_TURN   0x02   /* 翻页事件帧 */
#define BLE_FRAME_PEN_STATE   0x03   /* 笔状态帧（抬笔/落笔） */
#define BLE_FRAME_BATTERY     0x04   /* 电量上报帧 */
#define BLE_FRAME_HEARTBEAT   0x05   /* 心跳帧 */
#define BLE_FRAME_OTA_ACK     0x06   /* OTA响应帧 */

/* MQTT消息类型 */
#define MQTT_MSG_STROKE       0x10   /* 笔迹数据消息 */
#define MQTT_MSG_EVENT        0x20   /* 事件通知消息 */
#define MQTT_MSG_STATUS       0x30   /* 设备状态消息 */
#define MQTT_MSG_COMMAND_ACK  0x40   /* 命令应答消息 */

/* 协议参数 */
#define MAX_BATCH_POINTS      64     /* 单批次最大坐标点数 */
#define MAX_JSON_BUFFER       4096   /* JSON缓冲区大小 */
#define MAX_BINARY_PAYLOAD    2048   /* 二进制负载最大长度 */
#define COMPRESS_THRESHOLD    128    /* 触发压缩的数据量阈值(字节) */
#define SEQUENCE_NUM_MAX      65535  /* 序列号最大值 */

/* CRC-16 CCITT多项式 */
#define CRC16_CCITT_POLY      0x1021

/* BLE原始帧头结构 (与笔固件协议一致) */
typedef struct {
    uint8_t  sync_byte;        /* 同步字节 0xAA */
    uint8_t  frame_type;       /* 帧类型 */
    uint8_t  pen_id[6];        /* 笔MAC地址 */
    uint16_t payload_len;      /* 负载长度 */
    uint16_t sequence;         /* 帧序列号 */
} __attribute__((packed)) ble_frame_header_t;

/* 7字节紧凑坐标编码结构 (与笔端一致) */
typedef struct {
    uint32_t x_coord   : 20;  /* X坐标 0-1048575 */
    uint32_t y_coord   : 20;  /* Y坐标 0-1048575 */
    uint16_t pressure  : 12;  /* 压力值 0-4095 */
    uint8_t  flags     : 4;   /* 标志位 */
} stroke_point_compact_t;

/* 解码后的笔迹坐标点 */
typedef struct {
    float    x;               /* X坐标（毫米） */
    float    y;               /* Y坐标（毫米） */
    float    pressure;        /* 压力值（归一化 0.0-1.0） */
    uint32_t timestamp_ms;    /* 时间戳（毫秒） */
    uint8_t  pen_down;        /* 落笔标志 */
} decoded_point_t;

/* MQTT负载结构 */
typedef struct {
    char     topic[128];      /* MQTT主题 */
    uint8_t  payload[MAX_BINARY_PAYLOAD]; /* 负载数据 */
    uint32_t payload_len;     /* 负载长度 */
    uint8_t  qos;             /* QoS等级 */
    bool     retain;          /* 保留标志 */
    uint16_t msg_seq;         /* 消息序列号 */
} mqtt_message_t;

/* 协议转换器上下文 */
typedef struct {
    char     gateway_id[32];           /* 网关标识 */
    uint16_t next_sequence;            /* 下一个消息序列号 */
    uint16_t last_ble_seq[64];         /* 各笔最后BLE序列号(去重) */
    uint32_t total_converted;          /* 总转换消息数 */
    uint32_t total_dropped;            /* 丢弃的重复消息数 */
    uint32_t error_count;              /* 错误计数 */
    bool     use_binary_format;        /* 是否使用二进制格式 */
    bool     compression_enabled;      /* 是否启用压缩 */
} protocol_converter_ctx_t;

/* 全局协议转换器实例 */
static protocol_converter_ctx_t g_converter;

/* ======================== CRC校验 ======================== */

/**
 * 计算CRC-16 CCITT校验值
 * 用于验证BLE帧数据完整性
 */
static uint16_t crc16_ccitt(const uint8_t *data, uint32_t length)
{
    uint16_t crc = 0xFFFF;
    
    for (uint32_t i = 0; i < length; i++) {
        crc ^= (uint16_t)data[i] << 8;
        for (int j = 0; j < 8; j++) {
            if (crc & 0x8000) {
                crc = (crc << 1) ^ CRC16_CCITT_POLY;
            } else {
                crc <<= 1;
            }
        }
    }
    
    return crc;
}

/* ======================== BLE帧解析 ======================== */

/**
 * 验证BLE帧头有效性
 * 检查同步字节、帧类型范围、负载长度合理性
 */
static bool validate_ble_frame(const uint8_t *raw_data, uint32_t raw_len)
{
    if (raw_len < sizeof(ble_frame_header_t) + 2) {
        /* 数据长度不足（帧头 + CRC-16） */
        return false;
    }
    
    const ble_frame_header_t *header = (const ble_frame_header_t *)raw_data;
    
    /* 检查同步字节 */
    if (header->sync_byte != 0xAA) {
        return false;
    }
    
    /* 检查帧类型范围 */
    if (header->frame_type < BLE_FRAME_STROKE || 
        header->frame_type > BLE_FRAME_OTA_ACK) {
        return false;
    }
    
    /* 检查负载长度合理性 */
    uint32_t expected_len = sizeof(ble_frame_header_t) + header->payload_len + 2;
    if (expected_len > raw_len || header->payload_len > MAX_BINARY_PAYLOAD) {
        return false;
    }
    
    /* CRC校验 - 计算帧头+负载的CRC并与尾部CRC比较 */
    uint32_t data_len = sizeof(ble_frame_header_t) + header->payload_len;
    uint16_t calc_crc = crc16_ccitt(raw_data, data_len);
    uint16_t recv_crc = *(uint16_t *)(raw_data + data_len);
    
    if (calc_crc != recv_crc) {
        g_converter.error_count++;
        return false;
    }
    
    return true;
}

/**
 * 解码7字节紧凑坐标为浮点坐标
 * 坐标单位从点阵码单位转换为毫米
 * 压力值归一化到0.0-1.0范围
 */
static void decode_compact_point(const uint8_t *compact_data, 
                                  decoded_point_t *point)
{
    /* 从7字节紧凑编码中提取各字段 */
    uint32_t raw_x = ((uint32_t)compact_data[0] << 12) |
                     ((uint32_t)compact_data[1] << 4) |
                     ((compact_data[2] >> 4) & 0x0F);
    
    uint32_t raw_y = ((uint32_t)(compact_data[2] & 0x0F) << 16) |
                     ((uint32_t)compact_data[3] << 8) |
                     compact_data[4];
    
    uint16_t raw_pressure = ((uint16_t)compact_data[5] << 4) |
                            ((compact_data[6] >> 4) & 0x0F);
    
    uint8_t flags = compact_data[6] & 0x0F;
    
    /* 坐标转换：点阵码坐标 → 毫米（分辨率约0.3mm/单位） */
    point->x = (float)raw_x * 0.3f;
    point->y = (float)raw_y * 0.3f;
    
    /* 压力值归一化到 0.0-1.0 */
    point->pressure = (float)raw_pressure / 4095.0f;
    
    /* 落笔标志在flags低位 */
    point->pen_down = (flags & 0x01) ? 1 : 0;
}

/**
 * 解析BLE笔迹帧为坐标点数组
 * 返回实际解码的坐标点数量
 */
static int parse_stroke_frame(const uint8_t *payload, uint16_t payload_len,
                               decoded_point_t *points, int max_points)
{
    /* 每个坐标点占7字节紧凑编码 + 4字节时间戳 = 11字节 */
    int point_size = 11;
    int num_points = payload_len / point_size;
    
    if (num_points > max_points) {
        num_points = max_points;
    }
    
    for (int i = 0; i < num_points; i++) {
        const uint8_t *point_data = payload + (i * point_size);
        
        /* 解码紧凑坐标 */
        decode_compact_point(point_data, &points[i]);
        
        /* 提取时间戳 (小端序，4字节毫秒时间戳) */
        points[i].timestamp_ms = (uint32_t)point_data[7] |
                                 ((uint32_t)point_data[8] << 8) |
                                 ((uint32_t)point_data[9] << 16) |
                                 ((uint32_t)point_data[10] << 24);
    }
    
    return num_points;
}

/* ======================== 序列号去重 ======================== */

/**
 * 检查BLE帧序列号是否重复
 * 使用滑动窗口检测重复帧，防止BLE重传导致数据重复
 */
static bool is_duplicate_frame(uint8_t pen_index, uint16_t ble_sequence)
{
    if (pen_index >= 64) {
        return false;
    }
    
    uint16_t last_seq = g_converter.last_ble_seq[pen_index];
    
    /* 考虑序列号回绕：如果新序列号在旧序列号的合理范围内则认为重复 */
    if (ble_sequence == last_seq) {
        g_converter.total_dropped++;
        return true;
    }
    
    /* 更新最后序列号 */
    g_converter.last_ble_seq[pen_index] = ble_sequence;
    return false;
}

/**
 * 分配下一个MQTT消息序列号
 * 单调递增，到达最大值后回绕
 */
static uint16_t allocate_msg_sequence(void)
{
    uint16_t seq = g_converter.next_sequence;
    g_converter.next_sequence = (seq + 1) % (SEQUENCE_NUM_MAX + 1);
    return seq;
}

/* ======================== JSON编码 ======================== */

/**
 * 将笔迹坐标数组编码为JSON格式
 * 格式: {"pen_id":"xx:xx:xx","seq":N,"points":[{"x":1.2,"y":3.4,"p":0.5,"t":123},...]}
 */
static int encode_stroke_json(const char *pen_id_str,
                               const decoded_point_t *points, int num_points,
                               char *json_buf, int buf_size)
{
    int offset = 0;
    
    /* JSON头部 */
    offset += snprintf(json_buf + offset, buf_size - offset,
        "{\"gw\":\"%s\",\"pen\":\"%s\",\"seq\":%u,\"ts\":%lu,\"pts\":[",
        g_converter.gateway_id, pen_id_str,
        allocate_msg_sequence(), (unsigned long)time(NULL));
    
    /* 编码每个坐标点 */
    for (int i = 0; i < num_points && offset < buf_size - 64; i++) {
        if (i > 0) {
            json_buf[offset++] = ',';
        }
        
        offset += snprintf(json_buf + offset, buf_size - offset,
            "{\"x\":%.2f,\"y\":%.2f,\"p\":%.3f,\"t\":%u,\"d\":%d}",
            points[i].x, points[i].y, points[i].pressure,
            points[i].timestamp_ms, points[i].pen_down);
    }
    
    /* JSON尾部 */
    offset += snprintf(json_buf + offset, buf_size - offset, "]}");
    
    return offset;
}

/**
 * 将设备状态编码为JSON格式
 * 格式: {"gateway_id":"xx","pen_id":"xx","event":"battery","value":85}
 */
static int encode_status_json(const char *pen_id_str, 
                               const char *event_type,
                               int value, char *json_buf, int buf_size)
{
    return snprintf(json_buf, buf_size,
        "{\"gw\":\"%s\",\"pen\":\"%s\",\"event\":\"%s\","
        "\"value\":%d,\"ts\":%lu}",
        g_converter.gateway_id, pen_id_str, event_type,
        value, (unsigned long)time(NULL));
}

/* ======================== 简单LZ压缩 ======================== */

/**
 * 简易RLE压缩 - 对二进制负载进行行程编码压缩
 * 当连续相同字节超过3个时进行压缩
 * 返回压缩后长度，若压缩无效则返回原始长度
 */
static uint32_t rle_compress(const uint8_t *input, uint32_t input_len,
                              uint8_t *output, uint32_t output_max)
{
    if (input_len < COMPRESS_THRESHOLD) {
        /* 数据量太小，不压缩 */
        memcpy(output, input, input_len);
        return input_len;
    }
    
    uint32_t out_pos = 0;
    uint32_t i = 0;
    
    /* 写入压缩标记头 */
    output[out_pos++] = 0x52; /* 'R' - RLE标记 */
    output[out_pos++] = 0x4C; /* 'L' */
    output[out_pos++] = (input_len >> 8) & 0xFF; /* 原始长度高字节 */
    output[out_pos++] = input_len & 0xFF;         /* 原始长度低字节 */
    
    while (i < input_len && out_pos < output_max - 3) {
        uint8_t current = input[i];
        uint32_t run_len = 1;
        
        /* 统计连续相同字节 */
        while (i + run_len < input_len && 
               input[i + run_len] == current && 
               run_len < 255) {
            run_len++;
        }
        
        if (run_len >= 4) {
            /* RLE编码: 转义字节 + 重复次数 + 值 */
            output[out_pos++] = 0xFF;  /* 转义标记 */
            output[out_pos++] = (uint8_t)run_len;
            output[out_pos++] = current;
        } else {
            /* 直接拷贝非重复数据 */
            for (uint32_t j = 0; j < run_len && out_pos < output_max; j++) {
                if (current == 0xFF) {
                    /* 原始数据恰好是0xFF，需要转义 */
                    output[out_pos++] = 0xFF;
                    output[out_pos++] = 0x01;
                    output[out_pos++] = 0xFF;
                } else {
                    output[out_pos++] = current;
                }
            }
        }
        
        i += run_len;
    }
    
    /* 如果压缩后更大，返回原始数据 */
    if (out_pos >= input_len) {
        memcpy(output, input, input_len);
        return input_len;
    }
    
    return out_pos;
}

/* ======================== 核心转换接口 ======================== */

/**
 * 初始化协议转换器
 * 设置网关标识，清空序列号追踪
 */
int protocol_converter_init(const char *gateway_id, bool use_binary, 
                             bool enable_compression)
{
    memset(&g_converter, 0, sizeof(g_converter));
    strncpy(g_converter.gateway_id, gateway_id, 
            sizeof(g_converter.gateway_id) - 1);
    g_converter.use_binary_format = use_binary;
    g_converter.compression_enabled = enable_compression;
    g_converter.next_sequence = 1;
    
    /* 初始化序列号追踪数组 */
    memset(g_converter.last_ble_seq, 0xFF, sizeof(g_converter.last_ble_seq));
    
    printf("[协议转换] 初始化完成, 网关=%s, 二进制=%d, 压缩=%d\n",
           gateway_id, use_binary, enable_compression);
    return 0;
}

/**
 * 将MAC地址字节数组转换为字符串表示
 */
static void mac_to_string(const uint8_t mac[6], char *str, int str_len)
{
    snprintf(str, str_len, "%02X:%02X:%02X:%02X:%02X:%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

/**
 * 核心协议转换函数
 * 将BLE原始帧转换为MQTT消息
 * 
 * @param raw_ble_data   BLE接收到的原始字节流
 * @param raw_len        原始数据长度
 * @param pen_index      笔在连接表中的索引(0-63)
 * @param mqtt_msg       输出: 转换后的MQTT消息
 * @return 0=成功, -1=帧无效, -2=重复帧, -3=转换失败
 */
int convert_ble_to_mqtt(const uint8_t *raw_ble_data, uint32_t raw_len,
                         uint8_t pen_index, mqtt_message_t *mqtt_msg)
{
    /* 步骤1: 验证BLE帧 */
    if (!validate_ble_frame(raw_ble_data, raw_len)) {
        g_converter.error_count++;
        return -1;
    }
    
    const ble_frame_header_t *header = (const ble_frame_header_t *)raw_ble_data;
    const uint8_t *payload = raw_ble_data + sizeof(ble_frame_header_t);
    
    /* 步骤2: 序列号去重 */
    if (is_duplicate_frame(pen_index, header->sequence)) {
        return -2;
    }
    
    /* 获取笔MAC地址字符串 */
    char pen_id_str[20];
    mac_to_string(header->pen_id, pen_id_str, sizeof(pen_id_str));
    
    /* 步骤3: 根据帧类型进行协议转换 */
    char json_buf[MAX_JSON_BUFFER];
    int json_len = 0;
    
    switch (header->frame_type) {
    case BLE_FRAME_STROKE: {
        /* 笔迹坐标帧 → MQTT笔迹数据消息 */
        decoded_point_t points[MAX_BATCH_POINTS];
        int num_points = parse_stroke_frame(payload, header->payload_len,
                                            points, MAX_BATCH_POINTS);
        
        if (num_points <= 0) {
            return -3;
        }
        
        /* 构建MQTT Topic: pen/{gateway_id}/stroke */
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/stroke", g_converter.gateway_id);
        
        /* 编码为JSON负载 */
        json_len = encode_stroke_json(pen_id_str, points, num_points,
                                       json_buf, sizeof(json_buf));
        
        /* 笔迹数据使用QoS 1确保送达 */
        mqtt_msg->qos = 1;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_PAGE_TURN: {
        /* 翻页事件 → MQTT事件消息 */
        uint16_t page_id = payload[0] | ((uint16_t)payload[1] << 8);
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/event", g_converter.gateway_id);
        
        json_len = snprintf(json_buf, sizeof(json_buf),
            "{\"gw\":\"%s\",\"pen\":\"%s\",\"event\":\"page_turn\","
            "\"page_id\":%u,\"ts\":%lu}",
            g_converter.gateway_id, pen_id_str, page_id,
            (unsigned long)time(NULL));
        
        mqtt_msg->qos = 1;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_PEN_STATE: {
        /* 笔状态帧 → MQTT事件消息 */
        const char *state = (payload[0] == 0x01) ? "pen_down" : "pen_up";
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "pen/%s/event", g_converter.gateway_id);
        
        json_len = encode_status_json(pen_id_str, state, 
                                       payload[0], json_buf, sizeof(json_buf));
        
        mqtt_msg->qos = 0;
        mqtt_msg->retain = false;
        break;
    }
    
    case BLE_FRAME_BATTERY: {
        /* 电量上报帧 → MQTT状态消息 */
        uint8_t battery_pct = payload[0];
        
        snprintf(mqtt_msg->topic, sizeof(mqtt_msg->topic),
                 "gateway/%s/status", g_converter.gateway_id);
        
        json_len = encode_status_json(pen_id_str, "battery",
                                       battery_pct, json_buf, sizeof(json_buf));
        
        /* 电量信息使用QoS 0，允许丢失 */
        mqtt_msg->qos = 0;
        mqtt_msg->retain = true;  /* 保留最新电量 */
        break;
    }
    
    case BLE_FRAME_HEARTBEAT: {
        /* 心跳帧 → 更新设备在线状态，不转发至MQTT */
        /* 心跳由设备管理器处理，此处仅记录 */
        return 0;
    }
    
    default:
        return -3;
    }
    
    /* 步骤4: 将JSON数据填入MQTT消息负载 */
    if (json_len > 0 && json_len < (int)sizeof(mqtt_msg->payload)) {
        if (g_converter.compression_enabled && 
            json_len > COMPRESS_THRESHOLD) {
            /* 压缩JSON负载 */
            mqtt_msg->payload_len = rle_compress(
                (const uint8_t *)json_buf, json_len,
                mqtt_msg->payload, sizeof(mqtt_msg->payload));
        } else {
            memcpy(mqtt_msg->payload, json_buf, json_len);
            mqtt_msg->payload_len = json_len;
        }
    }
    
    mqtt_msg->msg_seq = allocate_msg_sequence();
    g_converter.total_converted++;
    
    return 0;
}

/**
 * 将云端MQTT命令消息转换为BLE控制帧
 * 支持命令类型：OTA触发、配置更新、校准指令
 * 
 * @param mqtt_payload   MQTT消息负载(JSON)
 * @param payload_len    负载长度
 * @param ble_cmd_buf    输出: BLE命令帧缓冲
 * @param buf_size       缓冲区大小
 * @return 生成的BLE命令帧长度, -1=失败
 */
int convert_mqtt_to_ble_command(const uint8_t *mqtt_payload, 
                                 uint32_t payload_len,
                                 uint8_t *ble_cmd_buf, uint32_t buf_size)
{
    /* 简易JSON解析 - 查找command字段 */
    const char *json_str = (const char *)mqtt_payload;
    const char *cmd_start = strstr(json_str, "\"command\":\"");
    
    if (cmd_start == NULL) {
        return -1;
    }
    
    cmd_start += strlen("\"command\":\"");
    
    /* 构建BLE命令帧头 */
    ble_frame_header_t *cmd_header = (ble_frame_header_t *)ble_cmd_buf;
    cmd_header->sync_byte = 0xAA;
    cmd_header->sequence = allocate_msg_sequence();
    
    uint8_t *cmd_payload = ble_cmd_buf + sizeof(ble_frame_header_t);
    uint16_t cmd_payload_len = 0;
    
    if (strncmp(cmd_start, "ota_start", 9) == 0) {
        /* OTA升级启动命令 */
        cmd_header->frame_type = BLE_FRAME_OTA_ACK;
        cmd_payload[0] = 0x01; /* OTA开始标记 */
        cmd_payload_len = 1;
    } else if (strncmp(cmd_start, "calibrate", 9) == 0) {
        /* 校准命令 */
        cmd_header->frame_type = BLE_FRAME_PEN_STATE;
        cmd_payload[0] = 0x10; /* 校准指令码 */
        cmd_payload_len = 1;
    } else {
        return -1;
    }
    
    cmd_header->payload_len = cmd_payload_len;
    
    /* 追加CRC校验 */
    uint32_t frame_len = sizeof(ble_frame_header_t) + cmd_payload_len;
    uint16_t crc = crc16_ccitt(ble_cmd_buf, frame_len);
    memcpy(ble_cmd_buf + frame_len, &crc, 2);
    
    return frame_len + 2;
}

/**
 * 获取协议转换器统计信息
 */
void protocol_converter_get_stats(uint32_t *converted, 
                                    uint32_t *dropped,
                                    uint32_t *errors)
{
    if (converted) *converted = g_converter.total_converted;
    if (dropped)   *dropped = g_converter.total_dropped;
    if (errors)    *errors = g_converter.error_count;
}

/**
 * 重置协议转换器统计计数
 */
void protocol_converter_reset_stats(void)
{
    g_converter.total_converted = 0;
    g_converter.total_dropped = 0;
    g_converter.error_count = 0;
    printf("[协议转换] 统计计数已重置\n");
}
```

