增加事件驱动和业务回滚处理方式
This commit is contained in:
166
app/error_handler.c
Normal file
166
app/error_handler.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* error_handler.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 错误处理与恢复模块实现
|
||||
* 依赖: RT-Thread Nano, osal, transaction, state_manager
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "transaction.h"
|
||||
#include "state_manager.h"
|
||||
#include "error_handler.h"
|
||||
|
||||
/**
|
||||
* @brief 处理网络错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
static int handle_network_error(error_code_t error, void *user_data)
|
||||
{
|
||||
osal_log_e("Network error: %d", error);
|
||||
|
||||
/* 设置网络状态为错误 */
|
||||
state_manager_set_network_state(NETWORK_STATE_ERROR);
|
||||
|
||||
/* 尝试恢复网络连接 */
|
||||
osal_log_i("Attempting to recover network connection...");
|
||||
|
||||
/* 这里可以添加具体的网络恢复逻辑,比如重新连接、重启网络接口等 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理传感器错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
static int handle_sensor_error(error_code_t error, void *user_data)
|
||||
{
|
||||
osal_log_e("Sensor error: %d", error);
|
||||
|
||||
/* 设置传感器状态为错误 */
|
||||
state_manager_set_sensor_state(SENSOR_STATE_ERROR);
|
||||
|
||||
/* 尝试恢复传感器 */
|
||||
osal_log_i("Attempting to recover sensor...");
|
||||
|
||||
/* 这里可以添加具体的传感器恢复逻辑,比如重新初始化传感器等 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理TCP错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
static int handle_tcp_error(error_code_t error, void *user_data)
|
||||
{
|
||||
osal_log_e("TCP error: %d", error);
|
||||
|
||||
/* 设置TCP状态为错误 */
|
||||
state_manager_set_tcp_state(TCP_STATE_ERROR);
|
||||
|
||||
/* 尝试恢复TCP连接 */
|
||||
osal_log_i("Attempting to recover TCP connection...");
|
||||
|
||||
/* 这里可以添加具体的TCP恢复逻辑,比如重新建立连接等 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理未知错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
static int handle_unknown_error(error_code_t error, void *user_data)
|
||||
{
|
||||
osal_log_e("Unknown error: %d", error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化错误处理器
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_init(void)
|
||||
{
|
||||
osal_log_i("Error handler initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_process(error_code_t error, void *user_data)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_NETWORK:
|
||||
return handle_network_error(error, user_data);
|
||||
case ERROR_SENSOR:
|
||||
return handle_sensor_error(error, user_data);
|
||||
case ERROR_TCP:
|
||||
return handle_tcp_error(error, user_data);
|
||||
case ERROR_UNKNOWN:
|
||||
default:
|
||||
return handle_unknown_error(error, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录错误日志
|
||||
* @param error 错误代码
|
||||
* @param message 错误信息
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_log(error_code_t error, const char *message)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_NETWORK:
|
||||
osal_log_e("[NETWORK ERROR] %s", message);
|
||||
break;
|
||||
case ERROR_SENSOR:
|
||||
osal_log_e("[SENSOR ERROR] %s", message);
|
||||
break;
|
||||
case ERROR_TCP:
|
||||
osal_log_e("[TCP ERROR] %s", message);
|
||||
break;
|
||||
case ERROR_UNKNOWN:
|
||||
default:
|
||||
osal_log_e("[UNKNOWN ERROR] %s", message);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 触发错误报警
|
||||
* @param error 错误代码
|
||||
* @param message 错误信息
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_alert(error_code_t error, const char *message)
|
||||
{
|
||||
/* 这里可以添加具体的报警逻辑,比如发送通知、触发LED闪烁等 */
|
||||
osal_log_e("[ALERT] %s", message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
49
app/error_handler.h
Normal file
49
app/error_handler.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* error_handler.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 错误处理与恢复模块头文件
|
||||
* 依赖: RT-Thread Nano, osal, transaction, state_manager
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef ERROR_HANDLER_H
|
||||
#define ERROR_HANDLER_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "state_manager.h"
|
||||
|
||||
/**
|
||||
* @brief 初始化错误处理器
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_init(void);
|
||||
|
||||
/**
|
||||
* @brief 处理错误
|
||||
* @param error 错误代码
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_process(error_code_t error, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief 记录错误日志
|
||||
* @param error 错误代码
|
||||
* @param message 错误信息
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_log(error_code_t error, const char *message);
|
||||
|
||||
/**
|
||||
* @brief 触发错误报警
|
||||
* @param error 错误代码
|
||||
* @param message 错误信息
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int error_handler_alert(error_code_t error, const char *message);
|
||||
|
||||
#endif /* ERROR_HANDLER_H */
|
||||
131
app/event_handler.c
Normal file
131
app/event_handler.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* event_handler.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件处理器模块实现
|
||||
* 依赖: RT-Thread Nano, osal, event_queue
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "event_queue.h"
|
||||
#include "event_handler.h"
|
||||
|
||||
/* 事件处理器数组 */
|
||||
static event_handler_t g_event_handlers[EVENT_TYPE_MAX];
|
||||
|
||||
/**
|
||||
* @brief 初始化事件处理器
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_init(void)
|
||||
{
|
||||
/* 初始化事件处理器数组 */
|
||||
for (int i = 0; i < EVENT_TYPE_MAX; i++)
|
||||
{
|
||||
g_event_handlers[i].handler = NULL;
|
||||
g_event_handlers[i].user_data = NULL;
|
||||
}
|
||||
|
||||
osal_log_i("Event handler initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册事件处理器
|
||||
* @param type 事件类型
|
||||
* @param handler 事件处理函数
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_register(event_type_t type, event_handler_func_t handler, void *user_data)
|
||||
{
|
||||
if (type < 0 || type >= EVENT_TYPE_MAX)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handler == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_event_handlers[type].handler = handler;
|
||||
g_event_handlers[type].user_data = user_data;
|
||||
|
||||
osal_log_i("Event handler registered for type %d", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注销事件处理器
|
||||
* @param type 事件类型
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_unregister(event_type_t type)
|
||||
{
|
||||
if (type < 0 || type >= EVENT_TYPE_MAX)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_event_handlers[type].handler = NULL;
|
||||
g_event_handlers[type].user_data = NULL;
|
||||
|
||||
osal_log_i("Event handler unregistered for type %d", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理事件
|
||||
* @param event 事件指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_process(event_t *event)
|
||||
{
|
||||
if (event == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
event_type_t type = event->type;
|
||||
if (type < 0 || type >= EVENT_TYPE_MAX)
|
||||
{
|
||||
osal_log_w("Invalid event type: %d", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event_handler_t *handler = &g_event_handlers[type];
|
||||
if (handler->handler != NULL)
|
||||
{
|
||||
osal_log_d("Processing event type %d", type);
|
||||
return handler->handler(event, handler->user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_d("No handler registered for event type %d", type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 事件分发线程
|
||||
* @param parameter 线程参数
|
||||
*/
|
||||
void event_dispatch_thread(void *parameter)
|
||||
{
|
||||
event_t event;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* 从事件队列中获取事件 */
|
||||
if (event_queue_pop(&event, OSAL_WAIT_FOREVER) == 0)
|
||||
{
|
||||
/* 处理事件 */
|
||||
event_handler_process(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
app/event_handler.h
Normal file
63
app/event_handler.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* event_handler.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件处理器模块头文件
|
||||
* 依赖: RT-Thread Nano, osal, event_queue
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef EVENT_HANDLER_H
|
||||
#define EVENT_HANDLER_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "event_queue.h"
|
||||
|
||||
/* 事件处理函数类型 */
|
||||
typedef int (*event_handler_func_t)(event_t *event, void *user_data);
|
||||
|
||||
/* 事件处理器结构体 */
|
||||
typedef struct {
|
||||
event_handler_func_t handler; /* 事件处理函数 */
|
||||
void *user_data; /* 用户数据 */
|
||||
} event_handler_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化事件处理器
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_init(void);
|
||||
|
||||
/**
|
||||
* @brief 注册事件处理器
|
||||
* @param type 事件类型
|
||||
* @param handler 事件处理函数
|
||||
* @param user_data 用户数据
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_register(event_type_t type, event_handler_func_t handler, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief 注销事件处理器
|
||||
* @param type 事件类型
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_unregister(event_type_t type);
|
||||
|
||||
/**
|
||||
* @brief 处理事件
|
||||
* @param event 事件指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_handler_process(event_t *event);
|
||||
|
||||
/**
|
||||
* @brief 事件分发线程
|
||||
* @param parameter 线程参数
|
||||
*/
|
||||
void event_dispatch_thread(void *parameter);
|
||||
|
||||
#endif /* EVENT_HANDLER_H */
|
||||
203
app/event_queue.c
Normal file
203
app/event_queue.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* event_queue.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件队列模块实现
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "event_queue.h"
|
||||
|
||||
/* 事件队列结构 */
|
||||
static event_queue_t g_event_queue;
|
||||
|
||||
/**
|
||||
* @brief 初始化事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_init(void)
|
||||
{
|
||||
/* 初始化事件队列 */
|
||||
g_event_queue.head = 0;
|
||||
g_event_queue.tail = 0;
|
||||
g_event_queue.count = 0;
|
||||
|
||||
/* 初始化互斥锁 */
|
||||
g_event_queue.mutex = osal_mutex_create("event_mutex");
|
||||
if (g_event_queue.mutex == NULL)
|
||||
{
|
||||
osal_log_e("Failed to create event queue mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 初始化信号量 */
|
||||
g_event_queue.sem = osal_sem_create("event_sem", 0);
|
||||
if (g_event_queue.sem == NULL)
|
||||
{
|
||||
osal_log_e("Failed to create event queue semaphore");
|
||||
osal_mutex_delete(g_event_queue.mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
osal_log_i("Event queue initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 销毁事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_deinit(void)
|
||||
{
|
||||
if (g_event_queue.mutex != NULL)
|
||||
{
|
||||
osal_mutex_delete(g_event_queue.mutex);
|
||||
g_event_queue.mutex = NULL;
|
||||
}
|
||||
|
||||
if (g_event_queue.sem != NULL)
|
||||
{
|
||||
osal_sem_delete(g_event_queue.sem);
|
||||
g_event_queue.sem = NULL;
|
||||
}
|
||||
|
||||
osal_log_i("Event queue deinitialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向事件队列中添加事件
|
||||
* @param event 事件指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_push(event_t *event)
|
||||
{
|
||||
if (event == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 加锁 */
|
||||
if (osal_mutex_take(g_event_queue.mutex, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take event queue mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 检查队列是否已满 */
|
||||
if (g_event_queue.count >= EVENT_QUEUE_SIZE)
|
||||
{
|
||||
osal_log_w("Event queue is full, dropping event");
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 添加事件到队列 */
|
||||
g_event_queue.events[g_event_queue.tail] = *event;
|
||||
g_event_queue.tail = (g_event_queue.tail + 1) % EVENT_QUEUE_SIZE;
|
||||
g_event_queue.count++;
|
||||
|
||||
/* 解锁 */
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
|
||||
/* 释放信号量 */
|
||||
osal_sem_release(g_event_queue.sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从事件队列中获取事件
|
||||
* @param event 事件指针,用于存储获取的事件
|
||||
* @param timeout 超时时间,单位ms
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_pop(event_t *event, int timeout)
|
||||
{
|
||||
if (event == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 等待信号量 */
|
||||
if (osal_sem_take(g_event_queue.sem, timeout) != OSAL_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 加锁 */
|
||||
if (osal_mutex_take(g_event_queue.mutex, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take event queue mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 检查队列是否为空 */
|
||||
if (g_event_queue.count == 0)
|
||||
{
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 从队列中获取事件 */
|
||||
*event = g_event_queue.events[g_event_queue.head];
|
||||
g_event_queue.head = (g_event_queue.head + 1) % EVENT_QUEUE_SIZE;
|
||||
g_event_queue.count--;
|
||||
|
||||
/* 解锁 */
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取事件队列中的事件数量
|
||||
* @return 事件数量
|
||||
*/
|
||||
int event_queue_get_count(void)
|
||||
{
|
||||
int count;
|
||||
|
||||
/* 加锁 */
|
||||
if (osal_mutex_take(g_event_queue.mutex, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take event queue mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = g_event_queue.count;
|
||||
|
||||
/* 解锁 */
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清空事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_clear(void)
|
||||
{
|
||||
/* 加锁 */
|
||||
if (osal_mutex_take(g_event_queue.mutex, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take event queue mutex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 清空队列 */
|
||||
g_event_queue.head = 0;
|
||||
g_event_queue.tail = 0;
|
||||
g_event_queue.count = 0;
|
||||
|
||||
/* 解锁 */
|
||||
osal_mutex_release(g_event_queue.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
101
app/event_queue.h
Normal file
101
app/event_queue.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* event_queue.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件队列模块头文件
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef EVENT_QUEUE_H
|
||||
#define EVENT_QUEUE_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
|
||||
/* 事件类型定义 */
|
||||
typedef enum {
|
||||
EVENT_TYPE_NONE = 0,
|
||||
EVENT_TYPE_SENSOR_DATA,
|
||||
EVENT_TYPE_NETWORK_CONNECTED,
|
||||
EVENT_TYPE_NETWORK_DISCONNECTED,
|
||||
EVENT_TYPE_TCP_CLIENT_CONNECTED,
|
||||
EVENT_TYPE_TCP_CLIENT_DISCONNECTED,
|
||||
EVENT_TYPE_TCP_DATA_RECEIVED,
|
||||
EVENT_TYPE_TIMER,
|
||||
EVENT_TYPE_ERROR,
|
||||
EVENT_TYPE_MAX
|
||||
} event_type_t;
|
||||
|
||||
/* 事件优先级定义 */
|
||||
typedef enum {
|
||||
EVENT_PRIORITY_LOW = 0,
|
||||
EVENT_PRIORITY_NORMAL,
|
||||
EVENT_PRIORITY_HIGH,
|
||||
EVENT_PRIORITY_CRITICAL
|
||||
} event_priority_t;
|
||||
|
||||
/* 事件结构体 */
|
||||
typedef struct {
|
||||
event_type_t type; /* 事件类型 */
|
||||
event_priority_t priority; /* 事件优先级 */
|
||||
void *data; /* 事件数据 */
|
||||
size_t data_size; /* 事件数据大小 */
|
||||
rt_tick_t timestamp; /* 事件时间戳 */
|
||||
} event_t;
|
||||
|
||||
/* 事件队列大小 */
|
||||
#define EVENT_QUEUE_SIZE 64
|
||||
|
||||
/* 事件队列结构体 */
|
||||
typedef struct {
|
||||
event_t events[EVENT_QUEUE_SIZE]; /* 事件数组 */
|
||||
int head; /* 队头索引 */
|
||||
int tail; /* 队尾索引 */
|
||||
int count; /* 事件数量 */
|
||||
osal_mutex_t mutex; /* 互斥锁 */
|
||||
osal_sem_t sem; /* 信号量 */
|
||||
} event_queue_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_init(void);
|
||||
|
||||
/**
|
||||
* @brief 销毁事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief 向事件队列中添加事件
|
||||
* @param event 事件指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_push(event_t *event);
|
||||
|
||||
/**
|
||||
* @brief 从事件队列中获取事件
|
||||
* @param event 事件指针,用于存储获取的事件
|
||||
* @param timeout 超时时间,单位ms
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_pop(event_t *event, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 获取事件队列中的事件数量
|
||||
* @return 事件数量
|
||||
*/
|
||||
int event_queue_get_count(void);
|
||||
|
||||
/**
|
||||
* @brief 清空事件队列
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_queue_clear(void);
|
||||
|
||||
#endif /* EVENT_QUEUE_H */
|
||||
110
app/event_trigger.c
Normal file
110
app/event_trigger.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* event_trigger.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件触发机制模块实现
|
||||
* 依赖: RT-Thread Nano, osal, event_queue
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "event_queue.h"
|
||||
|
||||
/**
|
||||
* @brief 触发事件
|
||||
* @param type 事件类型
|
||||
* @param priority 事件优先级
|
||||
* @param data 事件数据
|
||||
* @param data_size 事件数据大小
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_trigger(event_type_t type, event_priority_t priority, void *data, size_t data_size)
|
||||
{
|
||||
event_t event;
|
||||
|
||||
event.type = type;
|
||||
event.priority = priority;
|
||||
event.data = data;
|
||||
event.data_size = data_size;
|
||||
event.timestamp = rt_tick_get();
|
||||
|
||||
return event_queue_push(&event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器回调函数
|
||||
* @param parameter 定时器参数
|
||||
*/
|
||||
static void timer_callback(void *parameter)
|
||||
{
|
||||
event_type_t event_type = (event_type_t)parameter;
|
||||
event_trigger(event_type, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建定时器事件
|
||||
* @param type 事件类型
|
||||
* @param interval 定时器间隔,单位ms
|
||||
* @return 定时器句柄,失败返回NULL
|
||||
*/
|
||||
osal_timer_t event_timer_create(event_type_t type, int interval)
|
||||
{
|
||||
osal_timer_t timer;
|
||||
|
||||
timer = osal_timer_create("event_timer", timer_callback, (void *)type, interval, 1);
|
||||
if (timer == NULL)
|
||||
{
|
||||
osal_log_e("Failed to create event timer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_start(osal_timer_t timer)
|
||||
{
|
||||
if (timer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return osal_timer_start(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 停止定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_stop(osal_timer_t timer)
|
||||
{
|
||||
if (timer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return osal_timer_stop(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_delete(osal_timer_t timer)
|
||||
{
|
||||
if (timer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return osal_timer_delete(timer);
|
||||
}
|
||||
58
app/event_trigger.h
Normal file
58
app/event_trigger.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* event_trigger.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事件触发机制模块头文件
|
||||
* 依赖: RT-Thread Nano, osal, event_queue
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef EVENT_TRIGGER_H
|
||||
#define EVENT_TRIGGER_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "event_queue.h"
|
||||
|
||||
/**
|
||||
* @brief 触发事件
|
||||
* @param type 事件类型
|
||||
* @param priority 事件优先级
|
||||
* @param data 事件数据
|
||||
* @param data_size 事件数据大小
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_trigger(event_type_t type, event_priority_t priority, void *data, size_t data_size);
|
||||
|
||||
/**
|
||||
* @brief 创建定时器事件
|
||||
* @param type 事件类型
|
||||
* @param interval 定时器间隔,单位ms
|
||||
* @return 定时器句柄,失败返回NULL
|
||||
*/
|
||||
osal_timer_t event_timer_create(event_type_t type, int interval);
|
||||
|
||||
/**
|
||||
* @brief 启动定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_start(osal_timer_t timer);
|
||||
|
||||
/**
|
||||
* @brief 停止定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_stop(osal_timer_t timer);
|
||||
|
||||
/**
|
||||
* @brief 删除定时器事件
|
||||
* @param timer 定时器句柄
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int event_timer_delete(osal_timer_t timer);
|
||||
|
||||
#endif /* EVENT_TRIGGER_H */
|
||||
550
app/main.c
550
app/main.c
@ -11,6 +11,13 @@
|
||||
#include <string.h>
|
||||
#include "lwip/prot/ip4.h"
|
||||
#include "sht40.h"
|
||||
#include "tcp_server.h"
|
||||
#include "event_queue.h"
|
||||
#include "event_handler.h"
|
||||
#include "event_trigger.h"
|
||||
#include "transaction.h"
|
||||
#include "state_manager.h"
|
||||
#include "error_handler.h"
|
||||
|
||||
/* Utility macros */
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
@ -35,11 +42,13 @@ osal_sem_t sem_ip_ready = NULL;
|
||||
#define STATIC_GW_ADDR2 1
|
||||
#define STATIC_GW_ADDR3 1
|
||||
|
||||
/* TCP Server Configuration */
|
||||
#define SERVER_IP_ADDR "192.168.1.116" /* PC IP Address */
|
||||
#define SERVER_PORT 5588
|
||||
|
||||
/* Blink Thread */
|
||||
/**
|
||||
* @brief LED闪烁任务入口函数
|
||||
* @param parameter 任务参数(本函数中未使用)
|
||||
* @note 该函数初始化PA6引脚为输出模式,并在循环中翻转该引脚状态,实现LED闪烁效果
|
||||
*/
|
||||
static void blink_entry(void *parameter)
|
||||
{
|
||||
/* Initialize PA6 */
|
||||
@ -50,16 +59,31 @@ static void blink_entry(void *parameter)
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
/* 初始化为关闭状态 */
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
|
||||
|
||||
while (1)
|
||||
{
|
||||
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
|
||||
// osal_log_i("System Running...");
|
||||
osal_thread_mdelay(1000);
|
||||
/* 检查数据上传成功标志 */
|
||||
if (data_upload_success)
|
||||
{
|
||||
/* 亮LED */
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
|
||||
osal_thread_mdelay(500); /* 亮500ms */
|
||||
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
|
||||
/* 重置标志 */
|
||||
data_upload_success = 0;
|
||||
}
|
||||
osal_thread_mdelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ethernet Input Thread */
|
||||
/**
|
||||
* @brief 以太网输入任务入口函数
|
||||
* @param parameter 任务参数(本函数中未使用)
|
||||
* @note 该函数在循环中调用ethernetif_input处理接收到的以太网数据包
|
||||
*/
|
||||
static void ethernet_input_entry(void *parameter)
|
||||
{
|
||||
while(1)
|
||||
@ -69,11 +93,22 @@ static void ethernet_input_entry(void *parameter)
|
||||
}
|
||||
}
|
||||
|
||||
/* Ping Configuration */
|
||||
/**
|
||||
* @brief Ping配置参数
|
||||
* @note 该结构体定义了Ping操作的相关参数,包括ID、数据大小、接收超时时间
|
||||
*/
|
||||
#define PING_ID 0xAFAF
|
||||
#define PING_DATA_SIZE 32
|
||||
#define PING_RCV_TIMEO 5000 // 5 seconds
|
||||
|
||||
/**
|
||||
* @brief 准备Ping回显包
|
||||
* @param iecho 指向icmp_echo_hdr结构体的指针,用于存储回显包
|
||||
* @param len 回显包的总长度(包括icmp_echo_hdr头和数据)
|
||||
* @param seq Ping包的序列号
|
||||
* @note 该函数填充icmp_echo_hdr结构体,设置类型为ICMP_ECHO,ID为PING_ID,序列号为seq,
|
||||
* 并填充数据部分为0到(data_len-1)的连续字节
|
||||
*/
|
||||
static void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len, u16_t seq)
|
||||
{
|
||||
size_t i;
|
||||
@ -92,6 +127,12 @@ static void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len, u16_t seq)
|
||||
iecho->chksum = inet_chksum(iecho, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查目标IP是否可达
|
||||
* @param target_ip 目标IP地址字符串
|
||||
* @return 如果目标IP可达,返回1;否则返回0
|
||||
* @note 该函数通过发送ICMP Echo请求包到目标IP,并等待响应来检查目标IP是否可达
|
||||
*/
|
||||
static int ping_check(const char *target_ip)
|
||||
{
|
||||
int s;
|
||||
@ -170,374 +211,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TCP Client Configuration */
|
||||
#define TCP_CLIENT_AUTH_USERNAME "admin"
|
||||
#define TCP_CLIENT_AUTH_PASSWORD "password123"
|
||||
#define TCP_CLIENT_MAX_RECONNECT_DELAY 10000 // 最大重连延迟 10 秒
|
||||
#define TCP_CLIENT_INIT_RECONNECT_DELAY 1000 // 初始重连延迟 1 秒
|
||||
#define TCP_CLIENT_HEARTBEAT_INTERVAL 500 // 心跳间隔 500ms
|
||||
#define TCP_CLIENT_AUTH_TIMEOUT 3000 // 认证超时 3 秒
|
||||
#define TCP_CLIENT_CONNECT_TIMEOUT 5000 // 连接超时 5 秒
|
||||
|
||||
/* Helper function: Check if authentication response is successful */
|
||||
static int is_auth_success(const char *response)
|
||||
{
|
||||
if (!response)
|
||||
return 0;
|
||||
|
||||
// 移除末尾的换行符和空格
|
||||
char *p = (char *)response;
|
||||
while (*p && (*p == ' ' || *p == '\n' || *p == '\r')) p++;
|
||||
char *end = p + strlen(p) - 1;
|
||||
while (end > p && (*end == ' ' || *end == '\n' || *end == '\r')) end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
// 转换为小写进行比较
|
||||
char lower_data[128];
|
||||
for (int i = 0; p[i]; i++) {
|
||||
lower_data[i] = tolower(p[i]);
|
||||
}
|
||||
lower_data[strlen(p)] = '\0';
|
||||
|
||||
osal_log_i("Processed auth response: '%s'", p);
|
||||
osal_log_i("Lowercase auth response: '%s'", lower_data);
|
||||
|
||||
/* Check if authentication was successful */
|
||||
if (strstr(lower_data, "ok") != NULL ||
|
||||
strstr(lower_data, "success") != NULL ||
|
||||
strstr(lower_data, "auth_success") != NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function: Create and configure socket */
|
||||
static int create_and_configure_socket(void)
|
||||
{
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
osal_log_e("Socket creation error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set non-blocking mode */
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
{
|
||||
osal_log_e("Failed to set non-blocking mode: %d", errno);
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set socket options for better performance */
|
||||
int keepalive = 1;
|
||||
int keepidle = 60;
|
||||
int keepintvl = 10;
|
||||
int keepcnt = 3;
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Helper function: Connect to server with timeout */
|
||||
static int connect_to_server(int sock, struct sockaddr_in *server_addr)
|
||||
{
|
||||
int ret = connect(sock, (struct sockaddr *)server_addr, sizeof(struct sockaddr));
|
||||
if (ret == -1 && errno != EINPROGRESS)
|
||||
{
|
||||
osal_log_e("Connect failed: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use select to wait for connection completion */
|
||||
fd_set wset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&wset);
|
||||
FD_SET(sock, &wset);
|
||||
tv.tv_sec = TCP_CLIENT_CONNECT_TIMEOUT / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_CONNECT_TIMEOUT % 1000) * 1000;
|
||||
|
||||
if (select(sock + 1, NULL, &wset, NULL, &tv) > 0)
|
||||
{
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
|
||||
if (error != 0)
|
||||
{
|
||||
osal_log_e("Connect failed: %d", error);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Connect timeout");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function: Send authentication and wait for response */
|
||||
static int authenticate_server(int sock)
|
||||
{
|
||||
/* Send authentication information */
|
||||
char auth_data[64];
|
||||
snprintf(auth_data, sizeof(auth_data), "AUTH %s %s\n", TCP_CLIENT_AUTH_USERNAME, TCP_CLIENT_AUTH_PASSWORD);
|
||||
|
||||
if (send(sock, auth_data, strlen(auth_data), 0) < 0)
|
||||
{
|
||||
osal_log_e("Failed to send authentication: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
osal_log_i("Sent authentication: %s", auth_data);
|
||||
|
||||
/* Wait for authentication response */
|
||||
char recv_data[128];
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(sock, &rset);
|
||||
tv.tv_sec = TCP_CLIENT_AUTH_TIMEOUT / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_AUTH_TIMEOUT % 1000) * 1000;
|
||||
|
||||
if (select(sock + 1, &rset, NULL, NULL, &tv) > 0)
|
||||
{
|
||||
int bytes_received = recv(sock, recv_data, sizeof(recv_data) - 1, 0);
|
||||
if (bytes_received > 0)
|
||||
{
|
||||
recv_data[bytes_received] = '\0';
|
||||
osal_log_i("Authentication response: '%s'", recv_data);
|
||||
|
||||
if (is_auth_success(recv_data))
|
||||
{
|
||||
osal_log_i("Authentication successful!");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Authentication failed: %s", recv_data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (bytes_received == 0)
|
||||
{
|
||||
osal_log_w("Connection closed by server during authentication");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Recv error during authentication: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_w("No authentication response received");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TCP Client Thread */
|
||||
static void tcp_client_entry(void *parameter)
|
||||
{
|
||||
int sock = -1;
|
||||
struct sockaddr_in server_addr;
|
||||
char recv_data[128];
|
||||
int bytes_received;
|
||||
int reconnect_count = 0;
|
||||
int reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY;
|
||||
|
||||
/* Wait for IP address ready */
|
||||
if (osal_sem_take(sem_ip_ready, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take IP ready semaphore");
|
||||
return;
|
||||
}
|
||||
|
||||
osal_log_i("TCP Client Starting...");
|
||||
|
||||
/* Prepare server address */
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(SERVER_PORT);
|
||||
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR);
|
||||
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Check Link Status */
|
||||
if (!netif_is_link_up(&gnetif)) {
|
||||
osal_log_w("Link down, waiting for link up...");
|
||||
osal_thread_mdelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create and configure socket */
|
||||
sock = create_and_configure_socket();
|
||||
if (sock < 0)
|
||||
{
|
||||
osal_log_e("Failed to create socket, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
osal_log_i("Connecting to server %s:%d...", SERVER_IP_ADDR, SERVER_PORT);
|
||||
|
||||
/* Connect to server */
|
||||
if (connect_to_server(sock, &server_addr) < 0)
|
||||
{
|
||||
closesocket(sock);
|
||||
osal_log_e("Connection failed, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
osal_log_i("Connected to server!");
|
||||
|
||||
/* Authenticate with server */
|
||||
if (!authenticate_server(sock))
|
||||
{
|
||||
osal_log_e("Authentication failed, reconnecting in %d ms...", reconnect_delay);
|
||||
closesocket(sock);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 认证成功,重置重连计数器和延迟
|
||||
reconnect_count = 0;
|
||||
reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY;
|
||||
|
||||
int report_interval = 5000; // 5秒上报一次温湿度数据
|
||||
osal_tick_t last_report_time = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Check Link Status */
|
||||
if (!netif_is_link_up(&gnetif)) {
|
||||
osal_log_w("Link lost during connection");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send heartbeat */
|
||||
if (send(sock, "Heartbeat", 9, 0) < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Send error: %d", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 定期读取并上报温湿度数据 */
|
||||
osal_tick_t current_time = osal_tick_get();
|
||||
if (current_time - last_report_time >= report_interval)
|
||||
{
|
||||
float temperature = 0.0f, humidity = 0.0f;
|
||||
int result = sht40_read_temperature_humidity(&temperature, &humidity);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
char sensor_data[64];
|
||||
int temp_int = (int)(temperature * 100);
|
||||
int hum_int = (int)(humidity * 100);
|
||||
|
||||
/* 处理负值温度显示 */
|
||||
int temp_integer = temp_int / 100;
|
||||
int temp_decimal = temp_int % 100;
|
||||
if (temp_decimal < 0) temp_decimal = -temp_decimal;
|
||||
|
||||
int hum_integer = hum_int / 100;
|
||||
int hum_decimal = hum_int % 100;
|
||||
if (hum_decimal < 0) hum_decimal = -hum_decimal;
|
||||
|
||||
if (temp_integer >= 0)
|
||||
{
|
||||
snprintf(sensor_data, sizeof(sensor_data), "TEMP=+%d.%02d℃,HUM=%d.%02d%%RH\n",
|
||||
temp_integer, temp_decimal, hum_integer, hum_decimal);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(sensor_data, sizeof(sensor_data), "TEMP=%d.%02d℃,HUM=%d.%02d%%RH\n",
|
||||
temp_integer, temp_decimal, hum_integer, hum_decimal);
|
||||
}
|
||||
|
||||
if (send(sock, sensor_data, strlen(sensor_data), 0) < 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK)
|
||||
{
|
||||
osal_log_e("Send sensor data failed: %d", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_i("Sent sensor data: %s", sensor_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Failed to read sensor data, result: %d", result);
|
||||
}
|
||||
last_report_time = current_time;
|
||||
}
|
||||
|
||||
/* Wait for data with timeout */
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(sock, &rset);
|
||||
tv.tv_sec = TCP_CLIENT_HEARTBEAT_INTERVAL / 1000;
|
||||
tv.tv_usec = (TCP_CLIENT_HEARTBEAT_INTERVAL % 1000) * 1000;
|
||||
|
||||
int n = select(sock + 1, &rset, NULL, NULL, &tv);
|
||||
if (n > 0) {
|
||||
bytes_received = recv(sock, recv_data, sizeof(recv_data) - 1, 0);
|
||||
if (bytes_received > 0)
|
||||
{
|
||||
recv_data[bytes_received] = '\0';
|
||||
osal_log_i("Received: %s", recv_data);
|
||||
}
|
||||
else if (bytes_received == 0)
|
||||
{
|
||||
osal_log_w("Connection closed by server");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Recv error: %d", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (n < 0) {
|
||||
osal_log_e("Select error: %d", errno);
|
||||
break;
|
||||
}
|
||||
/* n == 0 is timeout, continue loop */
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
osal_log_i("Connection closed, reconnecting in %d ms...", reconnect_delay);
|
||||
osal_thread_mdelay(reconnect_delay);
|
||||
// 指数退避重连
|
||||
reconnect_count++;
|
||||
reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Network Monitor Thread (DHCP & Fallback) */
|
||||
static void network_monitor_entry(void *parameter)
|
||||
@ -553,6 +227,8 @@ static void network_monitor_entry(void *parameter)
|
||||
if (gnetif.ip_addr.addr != 0)
|
||||
{
|
||||
osal_log_i("DHCP Success!");
|
||||
/* 触发网络连接事件 */
|
||||
event_trigger(EVENT_TYPE_NETWORK_CONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
osal_thread_mdelay(100);
|
||||
@ -574,6 +250,8 @@ static void network_monitor_entry(void *parameter)
|
||||
|
||||
netif_set_addr(&gnetif, &ipaddr, &netmask, &gw);
|
||||
netif_set_up(&gnetif);
|
||||
/* 触发网络连接事件 */
|
||||
event_trigger(EVENT_TYPE_NETWORK_CONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
|
||||
osal_log_i("IP Address: %d.%d.%d.%d", ip4_addr1(&gnetif.ip_addr), ip4_addr2(&gnetif.ip_addr), ip4_addr3(&gnetif.ip_addr), ip4_addr4(&gnetif.ip_addr));
|
||||
@ -591,6 +269,61 @@ static void network_monitor_entry(void *parameter)
|
||||
}
|
||||
}
|
||||
|
||||
/* 事件处理函数 */
|
||||
static int sensor_data_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling sensor data event");
|
||||
/* 这里可以添加传感器数据处理逻辑 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int network_connected_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling network connected event");
|
||||
state_manager_set_network_state(NETWORK_STATE_CONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int network_disconnected_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling network disconnected event");
|
||||
state_manager_set_network_state(NETWORK_STATE_DISCONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcp_client_connected_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling TCP client connected event");
|
||||
state_manager_set_tcp_state(TCP_STATE_CONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcp_client_disconnected_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling TCP client disconnected event");
|
||||
state_manager_set_tcp_state(TCP_STATE_LISTENING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timer_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling timer event");
|
||||
/* 这里可以添加定时任务逻辑 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int error_handler(event_t *event, void *user_data)
|
||||
{
|
||||
osal_log_i("Handling error event");
|
||||
error_code_t error = ERROR_UNKNOWN;
|
||||
if (event->data != NULL)
|
||||
{
|
||||
error = *(error_code_t *)event->data;
|
||||
}
|
||||
error_handler_process(error, user_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
osal_thread_t tid;
|
||||
@ -601,6 +334,62 @@ int main(void)
|
||||
rt_kprintf("Main: OSAL Log Level = %d\n", OSAL_LOG_LEVEL);
|
||||
osal_log_i("Test osal_log_i from main");
|
||||
|
||||
/* Initialize event queue */
|
||||
if (event_queue_init() != 0)
|
||||
{
|
||||
osal_log_e("Failed to initialize event queue");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize event handler */
|
||||
if (event_handler_init() != 0)
|
||||
{
|
||||
osal_log_e("Failed to initialize event handler");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize transaction management */
|
||||
if (transaction_init() != 0)
|
||||
{
|
||||
osal_log_e("Failed to initialize transaction management");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize state manager */
|
||||
if (state_manager_init() != 0)
|
||||
{
|
||||
osal_log_e("Failed to initialize state manager");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize error handler */
|
||||
if (error_handler_init() != 0)
|
||||
{
|
||||
osal_log_e("Failed to initialize error handler");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register event handlers */
|
||||
event_handler_register(EVENT_TYPE_SENSOR_DATA, sensor_data_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_NETWORK_CONNECTED, network_connected_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_NETWORK_DISCONNECTED, network_disconnected_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_TCP_CLIENT_CONNECTED, tcp_client_connected_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_TCP_CLIENT_DISCONNECTED, tcp_client_disconnected_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_TIMER, timer_handler, NULL);
|
||||
event_handler_register(EVENT_TYPE_ERROR, error_handler, NULL);
|
||||
|
||||
/* Create event dispatch thread */
|
||||
tid = osal_thread_create("event_dispatch", event_dispatch_thread, NULL, 1024, 8);
|
||||
if (tid != NULL)
|
||||
{
|
||||
osal_thread_start(tid);
|
||||
rt_kprintf("Thread 'event_dispatch' created.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Failed to create thread 'event_dispatch'\n");
|
||||
}
|
||||
|
||||
/* Initialize TCP/IP stack */
|
||||
rt_kprintf("Initializing TCP/IP stack...\n");
|
||||
tcpip_init(NULL, NULL);
|
||||
@ -649,10 +438,13 @@ int main(void)
|
||||
if (sht40_init() != 0)
|
||||
{
|
||||
osal_log_e("SHT40 sensor initialization failed");
|
||||
error_code_t error = ERROR_SENSOR;
|
||||
event_trigger(EVENT_TYPE_ERROR, EVENT_PRIORITY_HIGH, &error, sizeof(error));
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_i("SHT40 sensor initialized successfully");
|
||||
state_manager_set_sensor_state(SENSOR_STATE_READY);
|
||||
|
||||
/* Use heater once during initialization for self-calibration */
|
||||
osal_log_i("Performing SHT40 self-calibration using heater...");
|
||||
@ -663,19 +455,21 @@ int main(void)
|
||||
else
|
||||
{
|
||||
osal_log_e("SHT40 self-calibration failed");
|
||||
error_code_t error = ERROR_SENSOR;
|
||||
event_trigger(EVENT_TYPE_ERROR, EVENT_PRIORITY_HIGH, &error, sizeof(error));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create TCP Client Thread */
|
||||
tid = osal_thread_create("tcp_client", tcp_client_entry, NULL, 2048, 15);
|
||||
/* Create TCP Server Thread */
|
||||
tid = osal_thread_create("tcp_server", tcp_server_entry, NULL, 2048, 15);
|
||||
if (tid != NULL)
|
||||
{
|
||||
osal_thread_start(tid);
|
||||
rt_kprintf("Thread 'tcp_client' created.\n");
|
||||
rt_kprintf("Thread 'tcp_server' created.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Failed to create thread 'tcp_client'\n");
|
||||
rt_kprintf("Failed to create thread 'tcp_server'\n");
|
||||
}
|
||||
|
||||
/* Create Blink/Status Thread */
|
||||
|
||||
136
app/state_manager.c
Normal file
136
app/state_manager.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* state_manager.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 状态管理模块实现
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
// #include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "state_manager.h"
|
||||
|
||||
/* 系统状态 */
|
||||
static system_state_t g_system_state;
|
||||
|
||||
/**
|
||||
* @brief 初始化状态管理
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_init(void)
|
||||
{
|
||||
/* 初始化系统状态 */
|
||||
g_system_state.network_state = NETWORK_STATE_DISCONNECTED;
|
||||
g_system_state.sensor_state = SENSOR_STATE_IDLE;
|
||||
g_system_state.tcp_state = TCP_STATE_CLOSED;
|
||||
g_system_state.error_code = ERROR_NONE;
|
||||
|
||||
osal_log_i("State manager initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取系统状态
|
||||
* @param state 系统状态指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_get_system_state(system_state_t *state)
|
||||
{
|
||||
if (state == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*state = g_system_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置网络状态
|
||||
* @param state 网络状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_network_state(network_state_t state)
|
||||
{
|
||||
g_system_state.network_state = state;
|
||||
osal_log_i("Network state set to %d", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置传感器状态
|
||||
* @param state 传感器状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_sensor_state(sensor_state_t state)
|
||||
{
|
||||
g_system_state.sensor_state = state;
|
||||
osal_log_i("Sensor state set to %d", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置TCP状态
|
||||
* @param state TCP状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_tcp_state(tcp_state_t state)
|
||||
{
|
||||
g_system_state.tcp_state = state;
|
||||
osal_log_i("TCP state set to %d", state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置错误代码
|
||||
* @param error 错误代码
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_error_code(error_code_t error)
|
||||
{
|
||||
g_system_state.error_code = error;
|
||||
osal_log_i("Error code set to %d", error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建状态快照
|
||||
* @param snapshot 状态快照指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_create_snapshot(state_snapshot_t *snapshot)
|
||||
{
|
||||
if (snapshot == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 复制当前系统状态 */
|
||||
snapshot->system_state = g_system_state;
|
||||
snapshot->timestamp = rt_tick_get();
|
||||
|
||||
osal_log_i("State snapshot created");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 恢复状态快照
|
||||
* @param snapshot 状态快照指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_restore_snapshot(state_snapshot_t *snapshot)
|
||||
{
|
||||
if (snapshot == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 恢复系统状态 */
|
||||
g_system_state = snapshot->system_state;
|
||||
|
||||
osal_log_i("State snapshot restored");
|
||||
return 0;
|
||||
}
|
||||
120
app/state_manager.h
Normal file
120
app/state_manager.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* state_manager.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 状态管理模块头文件
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef STATE_MANAGER_H
|
||||
#define STATE_MANAGER_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
|
||||
/* 网络状态定义 */
|
||||
typedef enum {
|
||||
NETWORK_STATE_DISCONNECTED = 0,
|
||||
NETWORK_STATE_CONNECTING,
|
||||
NETWORK_STATE_CONNECTED,
|
||||
NETWORK_STATE_ERROR
|
||||
} network_state_t;
|
||||
|
||||
/* 传感器状态定义 */
|
||||
typedef enum {
|
||||
SENSOR_STATE_IDLE = 0,
|
||||
SENSOR_STATE_READING,
|
||||
SENSOR_STATE_READY,
|
||||
SENSOR_STATE_ERROR
|
||||
} sensor_state_t;
|
||||
|
||||
/* TCP状态定义 */
|
||||
typedef enum {
|
||||
TCP_STATE_CLOSED = 0,
|
||||
TCP_STATE_LISTENING,
|
||||
TCP_STATE_CONNECTED,
|
||||
TCP_STATE_ERROR
|
||||
} tcp_state_t;
|
||||
|
||||
/* 错误代码定义 */
|
||||
typedef enum {
|
||||
ERROR_NONE = 0,
|
||||
ERROR_NETWORK,
|
||||
ERROR_SENSOR,
|
||||
ERROR_TCP,
|
||||
ERROR_UNKNOWN
|
||||
} error_code_t;
|
||||
|
||||
/* 系统状态结构体 */
|
||||
typedef struct {
|
||||
network_state_t network_state; /* 网络状态 */
|
||||
sensor_state_t sensor_state; /* 传感器状态 */
|
||||
tcp_state_t tcp_state; /* TCP状态 */
|
||||
error_code_t error_code; /* 错误代码 */
|
||||
} system_state_t;
|
||||
|
||||
/* 状态快照结构体 */
|
||||
typedef struct {
|
||||
system_state_t system_state; /* 系统状态 */
|
||||
rt_tick_t timestamp; /* 时间戳 */
|
||||
} state_snapshot_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化状态管理
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_init(void);
|
||||
|
||||
/**
|
||||
* @brief 获取系统状态
|
||||
* @param state 系统状态指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_get_system_state(system_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief 设置网络状态
|
||||
* @param state 网络状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_network_state(network_state_t state);
|
||||
|
||||
/**
|
||||
* @brief 设置传感器状态
|
||||
* @param state 传感器状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_sensor_state(sensor_state_t state);
|
||||
|
||||
/**
|
||||
* @brief 设置TCP状态
|
||||
* @param state TCP状态
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_tcp_state(tcp_state_t state);
|
||||
|
||||
/**
|
||||
* @brief 设置错误代码
|
||||
* @param error 错误代码
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_set_error_code(error_code_t error);
|
||||
|
||||
/**
|
||||
* @brief 创建状态快照
|
||||
* @param snapshot 状态快照指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_create_snapshot(state_snapshot_t *snapshot);
|
||||
|
||||
/**
|
||||
* @brief 恢复状态快照
|
||||
* @param snapshot 状态快照指针
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int state_manager_restore_snapshot(state_snapshot_t *snapshot);
|
||||
|
||||
#endif /* STATE_MANAGER_H */
|
||||
350
app/tcp_server.c
Normal file
350
app/tcp_server.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* tcp_server.c
|
||||
*
|
||||
* Created on: 2026-03-03
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: TCP服务器模块实现
|
||||
* 依赖: lwIP网络栈、SHT40传感器、osal、事件驱动模块
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准lwIP API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "tcp_server.h"
|
||||
#include "sht40.h"
|
||||
#include "event_trigger.h"
|
||||
#include "state_manager.h"
|
||||
#include "transaction.h"
|
||||
|
||||
/* 外部变量声明 */
|
||||
extern struct netif gnetif;
|
||||
extern osal_sem_t sem_ip_ready;
|
||||
|
||||
/* 全局标志 */
|
||||
volatile int data_upload_success = 0;
|
||||
|
||||
/* 客户端连接数组 */
|
||||
static client_conn_t clients[TCP_SERVER_MAX_CLIENTS];
|
||||
|
||||
/* 辅助函数: 初始化客户端连接 */
|
||||
static void init_client_connections(void)
|
||||
{
|
||||
for (int i = 0; i < TCP_SERVER_MAX_CLIENTS; i++) {
|
||||
clients[i].sock = -1;
|
||||
clients[i].connected = 0;
|
||||
memset(&clients[i].addr, 0, sizeof(clients[i].addr));
|
||||
}
|
||||
}
|
||||
|
||||
/* 辅助函数: 查找空闲客户端槽位 */
|
||||
static int find_free_client_slot(void)
|
||||
{
|
||||
for (int i = 0; i < TCP_SERVER_MAX_CLIENTS; i++) {
|
||||
if (!clients[i].connected) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 辅助函数: 接受新客户端连接 */
|
||||
static void accept_new_connection(int server_sock)
|
||||
{
|
||||
int client_sock;
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t client_addr_len = sizeof(client_addr);
|
||||
|
||||
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len);
|
||||
if (client_sock < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Accept error: %d", errno);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 设置客户端socket为非阻塞模式 */
|
||||
int flags = fcntl(client_sock, F_GETFL, 0);
|
||||
if (fcntl(client_sock, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
osal_log_e("Failed to set non-blocking mode for client: %d", errno);
|
||||
closesocket(client_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 查找空闲客户端槽位 */
|
||||
int slot = find_free_client_slot();
|
||||
if (slot < 0) {
|
||||
osal_log_w("No free client slots available");
|
||||
closesocket(client_sock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 将客户端添加到连接数组 */
|
||||
clients[slot].sock = client_sock;
|
||||
clients[slot].addr = client_addr;
|
||||
clients[slot].connected = 1;
|
||||
|
||||
osal_log_i("Client connected from %s:%d",
|
||||
inet_ntoa(client_addr.sin_addr),
|
||||
ntohs(client_addr.sin_port));
|
||||
|
||||
/* 触发客户端连接事件 */
|
||||
event_trigger(EVENT_TYPE_TCP_CLIENT_CONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
|
||||
/* 辅助函数: 向所有连接的客户端发送数据 */
|
||||
static void send_data_to_all_clients(const char *data, int len)
|
||||
{
|
||||
for (int i = 0; i < TCP_SERVER_MAX_CLIENTS; i++) {
|
||||
if (clients[i].connected) {
|
||||
if (send(clients[i].sock, data, len, 0) < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Send error to client %d: %d", i, errno);
|
||||
closesocket(clients[i].sock);
|
||||
clients[i].sock = -1;
|
||||
clients[i].connected = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 辅助函数: 检查客户端连接 */
|
||||
static void check_client_connections(void)
|
||||
{
|
||||
char recv_buf[128];
|
||||
|
||||
for (int i = 0; i < TCP_SERVER_MAX_CLIENTS; i++) {
|
||||
if (clients[i].connected) {
|
||||
/* 检查 incoming data */
|
||||
fd_set rset;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(clients[i].sock, &rset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000; // 10ms timeout
|
||||
|
||||
int n = select(clients[i].sock + 1, &rset, NULL, NULL, &tv);
|
||||
if (n > 0) {
|
||||
int bytes_received = recv(clients[i].sock, recv_buf, sizeof(recv_buf) - 1, 0);
|
||||
if (bytes_received > 0) {
|
||||
recv_buf[bytes_received] = '\0';
|
||||
osal_log_i("Received from client %d: %s", i, recv_buf);
|
||||
} else if (bytes_received == 0) {
|
||||
osal_log_w("Client %d disconnected", i);
|
||||
closesocket(clients[i].sock);
|
||||
clients[i].sock = -1;
|
||||
clients[i].connected = 0;
|
||||
/* 触发客户端断开连接事件 */
|
||||
event_trigger(EVENT_TYPE_TCP_CLIENT_DISCONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
} else {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
osal_log_e("Recv error from client %d: %d", i, errno);
|
||||
closesocket(clients[i].sock);
|
||||
clients[i].sock = -1;
|
||||
clients[i].connected = 0;
|
||||
/* 触发客户端断开连接事件 */
|
||||
event_trigger(EVENT_TYPE_TCP_CLIENT_DISCONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
}
|
||||
} else if (n < 0) {
|
||||
osal_log_e("Select error for client %d: %d", i, errno);
|
||||
closesocket(clients[i].sock);
|
||||
clients[i].sock = -1;
|
||||
clients[i].connected = 0;
|
||||
/* 触发客户端断开连接事件 */
|
||||
event_trigger(EVENT_TYPE_TCP_CLIENT_DISCONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 辅助函数: 检查是否有客户端连接 */
|
||||
static int has_client_connections(void)
|
||||
{
|
||||
for (int i = 0; i < TCP_SERVER_MAX_CLIENTS; i++) {
|
||||
if (clients[i].connected) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 辅助函数: 创建和配置socket */
|
||||
static int create_and_configure_socket(void)
|
||||
{
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
osal_log_e("Socket creation error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 设置非阻塞模式 */
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
{
|
||||
osal_log_e("Failed to set non-blocking mode: %d", errno);
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 设置socket选项以提高性能 */
|
||||
int keepalive = 1;
|
||||
int keepidle = 60;
|
||||
int keepintvl = 10;
|
||||
int keepcnt = 3;
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* TCP服务器线程 */
|
||||
void tcp_server_entry(void *parameter)
|
||||
{
|
||||
int server_sock = -1;
|
||||
struct sockaddr_in server_addr;
|
||||
|
||||
/* 等待IP地址就绪 */
|
||||
if (osal_sem_take(sem_ip_ready, OSAL_WAIT_FOREVER) != OSAL_OK)
|
||||
{
|
||||
osal_log_e("Failed to take IP ready semaphore");
|
||||
return;
|
||||
}
|
||||
|
||||
osal_log_i("TCP Server Starting...");
|
||||
|
||||
/* 初始化客户端连接 */
|
||||
init_client_connections();
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* 检查链路状态 */
|
||||
if (!netif_is_link_up(&gnetif)) {
|
||||
osal_log_w("Link down, waiting for link up...");
|
||||
osal_thread_mdelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 创建和配置服务器socket */
|
||||
if (server_sock < 0) {
|
||||
server_sock = create_and_configure_socket();
|
||||
if (server_sock < 0) {
|
||||
osal_log_e("Failed to create server socket, retrying...");
|
||||
osal_thread_mdelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 准备服务器地址 */
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(TCP_SERVER_PORT);
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
|
||||
|
||||
/* 绑定socket */
|
||||
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) {
|
||||
osal_log_e("Bind error: %d", errno);
|
||||
closesocket(server_sock);
|
||||
server_sock = -1;
|
||||
osal_thread_mdelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 开始监听 */
|
||||
if (listen(server_sock, TCP_SERVER_MAX_CLIENTS) < 0) {
|
||||
osal_log_e("Listen error: %d", errno);
|
||||
closesocket(server_sock);
|
||||
server_sock = -1;
|
||||
osal_thread_mdelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
osal_log_i("TCP Server listening on port %d", TCP_SERVER_PORT);
|
||||
}
|
||||
|
||||
/* 接受新连接 */
|
||||
accept_new_connection(server_sock);
|
||||
|
||||
/* 检查客户端连接 */
|
||||
check_client_connections();
|
||||
|
||||
/* 定期读取并发送温湿度数据 */
|
||||
static osal_tick_t last_report_time = 0;
|
||||
int report_interval = 5000; // 5秒上报一次温湿度数据
|
||||
osal_tick_t current_time = osal_tick_get();
|
||||
|
||||
if ((unsigned int)(current_time - last_report_time) >= (unsigned int)report_interval)
|
||||
{
|
||||
/* 检查是否有客户端连接 */
|
||||
if (has_client_connections())
|
||||
{
|
||||
/* 开始事务 */
|
||||
int tx_id = transaction_begin(NULL, NULL);
|
||||
if (tx_id > 0)
|
||||
{
|
||||
float temperature = 0.0f, humidity = 0.0f;
|
||||
int result = sht40_read_temperature_humidity(&temperature, &humidity);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
char sensor_data[64];
|
||||
int temp_int = (int)(temperature * 100);
|
||||
int hum_int = (int)(humidity * 100);
|
||||
|
||||
/* 处理负值温度显示 */
|
||||
int temp_integer = temp_int / 100;
|
||||
int temp_decimal = temp_int % 100;
|
||||
if (temp_decimal < 0) temp_decimal = -temp_decimal;
|
||||
|
||||
int hum_integer = hum_int / 100;
|
||||
int hum_decimal = hum_int % 100;
|
||||
if (hum_decimal < 0) hum_decimal = -hum_decimal;
|
||||
|
||||
if (temp_integer >= 0)
|
||||
{
|
||||
snprintf(sensor_data, sizeof(sensor_data), "TEMP=+%d.%02d℃,HUM=%d.%02d%%RH\n",
|
||||
temp_integer, temp_decimal, hum_integer, hum_decimal);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(sensor_data, sizeof(sensor_data), "TEMP=%d.%02d℃,HUM=%d.%02d%%RH\n",
|
||||
temp_integer, temp_decimal, hum_integer, hum_decimal);
|
||||
}
|
||||
|
||||
/* 发送给所有连接的客户端 */
|
||||
send_data_to_all_clients(sensor_data, strlen(sensor_data));
|
||||
osal_log_i("Sent sensor data: %s", sensor_data);
|
||||
/* 设置数据上传成功标志 */
|
||||
data_upload_success = 1;
|
||||
|
||||
/* 提交事务 */
|
||||
transaction_commit(tx_id);
|
||||
|
||||
/* 触发传感器数据事件 */
|
||||
event_trigger(EVENT_TYPE_SENSOR_DATA, EVENT_PRIORITY_NORMAL, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_log_e("Failed to read sensor data, result: %d", result);
|
||||
/* 回滚事务 */
|
||||
transaction_rollback(tx_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_report_time = current_time;
|
||||
}
|
||||
|
||||
/* 向所有客户端发送心跳 */
|
||||
send_data_to_all_clients("Heartbeat\n", 9);
|
||||
|
||||
osal_thread_mdelay(TCP_SERVER_HEARTBEAT_INTERVAL);
|
||||
}
|
||||
}
|
||||
36
app/tcp_server.h
Normal file
36
app/tcp_server.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* tcp_server.h
|
||||
*
|
||||
* Created on: 2026-03-03
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: TCP服务器模块
|
||||
* 依赖: lwIP网络栈、SHT40传感器
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准lwIP API
|
||||
*/
|
||||
|
||||
#ifndef TCP_SERVER_H
|
||||
#define TCP_SERVER_H
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
/* TCP Server Configuration */
|
||||
#define TCP_SERVER_PORT 5588
|
||||
#define TCP_SERVER_MAX_CLIENTS 2
|
||||
#define TCP_SERVER_HEARTBEAT_INTERVAL 500 // 心跳间隔 500ms
|
||||
#define TCP_SERVER_RECEIVE_TIMEOUT 5000 // 接收超时 5 秒
|
||||
|
||||
/* 客户端连接结构 */
|
||||
typedef struct {
|
||||
int sock; /* 客户端socket */
|
||||
struct sockaddr_in addr; /* 客户端地址 */
|
||||
int connected; /* 连接状态 */
|
||||
} client_conn_t;
|
||||
|
||||
/* 全局标志 */
|
||||
extern volatile int data_upload_success;
|
||||
|
||||
/* 函数声明 */
|
||||
void tcp_server_entry(void *parameter);
|
||||
|
||||
#endif /* TCP_SERVER_H */
|
||||
147
app/transaction.c
Normal file
147
app/transaction.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* transaction.c
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事务管理模块实现
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
#include "transaction.h"
|
||||
|
||||
/* 事务数组 */
|
||||
static transaction_t g_transactions[MAX_TRANSACTIONS];
|
||||
|
||||
/**
|
||||
* @brief 初始化事务管理
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_init(void)
|
||||
{
|
||||
/* 初始化事务数组 */
|
||||
for (int i = 0; i < MAX_TRANSACTIONS; i++)
|
||||
{
|
||||
g_transactions[i].id = 0;
|
||||
g_transactions[i].status = TRANSACTION_STATUS_IDLE;
|
||||
g_transactions[i].rollback_func = NULL;
|
||||
g_transactions[i].user_data = NULL;
|
||||
}
|
||||
|
||||
osal_log_i("Transaction management initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开始事务
|
||||
* @param rollback_func 回滚函数
|
||||
* @param user_data 用户数据
|
||||
* @return 事务ID,失败返回0
|
||||
*/
|
||||
int transaction_begin(transaction_rollback_func_t rollback_func, void *user_data)
|
||||
{
|
||||
/* 查找空闲事务 */
|
||||
int id = 0;
|
||||
for (int i = 0; i < MAX_TRANSACTIONS; i++)
|
||||
{
|
||||
if (g_transactions[i].status == TRANSACTION_STATUS_IDLE)
|
||||
{
|
||||
id = i + 1; /* 事务ID从1开始 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
osal_log_e("No free transaction available");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 初始化事务 */
|
||||
g_transactions[id - 1].id = id;
|
||||
g_transactions[id - 1].status = TRANSACTION_STATUS_ACTIVE;
|
||||
g_transactions[id - 1].rollback_func = rollback_func;
|
||||
g_transactions[id - 1].user_data = user_data;
|
||||
|
||||
osal_log_i("Transaction %d started", id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 提交事务
|
||||
* @param id 事务ID
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_commit(int id)
|
||||
{
|
||||
if (id < 1 || id > MAX_TRANSACTIONS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
transaction_t *tx = &g_transactions[id - 1];
|
||||
if (tx->status != TRANSACTION_STATUS_ACTIVE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 提交事务 */
|
||||
tx->status = TRANSACTION_STATUS_IDLE;
|
||||
tx->rollback_func = NULL;
|
||||
tx->user_data = NULL;
|
||||
|
||||
osal_log_i("Transaction %d committed", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 回滚事务
|
||||
* @param id 事务ID
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_rollback(int id)
|
||||
{
|
||||
if (id < 1 || id > MAX_TRANSACTIONS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
transaction_t *tx = &g_transactions[id - 1];
|
||||
if (tx->status != TRANSACTION_STATUS_ACTIVE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 执行回滚函数 */
|
||||
if (tx->rollback_func != NULL)
|
||||
{
|
||||
osal_log_i("Rolling back transaction %d", id);
|
||||
tx->rollback_func(tx->user_data);
|
||||
}
|
||||
|
||||
/* 重置事务状态 */
|
||||
tx->status = TRANSACTION_STATUS_IDLE;
|
||||
tx->rollback_func = NULL;
|
||||
tx->user_data = NULL;
|
||||
|
||||
osal_log_i("Transaction %d rolled back", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取事务状态
|
||||
* @param id 事务ID
|
||||
* @return 事务状态
|
||||
*/
|
||||
transaction_status_t transaction_get_status(int id)
|
||||
{
|
||||
if (id < 1 || id > MAX_TRANSACTIONS)
|
||||
{
|
||||
return TRANSACTION_STATUS_INVALID;
|
||||
}
|
||||
|
||||
return g_transactions[id - 1].status;
|
||||
}
|
||||
76
app/transaction.h
Normal file
76
app/transaction.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* transaction.h
|
||||
*
|
||||
* Created on: 2026-03-04
|
||||
* Author: RT-Thread
|
||||
*
|
||||
* 功能: 事务管理模块头文件
|
||||
* 依赖: RT-Thread Nano, osal
|
||||
* 跨平台适配: 基于RT-Thread Nano,使用标准API
|
||||
*/
|
||||
|
||||
#ifndef TRANSACTION_H
|
||||
#define TRANSACTION_H
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "osal.h"
|
||||
|
||||
/* 事务状态定义 */
|
||||
typedef enum {
|
||||
TRANSACTION_STATUS_IDLE = 0,
|
||||
TRANSACTION_STATUS_ACTIVE,
|
||||
TRANSACTION_STATUS_COMMITTED,
|
||||
TRANSACTION_STATUS_ROLLED_BACK,
|
||||
TRANSACTION_STATUS_INVALID
|
||||
} transaction_status_t;
|
||||
|
||||
/* 回滚函数类型 */
|
||||
typedef void (*transaction_rollback_func_t)(void *user_data);
|
||||
|
||||
/* 事务结构体 */
|
||||
typedef struct {
|
||||
int id; /* 事务ID */
|
||||
transaction_status_t status; /* 事务状态 */
|
||||
transaction_rollback_func_t rollback_func; /* 回滚函数 */
|
||||
void *user_data; /* 用户数据 */
|
||||
} transaction_t;
|
||||
|
||||
/* 最大事务数量 */
|
||||
#define MAX_TRANSACTIONS 16
|
||||
|
||||
/**
|
||||
* @brief 初始化事务管理
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_init(void);
|
||||
|
||||
/**
|
||||
* @brief 开始事务
|
||||
* @param rollback_func 回滚函数
|
||||
* @param user_data 用户数据
|
||||
* @return 事务ID,失败返回0
|
||||
*/
|
||||
int transaction_begin(transaction_rollback_func_t rollback_func, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief 提交事务
|
||||
* @param id 事务ID
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_commit(int id);
|
||||
|
||||
/**
|
||||
* @brief 回滚事务
|
||||
* @param id 事务ID
|
||||
* @return 0 成功,非0 失败
|
||||
*/
|
||||
int transaction_rollback(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取事务状态
|
||||
* @param id 事务ID
|
||||
* @return 事务状态
|
||||
*/
|
||||
transaction_status_t transaction_get_status(int id);
|
||||
|
||||
#endif /* TRANSACTION_H */
|
||||
Reference in New Issue
Block a user