数据库操作(810,811)指令,数据库读写实现

This commit is contained in:
sc committed 2025-10-26 01:34:18 +08:00
1 parent 1096dbb42f
commit 64d820b24c
8 files changed
+640 -350

No files matched your search

+372 -243
View File
@@ -16,274 +16,403 @@
#include <dbhelper.h>
#define DB_NAME "/SC828.db"
int db_HelperInit;
rt_mq_t db_mq = RT_NULL; //
sqlite3 **db;
// 消息队列对象与缓冲区(静态分配)
//static struct rt_mq db_mq;
//static char mq_pool[DB_QUEUE_SIZE * sizeof(struct db_command)];
// 全局数据库连接与状态
static sqlite3 *g_db = RT_NULL;
static rt_bool_t db_enabled = RT_FALSE; // 是否允许数据库操作
static rt_mutex_t state_mutex = RT_NULL; // 状态访问锁
// 函数前向声明
static void return_timeout(struct db_command *cmd);
static void return_disabled(struct db_command *cmd);
static void handle_db_command(struct db_command *cmd);
static int callback(void *result_str, int argc, char **argv, char **azColName);
static const char *sql_upgrade_workorder_steps =
"CREATE TABLE WorkorderSteps ("
"WorkOrder VARCHAR,"
"DYELOT VARCHAR,"
"ProgramID VARCHAR,"
"Program VARCHAR,"
"ReDye INT DEFAULT (0),"
"Mode VARCHAR,"
"Step INT,"
"StepID VARCHAR,"
"StepName VARCHAR,"
"ParameterName VARCHAR,"
"Parameter1 DOUBLE,"
"Parameter2 DOUBLE,"
"Parameter3 DOUBLE,"
"Parameter4 DOUBLE,"
"Parameter5 DOUBLE,"
"Parameter6 INT,"
"Parameter7 INT,"
"Parameter8 INT,"
"Parameter9 INT,"
"Parameter10 INT,"
"Remark VARCHAR,"
"StepTime INT,"
"StepID_S1 VARCHAR,"
"StepID_S2 VARCHAR,"
"StepID_S3 VARCHAR,"
"StepName_S1 VARCHAR,"
"StepName_S2 VARCHAR,"
"StepName_S3 VARCHAR,"
"Parameter1_S1 DOUBLE,"
"Parameter1_S2 DOUBLE,"
"Parameter1_S3 DOUBLE,"
"Parameter2_S1 DOUBLE,"
"Parameter2_S2 DOUBLE,"
"Parameter2_S3 DOUBLE,"
"Parameter3_S1 DOUBLE,"
"Parameter3_S2 DOUBLE,"
"Parameter3_S3 DOUBLE,"
"Parameter4_S1 DOUBLE,"
"Parameter4_S2 DOUBLE,"
"Parameter4_S3 DOUBLE,"
"Parameter5_S1 DOUBLE,"
"Parameter5_S2 DOUBLE,"
"Parameter5_S3 DOUBLE"
"); ";
"CREATE TABLE WorkorderSteps (WorkOrder VARCHAR,DYELOT VARCHAR,ProgramID VARCHAR,Program VARCHAR,ReDye INT DEFAULT (0),"
"Mode VARCHAR,Step INT,StepID VARCHAR,StepName VARCHAR,ParameterName VARCHAR,P1 DOUBLE,P2 DOUBLE,P3 DOUBLE,"
"P4 DOUBLE,P5 DOUBLE,P6 INT,P7 INT,P8 INT,P9 INT,P10 INT,Remark VARCHAR,StepTime INT,StepID_S1 VARCHAR,"
"StepID_S2 VARCHAR,StepID_S3 VARCHAR,StepName_S1 VARCHAR,StepName_S2 VARCHAR,StepName_S3 VARCHAR,P1_S1 DOUBLE,"
"P1_S2 DOUBLE,P1_S3 DOUBLE,P2_S1 DOUBLE,P2_S2 DOUBLE,P2_S3 DOUBLE,P3_S1 DOUBLE,P3_S2 DOUBLE,P3_S3 DOUBLE,"
"P4_S1 DOUBLE,P4_S2 DOUBLE,P4_S3 DOUBLE,P5_S1 DOUBLE,P5_S2 DOUBLE,P5_S3 DOUBLE); ";
static const char *sql_upgrade_workorder_set =
"CREATE TABLE WorkOrderSet ("
"WorkOrder VARCHAR,"
"ReDye INT DEFAULT (0),"
"PumpSpeed INT,"
"Blower INT,"
"Swing INT,"
"ClothWheel INT,"
"Nozzle INT"
"); ";
"CREATE TABLE WorkOrderSet (WorkOrder VARCHAR,ReDye INT DEFAULT (0),PumpSpeed INT,Blower INT,Swing INT,ClothWheel INT,Nozzle INT); ";
static const char *sql_upgrade_workorder =
"CREATE TABLE WorkOrder ("
"WorkOrder VARCHAR,"
"Dyelot VARCHAR,"
"ReDye INT DEFAULT (0),"
"ProgramName VARCHAR,"
"StartTime DATETIME,"
"EndTime DATETIME,"
"Time TEXT,"
"lock INT,"
"State INT,"
"ProgramID VARCHAR,"
"Machines VARCHAR,"
"color VARCHAR,"
"ColorNumber VARCHAR,"
"Client VARCHAR,"
"ClothWeight VARCHAR,"
"ClothSpecies VARCHAR,"
"BathRatio VARCHAR,"
"Total VARCHAR,"
"USER VARCHAR,"
"ColorName VARCHAR,"
"Remark TEXT"
"); ";
"CREATE TABLE WorkOrder (WorkOrder VARCHAR,Dyelot VARCHAR,ReDyeINT DEFAULT (0),ProgramNameVARCHAR,StartTime DATETIME,EndTime DATETIME,"
"Time TEXT,lock INT,State INT,ProgramID VARCHAR,Machines VARCHAR,color VARCHAR,ColorNumber VARCHAR,Client VARCHAR,ClothWeight VARCHAR,"
"ClothSpecies VARCHAR,BathRatio VARCHAR,Total VARCHAR,USER VARCHAR,ColorName VARCHAR,Remark TEXT); ";
static const char *sql_upgrade_run_table =
// "PRAGMA foreign_keys = OFF; "
// "BEGIN TRANSACTION; "
// "CREATE TABLE sqlitestudio_temp_table AS SELECT * FROM RUN; "
// "DROP TABLE RUN; "
"CREATE TABLE RUN ("
"WorkOrder VARCHAR,"
"DYELOT VARCHAR,"
"ReDye INT DEFAULT (0),"
"RUN INT,"
"Mode VARCHAR,"
"ProgramID VARCHAR,"
"Program VARCHAR,"
"StepID VARCHAR,"
"Step INT,"
"StepName VARCHAR,"
"ParameterName VARCHAR,"
"Parameter1 DOUBLE,"
"Parameter2 DOUBLE,"
"Parameter3 DOUBLE,"
"Parameter4 DOUBLE,"
"Parameter5 DOUBLE,"
"Parameter6 INT,"
"Parameter7 INT,"
"Parameter8 INT,"
"Parameter9 INT,"
"Parameter10 INT,"
"Remark VARCHAR,"
"StepTime INT,"
"StepID_S1 VARCHAR,"
"StepID_S2 VARCHAR,"
"StepID_S3 VARCHAR,"
"StepName_S1 VARCHAR,"
"StepName_S2 VARCHAR,"
"StepName_S3 VARCHAR,"
"Parameter1_S1 DOUBLE,"
"Parameter1_S2 DOUBLE,"
"Parameter1_S3 DOUBLE,"
"Parameter2_S1 DOUBLE,"
"Parameter2_S2 DOUBLE,"
"Parameter2_S3 DOUBLE,"
"Parameter3_S1 DOUBLE,"
"Parameter3_S2 DOUBLE,"
"Parameter3_S3 DOUBLE,"
"Parameter4_S1 DOUBLE,"
"Parameter4_S2 DOUBLE,"
"Parameter4_S3 DOUBLE,"
"Parameter5_S1 DOUBLE,"
"Parameter5_S2 DOUBLE,"
"Parameter5_S3 DOUBLE"
");";
"CREATE TABLE RUN (WorkOrder VARCHAR,DYELOT VARCHAR,ProgramID VARCHAR,Program VARCHAR,ReDye INT DEFAULT (0),"
"Mode VARCHAR,Step INT,StepID VARCHAR,StepName VARCHAR,ParameterName VARCHAR,P1 DOUBLE,P2 DOUBLE,P3 DOUBLE,"
"P4 DOUBLE,P5 DOUBLE,P6 INT,P7 INT,P8 INT,P9 INT,P10 INT,Remark VARCHAR,StepTime INT,StepID_S1 VARCHAR,"
"StepID_S2 VARCHAR,StepID_S3 VARCHAR,StepName_S1 VARCHAR,StepName_S2 VARCHAR,StepName_S3 VARCHAR,P1_S1 DOUBLE,"
"P1_S2 DOUBLE,P1_S3 DOUBLE,P2_S1 DOUBLE,P2_S2 DOUBLE,P2_S3 DOUBLE,P3_S1 DOUBLE,P3_S2 DOUBLE,P3_S3 DOUBLE,"
"P4_S1 DOUBLE,P4_S2 DOUBLE,P4_S3 DOUBLE,P5_S1 DOUBLE,P5_S2 DOUBLE,P5_S3 DOUBLE); ";
static const char *sql_upgrade_dyelot_table =
"CREATE TABLE Dyelot ("
"WorkOrder VARCHAR,"
"Dyelot VARCHAR,"
"ReDye INT,"
"Machine VARCHAR,"
"Step INT,"
"Tank INT,"
"State INT,"
"ProductCode VARCHAR,"
"ProductName VARCHAR,"
"ProductType INT,"
"Grams FLOAT,"
"Amount FLOAT,"
"CALL_TIME VARCHAR,"
"DispenseEndTime VARCHAR,"
"Type INT"
"); ";
"CREATE TABLE Dyelot (WorkOrder VARCHAR,Dyelot VARCHAR,ReDye INT,Machine VARCHAR,Step INT,Tank INT,State INT,ProductCode VARCHAR,"
"ProductName VARCHAR,ProductType INT,Grams FLOAT,Amount FLOAT,CALL_TIME VARCHAR,DispenseEndTime VARCHAR,Type INT); ";
static const char *sql_upgrade_iolog_table =
// "CREATE TABLE sqlitestudio_temp_table AS SELECT * FROM IOLog; "
// "DROP TABLE IOLog; "
"CREATE TABLE IOLog ("
"ID varchar(32),"
"IOName varchar(32),"
"type varchar(32),"
"Value DOUBLE DEFAULT (0),"
"DIO BOOLEAN,"
"AIO INTEGER DEFAULT (0),"
"PLC varchar(32)"
"); ";
"CREATE TABLE IOLog (ID varchar,IOName varchar,type varchar,Value DOUBLE DEFAULT (0),DIO BOOLEAN,AIO INTEGER DEFAULT (0),PLC varchar); ";
static const char *sql_upgrade_chart_table =
"CREATE TABLE Chart ("
"WorkOrder varchar(32),"
"DYELOT varchar(32),"
"ReDye INTEGER ,"
"Name varchar(32),"
"Time varchar(32),"
"MTT DOUBLE DEFAULT (0),"
"MTL DOUBLE DEFAULT (0),"
"STTA DOUBLE DEFAULT (0),"
"STLA DOUBLE DEFAULT (0),"
"STTB DOUBLE DEFAULT (0),"
"STLB DOUBLE DEFAULT (0),"
"STTC DOUBLE DEFAULT (0),"
"STLC DOUBLE DEFAULT (0),"
"MTH DOUBLE DEFAULT (0),"
"MST DOUBLE DEFAULT (0),"
"MSL DOUBLE DEFAULT (0),"
"MUT DOUBLE DEFAULT (0)"
"); ";
"CREATE TABLE Chart (WorkOrder varchar,DYELOT varchar,ReDye INTEGER,Name varchar,Time varchar,MTT DOUBLE DEFAULT (0),MTL DOUBLE DEFAULT (0),"
"STTA DOUBLE DEFAULT (0),STLA DOUBLE DEFAULT (0),STTB DOUBLE DEFAULT (0),STLB DOUBLE DEFAULT (0),STTC DOUBLE DEFAULT (0),"
"STLC DOUBLE DEFAULT (0),MTH DOUBLE DEFAULT (0),MST DOUBLE DEFAULT (0),MSL DOUBLE DEFAULT (0),MUT DOUBLE DEFAULT (0)); ";
void db_sqlite(void *parameter)
// ------------------------
// 内部工具函数
// ------------------------
/**
* @brief 返回超时错误(排队时间过长)
*/
static void return_timeout(struct db_command *cmd) {
cmd->result_code = -RT_ETIMEOUT;
rt_strncpy(cmd->result, "Cmd timeout: waited too long in queue", MAX_RESULT_LEN - 1);
if (cmd->reply_sem) {
rt_sem_release(cmd->reply_sem);
}
}
/**
* @brief 返回“数据库已禁用”错误
*/
static void return_disabled(struct db_command *cmd) {
cmd->result_code = -RT_ENODEV;
rt_strncpy(cmd->result, "Error: Database is disabled", MAX_RESULT_LEN - 1);
if (cmd->reply_sem) {
rt_sem_release(cmd->reply_sem);
}
}
/**
* @brief SELECT 查询回调函数
*/
static int callback(void *result_str, int argc, char **argv, char **azColName) {
char *str = (char *)result_str;
int len = rt_strlen(str);
for (int i = 0; i < argc; i++) {
rt_snprintf(str + len, MAX_RESULT_LEN - len, "%s=%s|",
azColName[i], argv[i] ? argv[i] : "NULL");
len = rt_strlen(str);
}
return 0;
}
/**
* @brief 执行具体 SQL 操作
*/
static void handle_db_command(struct db_command *cmd) {
char *err_msg = 0;
int rc;
switch (cmd->type) {
case DB_CMD_INSERT:
case DB_CMD_DELETE:
case DB_CMD_UPDATE:
case DB_CMD_EXEC:
rc = sqlite3_exec(g_db, cmd->sql, 0, 0, &err_msg);
if (rc != SQLITE_OK) {
cmd->result_code = rc;
rt_strncpy(cmd->result, err_msg, MAX_RESULT_LEN - 1);
sqlite3_free(err_msg);
} else {
cmd->result_code = 0;
rt_strncpy(cmd->result, "OK", MAX_RESULT_LEN - 1);
}
break;
case DB_CMD_SELECT:
cmd->result[0] = '\0';
rc = sqlite3_exec(g_db, cmd->sql, callback, cmd->result, &err_msg);
if (rc != SQLITE_OK) {
cmd->result_code = rc;
rt_strncpy(cmd->result, err_msg, MAX_RESULT_LEN - 1);
sqlite3_free(err_msg);
} else {
cmd->result_code = 0;
if (cmd->result[0] == '\0')
rt_strncpy(cmd->result, "No data", MAX_RESULT_LEN - 1);
}
break;
case DB_CMD_EXIT:
rt_strncpy(cmd->result, "Exit", MAX_RESULT_LEN - 1);
cmd->result_code = 0;
break;
default:
cmd->result_code = -1;
rt_strncpy(cmd->result, "Invalid command", MAX_RESULT_LEN - 1);
break;
}
}
// ------------------------
// 外部接口实现
// ------------------------
/**
* @brief 外部调用:立即关闭数据库并禁用所有操作
*/
void close_db_immediately(void) {
if (!state_mutex) return;
rt_mutex_take(state_mutex, RT_WAITING_FOREVER);
{
if (g_db) {
sqlite3_close(g_db);
g_db = RT_NULL;
}
db_enabled = RT_FALSE;
}
rt_mutex_release(state_mutex);
rt_kprintf("Database disabled.\n");
}
void db_sqlite_init_full(void)
{
if (access(DB_NAME, F_OK) == 0)
{
rt_kprintf("DB open\n");
if (db_connect(DB_NAME) == RT_EOK){
if(db_table_is_exist("WorkorderSteps")<=0){
if(db_create_database(sql_upgrade_workorder_steps)==0)
{rt_kprintf("WorkorderSteps Created successfully \n");}else{rt_kprintf("WorkorderSteps Creation failed \n");}
}
if(db_table_is_exist("WorkOrderSet")<=0){
if(db_create_database(sql_upgrade_workorder_set)==0)
{rt_kprintf("WorkOrderSet Created successfully \n");}else{rt_kprintf("WorkOrderSet Creation failed \n");}
}
if(db_table_is_exist("WorkOrder")<=0){
if(db_create_database(sql_upgrade_workorder)==0)
{rt_kprintf("WorkOrder Created successfully \n");}else{rt_kprintf("WorkOrder Creation failed \n");}
}
if(db_table_is_exist("RUN")<=0){
if(db_create_database(sql_upgrade_run_table)==0)
{rt_kprintf("RUN Created successfully \n");}else{rt_kprintf("RUN Creation failed \n");}
}
if(db_table_is_exist("Dyelot")<=0){
if(db_create_database(sql_upgrade_dyelot_table)==0)
{rt_kprintf("Dyelot Created successfully \n");}else{rt_kprintf("Dyelot Creation failed \n");}
}
if(db_table_is_exist("IOLog")<=0){
if(db_create_database(sql_upgrade_iolog_table)==0)
{rt_kprintf("IOLog Created successfully \n");}else{rt_kprintf("IOLog Creation failed \n");}
}
if(db_table_is_exist("Chart")<=0){
if(db_create_database(sql_upgrade_chart_table)==0)
{rt_kprintf("Chart Created successfully \n");}else{rt_kprintf("Chart Creation failed \n");}
}
{
rt_kprintf("DB open\n");
if (db_connect(DB_NAME) == RT_EOK){
if(db_table_is_exist("WorkorderSteps")<=0){
if(db_create_database(sql_upgrade_workorder_steps)==0)
{rt_kprintf("WorkorderSteps Created successfully \n");}else{rt_kprintf("WorkorderSteps Creation failed \n");}
}
if(db_table_is_exist("WorkOrderSet")<=0){
if(db_create_database(sql_upgrade_workorder_set)==0)
{rt_kprintf("WorkOrderSet Created successfully \n");}else{rt_kprintf("WorkOrderSet Creation failed \n");}
}
if(db_table_is_exist("WorkOrder")<=0){
if(db_create_database(sql_upgrade_workorder)==0)
{rt_kprintf("WorkOrder Created successfully \n");}else{rt_kprintf("WorkOrder Creation failed \n");}
}
if(db_table_is_exist("RUN")<=0){
if(db_create_database(sql_upgrade_run_table)==0)
{rt_kprintf("RUN Created successfully \n");}else{rt_kprintf("RUN Creation failed \n");}
}
if(db_table_is_exist("Dyelot")<=0){
if(db_create_database(sql_upgrade_dyelot_table)==0)
{rt_kprintf("Dyelot Created successfully \n");}else{rt_kprintf("Dyelot Creation failed \n");}
}
if(db_table_is_exist("IOLog")<=0){
if(db_create_database(sql_upgrade_iolog_table)==0)
{rt_kprintf("IOLog Created successfully \n");}else{rt_kprintf("IOLog Creation failed \n");}
}
if(db_table_is_exist("Chart")<=0){
if(db_create_database(sql_upgrade_chart_table)==0)
{rt_kprintf("Chart Created successfully \n");}else{rt_kprintf("Chart Creation failed \n");}
}
}else{
rt_kprintf("DB ok\n");
db_connect(DB_NAME);
}
}else{
rt_kprintf("DB open failed \n");
sqlite3_open(DB_NAME, db);
//创建表
db_create_database(sql_upgrade_workorder_steps);
db_create_database(sql_upgrade_workorder_set);
db_create_database(sql_upgrade_workorder);
db_create_database(sql_upgrade_run_table);
db_create_database(sql_upgrade_dyelot_table);
db_create_database(sql_upgrade_iolog_table);
db_create_database(sql_upgrade_chart_table);
}
}
}else{
rt_kprintf("DB open failed \n");
sqlite3_open(DB_NAME, db);
//创建表
db_create_database(sql_upgrade_workorder_steps);
db_create_database(sql_upgrade_workorder_set);
db_create_database(sql_upgrade_workorder);
db_create_database(sql_upgrade_run_table);
db_create_database(sql_upgrade_dyelot_table);
db_create_database(sql_upgrade_iolog_table);
db_create_database(sql_upgrade_chart_table);
/**
* @brief 数据库处理线程入口函数
*/
static void db_sqlite(void *parameter) {
struct db_command cmd;
rt_tick_t max_wait_ticks = rt_tick_from_millisecond(DB_MAX_WAITING_MS);
// 检查并初始化数据库文件
db_sqlite_init_full();
// ✅ 使用 rt_mq_create 动态创建消息队列
db_mq = rt_mq_create("db_mq", sizeof(struct db_command), DB_QUEUE_SIZE, RT_IPC_FLAG_FIFO);
if (db_mq == RT_NULL) {
rt_kprintf("Failed to create message queue 'db_mq'!\n");
return;
}
// 创建状态锁
state_mutex = rt_mutex_create("db_lock", RT_IPC_FLAG_FIFO);
if (!state_mutex) {
rt_kprintf("Failed to create db_lock mutex!\n");
rt_mq_delete(db_mq); // 创建失败要清理
db_mq = RT_NULL;
return;
}
// db_HelperInit = db_helper_init();
// if(db_HelperInit =RT_EOK){
// rt_kprintf("HelperInit database\n");
// }else {
// sqlite3_open(DB_NAME, db);
// db_ = db_create_database("CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);");
// if(db_=0){rt_kprintf("database ok\n");}else{rt_kprintf("database no\n");}
// }
/* int fd = 0;
const char *dbname = db_get_name();
fd = open(dbname, O_RDONLY);
if (fd > 0)
rt_kprintf("%s exist\r\n", dbname);
else
rt_kprintf("%s not exist\r\n");
const char *sql = "CREATE TABLE IF NOT EXISTS student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
rt_kprintf("sql cmd: %s\r\n\r\n", sql);
int ret = db_create_database(sql);
rt_kprintf("sql ret: %d\r\n", ret);*/
// 默认启用数据库
db_enabled = RT_TRUE;
// sqlite3_os_init();
/* int rc = db_connect("/rt.db");
if (rc <0) {
const char *sql = "CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(32) NOT NULL,score INT NOT NULL);";
int db_create_database(sql);
}*/
rt_kprintf("Database handler started. Path: %s\n", DB_NAME);
while (1) {
// 接收命令
if (rt_mq_recv(db_mq, &cmd, sizeof(struct db_command), RT_WAITING_FOREVER) != RT_EOK)
continue;
// 1. 检查排队超时
rt_tick_t now = rt_tick_get();
if ((now - cmd.send_tick) > max_wait_ticks) {
int wait_ms = (now - cmd.send_tick) * 1000 / RT_TICK_PER_SECOND;
rt_kprintf("DROP cmd[type=%d]: waited %dms > limit(%dms)\n", cmd.type, wait_ms, DB_MAX_WAITING_MS);
return_timeout(&cmd);
continue;
}
// 2. 获取当前启用状态
rt_bool_t current_enabled;
rt_mutex_take(state_mutex, RT_WAITING_FOREVER);
current_enabled = db_enabled;
rt_mutex_release(state_mutex);
// 3. 若已禁用 → 返回错误
if (!current_enabled) {
rt_kprintf("Rejected cmd[type=%d]: database is disabled\n", cmd.type);
return_disabled(&cmd);
if (cmd.type == DB_CMD_EXIT) break;
continue;
}
// 4. 打开数据库(如果未打开)
rt_mutex_take(state_mutex, RT_WAITING_FOREVER);
{
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);
}
}
}
rt_mutex_release(state_mutex);
// 5. 执行命令
handle_db_command(&cmd);
// 6. 返回结果
if (cmd.reply_sem) {
rt_sem_release(cmd.reply_sem);
}
// 7. 退出命令
if (cmd.type == DB_CMD_EXIT) break;
}
// ✅ 清理资源
if (g_db) {
sqlite3_close(g_db);
g_db = RT_NULL;
}
db_enabled = RT_FALSE;
if (state_mutex) {
rt_mutex_delete(state_mutex);
state_mutex = RT_NULL;
}
// ✅ 删除动态消息队列
if (db_mq) {
rt_mq_delete(db_mq);
db_mq = RT_NULL;
}
rt_kprintf("Database handler exited.\n");
}
/**
* @brief 向数据库发送命令并等待响应
*
* @param type 命令类型(INSERT/SELECT等)
* @param sql SQL 语句字符串
* @param timeout_ms 超时时间(毫秒),0 表示不等待
* @return RT_EOK 成功,RT_ETIMEOUT 超时,RT_ERROR 失败
*/
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;
// 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;
}
// 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();
// 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;
}
// 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); // 永久等待(慎用)
}
// 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;
}
/* 线程 */
@@ -291,7 +420,7 @@ void thread_DB_SQLite(void)
{
/* 初始化线程 1,名称是 thread1,入口是 thread1_entry*/
rt_thread_t tid;
tid = rt_thread_create("db_sqlite", db_sqlite, RT_NULL, 1024*64, 3, 15);
tid = rt_thread_create("db_sqlite", db_sqlite, RT_NULL, 1024*16, 3, 15);
if (tid != RT_NULL)
{
+107
View File
@@ -10,6 +10,113 @@
#ifndef APPLICATIONS_DB_DB_SQLITE_H_
#define APPLICATIONS_DB_SQLITE_SYS_H_
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ========================
* 配置参数
* ======================== */
#ifndef MAX_SQL_LEN
#define MAX_SQL_LEN (1024) /**< SQL 语句最大长度 */
#endif
#ifndef MAX_RESULT_LEN
#define MAX_RESULT_LEN (1024) /**< 结果字符串最大长度 */
#endif
#ifndef DB_MAX_WAITING_MS
#define DB_MAX_WAITING_MS (5000) /**< 命令最大等待时间(毫秒),默认 5 秒 */
#endif
#ifndef DB_QUEUE_SIZE
#define DB_QUEUE_SIZE (8) /**< 消息队列容量(最多缓存 8 条命令) */
#endif
/* 补充常见错误码(如果 RT-Thread 未定义) */
#ifndef RT_ENODEV
#define RT_ENODEV (-5)
#endif
#ifndef RT_ETIMEOUT
#define RT_ETIMEOUT (-4)
#endif
/* ========================
* 命令类型枚举
* ======================== */
enum db_cmd_type
{
DB_CMD_INSERT, /**< 插入数据 */
DB_CMD_DELETE, /**< 删除数据 */
DB_CMD_UPDATE, /**< 更新数据 */
DB_CMD_SELECT, /**< 查询数据(返回结果字符串) */
DB_CMD_EXEC, /**< 执行任意 SQL(无结果集) */
DB_CMD_EXIT /**< 退出数据库线程(内部使用) */
};
/* ========================
* 数据库命令结构体
* ======================== */
struct db_command
{
enum db_cmd_type type; /**< 命令类型 */
char sql[MAX_SQL_LEN]; /**< SQL 语句内容 */
rt_uint32_t result_code; /**< 返回码(SQLite code 或负的 RT-Error) */
char result[MAX_RESULT_LEN]; /**< 结果或错误信息 */
rt_sem_t reply_sem; /**< 回应信号量(由调用方创建,用于同步) */
rt_tick_t send_tick; /**< 发送时刻的系统 tick,用于超时检测 */
};
/* ========================
* 全局变量声明
* ======================== */
/**
* 消息队列句柄:用于向数据库线程发送命令
* 必须在 .c 文件中定义为:rt_mq_t db_mq = RT_NULL;
*/
extern rt_mq_t db_mq;
/* ========================
* 函数接口声明
* ======================== */
/**
* @brief 启动数据库处理线程
*
* 创建一个名为 "data_sqlite" 的线程,初始化 SQLite 数据库,
* 并开始监听 db_mq 中的 SQL 请求。
*
* @note 若已运行,多次调用无效。
*/
void thread_DB_SQLite(void);
/**
* @brief 立即关闭数据库并禁止后续操作
*
* 关闭当前数据库连接,并设置禁用标志。
* 之后所有新请求将立即失败,返回“数据库已禁用”。
*
* @note 此函数是线程安全的。
*/
void close_db_immediately(void);
/**
* @brief 向数据库发送命令并等待响应
*
* @param type 命令类型(INSERT/SELECT等)
* @param sql SQL 语句字符串
* @param timeout_ms 超时时间(毫秒),0 表示不等待
* @return RT_EOK 成功,RT_ETIMEOUT 超时,RT_ERROR 失败
*/
rt_err_t db_send_command(enum db_cmd_type type, const char* sql, rt_int32_t timeout_ms);
#ifdef __cplusplus
}
#endif
#endif /* APPLICATIONS_DB_DB_SQLITE_H_ */