software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,332 @@
/*
* 自然写互动课堂教学管理网关软件 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;
}