串口1,485功能。

数据接收解析及数据库处理
This commit is contained in:
sc committed 2025-11-29 02:03:29 +08:00
1 parent e36baf375d
commit 0735772f8a
19 files changed
+2066 -228

No files matched your search

+55 -121
View File
@@ -11,151 +11,85 @@
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <drivers/serial.h> // ← 显式包含,确保 RT_SERIAL_EVENT_RX_IDLE 可见
#include "data_comm.h"
#include <rs485.h>
#define DBG_TAG "SCCM_link"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define SAMPLE_UART_NAME "uart1"
#define RX_LINE_BUF_SIZE 1024
static rt_device_t serial;
static struct rt_semaphore rx_sem;
// 接收回调
static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
{
// 注意:在 RT-Thread 5.x,当使用 INT_RX 时,size 是接收到的字节数
// 但若启用了 RX_IDLE 模式,底层驱动会在 IDLE 时回调,并传入事件
// 安全做法:检查是否为事件(高位标志)
// if (size & RT_SERIAL_EVENT_RX_IDLE)
{
LOG_D("RX IDLE event received");
rt_sem_release(&rx_sem);
return RT_EOK;
}
// 如果是普通数据(size > 0),也可处理,但本例依赖 IDLE 触发
return RT_EOK;
}
static int read_line_from_uart(char *buf, int maxlen)
{
char ch;
int len = 0;
while (len < maxlen - 1)
{
// 注意:在 INT_RX 模式下,rt_device_read 会从驱动内部 buffer 读取
rt_size_t result = rt_device_read(serial, 0, &ch, 1);
if (result <= 0)
{
break; // 无更多数据
}
buf[len++] = ch;
if (ch == '\n')
{
buf[len] = '\0';
return len;
}
}
buf[len] = '\0';
return len;
}
#define RX_LINE_BUF_SIZE 1024
#define RS485_SAMPLE_SLAVE_SERIAL "uart1"
#define RS485_SAMPLE_SLAVE_BAUDRATE 115200
#define RS485_SAMPLE_MASTER_PARITY 0 //0 -- none parity
#define RS485_SAMPLE_SLAVE_PIN -1 //-1 -- nonuse rs485 mode control
#define RS485_SAMPLE_SLAVE_LVL 1
#define RS485_TOM_MS 50
void uart_thread_entry(void *parameter)
{
char input[RX_LINE_BUF_SIZE];
int len;
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
serial = rt_device_find(SAMPLE_UART_NAME);
if (!serial)
{
LOG_E("Cannot find %s", SAMPLE_UART_NAME);
return;
}
static rt_uint8_t input[RX_LINE_BUF_SIZE];
rs485_inst_t *hinst = rs485_create(RS485_SAMPLE_SLAVE_SERIAL, RS485_SAMPLE_SLAVE_BAUDRATE,
RS485_SAMPLE_MASTER_PARITY, RS485_SAMPLE_SLAVE_PIN, RS485_SAMPLE_SLAVE_LVL);
// Step 1: 设置串口基本参数(波特率等)
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = BAUD_RATE_115200; // 根据需要调整
config.data_bits = DATA_BITS_8;
config.stop_bits = STOP_BITS_1;
config.parity = PARITY_NONE;
config.bufsz = RX_LINE_BUF_SIZE; // 驱动内部接收 buffer 大小
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);
if (hinst == RT_NULL)
{
LOG_E("create LINK instance fail.");
return;
}
// Step 2: 【关键】启用 RX IDLE 模式
// rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, (void*)RT_SERIAL_RX_IDLE);
rs485_set_recv_tmo(hinst, RS485_TOM_MS);
if (rs485_connect(hinst) != RT_EOK)
{
rs485_destory(hinst);
LOG_E("LINK connect fail.");
return;
}
// Step 3: 打开串口(使用中断接收)
rt_err_t result = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);
if (result != RT_EOK)
{
LOG_E("Failed to open %s, error=%d", SAMPLE_UART_NAME, result);
return;
}
// Step 4: 设置回调
rt_device_set_rx_indicate(serial, uart_rx_ind);
LOG_I("SCCM thread (IDLE mode) running on %s", SAMPLE_UART_NAME);
LOG_I("SCCM thread running on %s", RS485_SAMPLE_SLAVE_SERIAL);
while (1)
{
// 等待数据就绪
if (rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK)
{
// 处理接收到的数据(提取完整行)
while ((len = get_line(input, sizeof(input))) > 0)
{
// 动态分配请求结构体(见之前完整代码)
struct proc_request *req = rt_malloc(sizeof(struct proc_request));
if (!req) continue;
{
int len = rs485_recv(hinst, input, sizeof(input));
rt_strncpy(req->input, input, sizeof(req->input));
req->input_len = len;
//req->input[len]='\0';
if (len > 0)
{
// 动态分配请求结构体(见之前完整代码)
struct proc_request *req = rt_malloc(sizeof(struct proc_request));
if (!req) continue;
rt_strncpy(req->input, (const char *)input, sizeof(req->input));
req->input_len = len;
req->sem = rt_malloc(sizeof(struct rt_semaphore));
if (!req->sem) {
rt_free(req);
continue;
}
rt_sem_init(req->sem, "uart_resp", 0, RT_IPC_FLAG_FIFO);
req->sem = rt_malloc(sizeof(struct rt_semaphore));
if (!req->sem) {
rt_free(req);
continue;
}
rt_sem_init(req->sem, "uart_resp", 0, RT_IPC_FLAG_FIFO);
// 发送到处理线程
if (rt_mq_send(proc_mq, &req, sizeof(req)) == RT_EOK)
{
// 等待处理完成
if (rt_sem_take(req->sem, RT_WAITING_FOREVER) == RT_EOK)
{
rt_device_write(serial, 0, req->output, req->output_len);
}
}
// 清理
rt_sem_detach(req->sem); // 或 rt_sem_delete
rt_free(req->sem);
rt_free(req);
}
}
}
// 发送到处理线程
if (rt_mq_send(proc_mq, &req, sizeof(req)) == RT_EOK)
{
// 等待处理完成
if (rt_sem_take(req->sem, rt_tick_from_millisecond(100)) >= RT_EOK)
{
rs485_send(hinst, req->output, req->output_len);
}
}
// 清理
rt_sem_detach(req->sem); // 或 rt_sem_delete
rt_free(req->sem);
rt_free(req);
}
}
}
int start_uart_thread(void)
{
rt_thread_t tid = rt_thread_create("data_uart",
uart_thread_entry,
RT_NULL,
2048,
25,
10);
rt_thread_t tid = rt_thread_create("uart1",uart_thread_entry,RT_NULL,2048,20,10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
+9 -9
View File
@@ -9,6 +9,7 @@
*/
/* DATA_comm.c */
#include <rtthread.h>
#include <rtdevice.h>
#include "cjson.h"
#include <stdio.h>
#include <string.h>
@@ -24,11 +25,10 @@
#include <rtdbg.h>
rt_mq_t proc_mq;
//static struct proc_request *req;
char cjson_falg=0;//是否解析cjson
char *json_buffer=NULL;
//
char *json_buffer=NULL;//
/**
* 截取两个指定子串之间的内容
@@ -432,17 +432,18 @@ void proc_thread_entry(void *parameter)
while (1)
{
// 接收请求指针
if (rt_mq_recv(proc_mq, &req, sizeof(req), RT_WAITING_FOREVER) == RT_EOK)
if (rt_mq_recv(proc_mq, &req, sizeof(req), RT_WAITING_FOREVER) >= RT_EOK)
{
if (!req) continue;
memcpy(DATA_api,req->input,5);
extract_between(req->input, "[", "]", DATA_machins, sizeof(DATA_machins));
if(strcmp(DATA_machins,machine_ID)==0)
{
char *p=strstr(req->input,"]");
if(!p){cjson_falg=0;}
else {
if(!p)
{
cjson_falg=0;
}else {
p += strlen("]");
}
@@ -481,8 +482,7 @@ int data_comm_init(void)
}
dat_comm_stack = rt_memheap_alloc(&sram_DTCMRAM, 1024*6);
dat_err = rt_thread_init(&dat_comm_thread, "dat_comm", proc_thread_entry, RT_NULL,
dat_comm_stack, 1024*6, 15, 10);
dat_err = rt_thread_init(&dat_comm_thread, "dat_comm", proc_thread_entry, RT_NULL,dat_comm_stack, 1024*6, 15, 10);
if(dat_err != RT_EOK)
{
+1 -12
View File
@@ -12,7 +12,6 @@
#include <dfs_posix.h>
#include <light/RUN_LED.h>
#include "DB_SQLite.h"
#include "DATA_comm.h"
#include "DATA_uart.h"
#define DBG_TAG "main"
@@ -23,19 +22,9 @@ extern rt_sem_t mount_sem; // 引用上面SD挂载线程定义的信号量
int main(void)
{
/*volatile uint32_t *sdram_test = (uint32_t*)0xC0000000;
*sdram_test = 0xAABBCCDD;
rt_thread_mdelay(1); // 等待稳定
if (*sdram_test != 0xAABBCCDD)
{
rt_kprintf("SDRAM init failed!\n");
while (1); // 卡死,不要继续
}
rt_kprintf("SDRAM test OK\n");*/
rt_sem_take(mount_sem, rt_tick_from_millisecond(5000)); // 等待挂载完成,最多等待 5 秒
thread_DB_SQLite();
//start_uart_thread();
start_uart_thread();
thread_RUN_LED();//运行指示灯线程
return RT_EOK;
}
+57 -80
View File
@@ -282,10 +282,10 @@ static void db_sqlite(void *parameter) {
// 默认启用数据库
db_enabled = RT_TRUE;
while (1) {
rt_thread_mdelay(500);
while (1)
{
// 接收命令
if (rt_mq_recv(db_mq, &cmd, sizeof(struct db_command), RT_WAITING_FOREVER) != RT_EOK)
if (rt_mq_recv(db_mq, &cmd, sizeof(struct db_command), RT_WAITING_FOREVER) <= RT_EOK)
continue;
//检查排队超时
@@ -310,30 +310,32 @@ static void db_sqlite(void *parameter) {
if (cmd.type == DB_CMD_EXIT) break;
continue;
}
//打开数据库(如果未打开)
rt_mutex_take(state_mutex, RT_WAITING_FOREVER);
if (!g_db && current_enabled)
{
if (!g_db && current_enabled) {
int rc = sqlite3_open(DB_NAME, &g_db);
if (rc != SQLITE_OK) {
rt_kprintf("Failed to open DB at %s: %s\n", DB_NAME, sqlite3_errmsg(g_db));
sqlite3_close(g_db);
g_db = RT_NULL;
rt_mutex_release(state_mutex);
return_disabled(&cmd);
continue;
} else {
rt_kprintf("Opened database: %s\n", DB_NAME);
}
int rc = sqlite3_open(DB_NAME, &g_db);
if (rc != SQLITE_OK)
{
rt_kprintf("Failed to open DB at %s: %s\n", DB_NAME, sqlite3_errmsg(g_db));
sqlite3_close(g_db);
g_db = RT_NULL;
rt_mutex_release(state_mutex);
return_disabled(&cmd);
continue;
} else {
rt_kprintf("Opened database: %s\n", DB_NAME);
}
}
rt_mutex_release(state_mutex);
//执行命令
handle_db_command(&cmd);
//返回结果
if (cmd.reply_sem) {
if (cmd.reply_sem != RT_NULL) {
rt_sem_release(cmd.reply_sem);
}
@@ -372,80 +374,55 @@ static void db_sqlite(void *parameter) {
*/
rt_err_t db_send_command(enum db_cmd_type type, const char* sql, rt_int32_t timeout_ms)
{
struct db_command cmd;
rt_sem_t sem = RT_NULL;
rt_err_t result = RT_EOK;
if (!sql || !db_mq) {
return -RT_EINVAL;
}
// 1. 创建临时信号量用于同步
sem = rt_sem_create("db_rep", 0, RT_IPC_FLAG_FIFO);
if (sem == RT_NULL)
{
rt_kprintf("Failed to create reply semaphore!\n");
return -RT_ENOMEM;
}
struct db_command cmd;
rt_sem_t sem = rt_sem_create("db_rep", 0, RT_IPC_FLAG_FIFO);
if (sem == RT_NULL) {
return -RT_ENOMEM;
}
// 2. 构造命令
rt_memset(&cmd, 0, sizeof(cmd));
cmd.type = type;
rt_strncpy(cmd.sql, sql, MAX_SQL_LEN - 1);
cmd.reply_sem = sem;
cmd.send_tick = rt_tick_get();
// 初始化命令结构体
rt_memset(&cmd, 0, sizeof(cmd));
cmd.type = type;
rt_strncpy(cmd.sql, sql, MAX_SQL_LEN - 1);
cmd.reply_sem = sem;
cmd.send_tick = rt_tick_get();
// 3. 发送命令到消息队列
if (rt_mq_send(db_mq, &cmd, sizeof(cmd)) != RT_EOK)
{
rt_kprintf("Failed to send command to db_mq!\n");
rt_sem_delete(sem);
return -RT_ERROR;
}
// 发送命令到数据库线程队列
if (rt_mq_send(db_mq, &cmd, sizeof(cmd)) != RT_EOK) {
rt_sem_delete(sem);
return -RT_ERROR;
}
// 4. 等待数据库线程处理完成(超时保护)
if (timeout_ms > 0)
{
rt_int32_t tick = rt_tick_from_millisecond(timeout_ms);
result = rt_sem_take(sem, tick);
}
else
{
result = rt_sem_take(sem, RT_WAITING_FOREVER); // 永久等待(慎用)
}
// 计算等待 tick(兼容 RT_WAITING_FOREVER)
rt_int32_t wait_ticks;
if (timeout_ms == RT_WAITING_FOREVER) {
wait_ticks = RT_WAITING_FOREVER;
} else if (timeout_ms <= 0) {
wait_ticks = 0; // 立即超时
} else {
wait_ticks = rt_tick_from_millisecond(timeout_ms);
}
// 5. 检查结果
if (result == RT_EOK)
{
rt_kprintf("SQL executed: code=%d\n", cmd.result_code);
if (type == DB_CMD_SELECT || strlen(cmd.result) > 0)
{
rt_kprintf("Result: %s\n", cmd.result);
}
}
else if (result == -RT_ETIMEOUT)
{
rt_kprintf("Database response timeout!\n");
}
else
{
rt_kprintf("Wait failed: %d\n", result);
}
// 6. 删除信号量
rt_sem_delete(sem);
return result;
// 等待数据库线程处理完成
rt_err_t result = rt_sem_take(sem, wait_ticks);
//rt_sem_delete(sem);
return result;
}
/* 线程 */
void thread_DB_SQLite(void)
{
rt_thread_t tid;
tid = rt_thread_create("db_sql", db_sqlite, RT_NULL, 1024 *32, 20, 10);
tid = rt_thread_create("db_sql", db_sqlite, RT_NULL, 1024 *48, 20, 10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_D("Failed to create SQLite thread!\n");
}
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}else{
LOG_D("Failed to create SQLite thread!\n");
}
}
+3 -1
View File
@@ -6,9 +6,10 @@
* Change Logs:
* Date Author Notes
* 2025-10-20 Administrator the first version
* 2025-11-29 Qwen Add auto_delete_sem to fix semaphore UAF
*/
#ifndef APPLICATIONS_DB_DB_SQLITE_H_
#define APPLICATIONS_DB_SQLITE_SYS_H_
#define APPLICATIONS_DB_DB_SQLITE_H_ // ← 注意:修正宏名,与文件路径一致(原为 _SYS_H_)
#include <rtthread.h>
@@ -69,6 +70,7 @@ struct db_command
char result[MAX_RESULT_LEN]; /**< 结果或错误信息 */
rt_sem_t reply_sem; /**< 回应信号量(由调用方创建,用于同步) */
rt_tick_t send_tick; /**< 发送时刻的系统 tick,用于超时检测 */
rt_bool_t auto_delete_sem; /**< 是否由数据库线程自动删除 reply_sem */
};
/* ========================