diff --git a/.config b/.config index a338552..a8f14f1 100644 --- a/.config +++ b/.config @@ -174,7 +174,9 @@ CONFIG_RT_USING_PIN=y # CONFIG_RT_USING_MTD_NOR is not set # CONFIG_RT_USING_MTD_NAND is not set # CONFIG_RT_USING_PM is not set -# CONFIG_RT_USING_RTC is not set +CONFIG_RT_USING_RTC=y +# CONFIG_RT_USING_ALARM is not set +CONFIG_RT_USING_SOFT_RTC=y CONFIG_RT_USING_SDIO=y CONFIG_RT_SDIO_STACK_SIZE=1024 CONFIG_RT_SDIO_THREAD_PRIORITY=15 diff --git a/.cproject b/.cproject index 2bf3637..df1c29d 100644 --- a/.cproject +++ b/.cproject @@ -892,7 +892,7 @@ - + diff --git a/applications/DATA/DATA_comm.c b/applications/DATA/DATA_comm.c index a79984f..e75c88b 100644 --- a/applications/DATA/DATA_comm.c +++ b/applications/DATA/DATA_comm.c @@ -17,6 +17,7 @@ #include "language.h" #include "Variable.h" #include "SC828_DATA_table.h" +#include "DB_SQLite.h" rt_mq_t proc_mq; @@ -59,15 +60,29 @@ int extract_between(const char *src, const char *start, const char *end, char *b } \ } while(0) // 提取浮点数 -#define GET_FLOAT_VAR(var, obj, key, default_val) do { \ - cJSON* _item = cJSON_GetObjectItem(obj, key); \ - (var) = cJSON_IsNumber(_item) ? (float)_item->valuedouble : (default_val); \ +#define GET_FLOAT_VAR(var, obj, key, default_val)do { \ + cJSON *_item = cJSON_GetObjectItem((obj), (key)); \ + (var) = (_item && cJSON_IsNumber(_item)) ? (float)(_item->valuedouble) : (default_val); \ } while(0) // 提取整数(int 类型) #define GET_INT_VAR(var, obj, key, default_val) do { \ cJSON* _item = cJSON_GetObjectItem(obj, key); \ (var) = cJSON_IsNumber(_item) ? (int)_item->valueint : (default_val); \ } while(0) +#define GET_INT_FROM_ANY(var, obj, key, default_val)do { \ + cJSON *_item = cJSON_GetObjectItem((obj), (key)); \ + if (_item) { \ + if (cJSON_IsNumber(_item)) { \ + (var) = (int)(_item->valueint); \ + } else if (cJSON_IsString(_item) && _item->valuestring) { \ + (var) = atoi(_item->valuestring); \ + } else { \ + (var) = (default_val); \ + } \ + } else { \ + (var) = (default_val); \ + } \ +} while(0) // ===== cJSON分析 =====// void pasre_DAT(const char *api, const char *json_str) @@ -102,46 +117,76 @@ void pasre_DAT(const char *api, const char *json_str) } else if (strcmp(api, "SC810") == 0) { + char STime[25]; + char pTime[10]; + // 字符串赋值 + GET_STRING(Work, root, "Work", sizeof(Work)); + GET_STRING(Dye, root, "Dye", sizeof(Dye)); + GET_STRING(STime, root, "STime", sizeof(STime)); + GET_STRING(pTime, root, "Time", sizeof(pTime)); + + // 定义足够大的缓冲区 + char sql[512] = {0}; // 初始化为 0 + // 安全格式化 + rt_snprintf(sql, sizeof(sql), + "INSERT INTO WorkorderSteps(WorkOrder,DYELOT,ReDye,StartTime,Time)" + "VALUES('%s','%s',0,%s,%s,)", + Work, Dye, STime,pTime); + if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) // + { + cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work)); + cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(Redye)); + } } else if (strcmp(api, "SC811") == 0) {//工单明细 - // === 解析整数变量 StepN === - GET_INT_VAR(StepN, root, "StepN", 0); - // 字符串赋值 - GET_STRING(Work, root, "Work", sizeof(Work)); - GET_STRING(Dye, root, "Dye", sizeof(Dye)); - GET_STRING(StepID, root, "StepID", sizeof(StepID)); - GET_STRING(SIDS1, root, "SIDS1", sizeof(SIDS1)); - GET_STRING(SIDS2, root, "SIDS2", sizeof(SIDS2)); - GET_STRING(SIDS3, root, "SIDS3", sizeof(SIDS3)); - // 浮点数赋值 - GET_FLOAT_VAR(P1, root, "P1", 0.0f); - GET_FLOAT_VAR(P2, root, "P2", 0.0f); - GET_FLOAT_VAR(P3, root, "P3", 0.0f); - GET_FLOAT_VAR(P4, root, "P4", 0.0f); - GET_FLOAT_VAR(P5, root, "P5", 0.0f); - GET_FLOAT_VAR(P1S1, root, "P1S1", 0.0f); - GET_FLOAT_VAR(P2S1, root, "P2S1", 0.0f); - GET_FLOAT_VAR(P3S1, root, "P3S1", 0.0f); - GET_FLOAT_VAR(P4S1, root, "P4S1", 0.0f); - GET_FLOAT_VAR(P5S1, root, "P5S1", 0.0f); - GET_FLOAT_VAR(P1S2, root, "P1S2", 0.0f); - GET_FLOAT_VAR(P2S2, root, "P2S2", 0.0f); - GET_FLOAT_VAR(P3S2, root, "P3S2", 0.0f); - GET_FLOAT_VAR(P4S2, root, "P4S2", 0.0f); - GET_FLOAT_VAR(P5S2, root, "P5S2", 0.0f); - GET_FLOAT_VAR(P1S3, root, "P1S3", 0.0f); - GET_FLOAT_VAR(P2S3, root, "P2S3", 0.0f); - GET_FLOAT_VAR(P3S3, root, "P3S3", 0.0f); - GET_FLOAT_VAR(P4S3, root, "P4S3", 0.0f); - GET_FLOAT_VAR(P5S3, root, "P5S3", 0.0f); + // 字符串赋值 + GET_STRING(Work, root, "Work", sizeof(Work)); + GET_STRING(Dye, root, "Dye", sizeof(Dye)); + GET_STRING(StepID, root, "StepID", sizeof(StepID)); + GET_STRING(SIDS1, root, "SIDS1", sizeof(SIDS1)); + //GET_STRING(SIDS2, root, "SIDS2", sizeof(SIDS2)); + //GET_STRING(SIDS3, root, "SIDS3", sizeof(SIDS3)); + //整数 + GET_INT_FROM_ANY(StepN, root, "Step", 0); + GET_INT_FROM_ANY(P1, root, "P1", 0); + GET_INT_FROM_ANY(P2, root, "P2", 0); + GET_INT_FROM_ANY(P3, root, "P3", 0); + GET_INT_FROM_ANY(P4, root, "P4", 0); + GET_INT_FROM_ANY(P5, root, "P5", 0); + GET_INT_FROM_ANY(P1S1, root, "P1S1",0); + GET_INT_FROM_ANY(P2S1, root, "P2S1",0); + GET_INT_FROM_ANY(P3S1, root, "P3S1",0); + GET_INT_FROM_ANY(P4S1, root, "P4S1",0); + GET_INT_FROM_ANY(P5S1, root, "P5S1",0); + //GET_INT_FROM_ANY(P1S2, root, "P1S2",0); + //GET_INT_FROM_ANY(P2S2, root, "P2S2",0); + //GET_INT_FROM_ANY(P3S2, root, "P3S2",0); + //GET_INT_FROM_ANY(P4S2, root, "P4S2",0); + //GET_INT_FROM_ANY(P5S2, root, "P5S2",0); + //GET_INT_FROM_ANY(P1S3, root, "P1S3",0); + //GET_INT_FROM_ANY(P2S3, root, "P2S3",0); + //GET_INT_FROM_ANY(P3S3, root, "P3S3",0); + //GET_INT_FROM_ANY(P4S3, root, "P4S3",0); + //GET_INT_FROM_ANY(P5S3, root, "P5S3",0); + + // 定义足够大的缓冲区 + char sql[512] = {0}; // 初始化为 0 - cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work)); - cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(Redye)); - cJSON_AddItemToObject(dat,"StepN",cJSON_CreateNumber(StepN)); + // 安全格式化 + rt_snprintf(sql, sizeof(sql), + "INSERT INTO WorkorderSteps(WorkOrder,DYELOT,ReDye,Step,StepID,P1,P2,P3,P4,P5,StepID_S1,P1_S1,P2_S1,P3_S1,P4_S1,P5_S1)" + "VALUES('%s','%s',0,%d,%s,%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d)", + Work, Dye, StepN,StepID,P1, P2, P3, P4, P5,SIDS1,P1S1,P2S1,P3S1,P4S1,P5S1 ); + if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) // + { + cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work)); + cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(Redye)); + cJSON_AddItemToObject(dat,"Step",cJSON_CreateNumber(StepN)); + } } else if (strcmp(api, "SC812") == 0) { - printf("Processing:SC812\n"); + //工单设定 } else if (strcmp(api, "SC813") == 0) { printf("Processing:SC813\n"); @@ -296,22 +341,27 @@ void proc_thread_entry(void *parameter) { if (!req) continue; memcpy(DATA_api,req->input,5); - extract_between(req->input, "[", "]", machine_ID, sizeof(machine_ID)); + 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 { + p += strlen("]"); + } - char *p=strstr(req->input,"]"); - if(!p){cjson_falg=0;} - else { - p += strlen("]"); - } + //处理指令分析 + pasre_DAT(DATA_api,p); - //处理指令分析 - pasre_DAT(DATA_api,p); - // 回复 - int16_t total_len = strlen(machine_ID) + strlen(json_buffer) + 8; - char t_buffer[total_len]; - snprintf(t_buffer,total_len,"%s[%s]%s\n",DATA_api,machine_ID,json_buffer); - req->output_len = rt_snprintf(req->output, sizeof(req->output),t_buffer); + // 回复 + int16_t total_len = strlen(machine_ID) + strlen(json_buffer) + 8; + char t_buffer[total_len]; + snprintf(t_buffer,total_len,"%s[%s]%s\n",DATA_api,machine_ID,json_buffer); + req->output_len = rt_snprintf(req->output, sizeof(req->output),t_buffer); + }else{ + req->output_len=0; + } // 通知 UART 线程可以发送了 if (req->sem) @@ -332,7 +382,7 @@ int data_comm_init(void) } rt_thread_t tid = rt_thread_create("data_comm", proc_thread_entry, RT_NULL, - 1024*5, 20, 10); + 1024*4, 20, 10); if (tid != RT_NULL) { rt_thread_startup(tid); diff --git a/applications/DATA/Variable.c b/applications/DATA/Variable.c index 940c16d..2716314 100644 --- a/applications/DATA/Variable.c +++ b/applications/DATA/Variable.c @@ -5,7 +5,7 @@ // 动态数据缓冲区(初始化为 NULL,后续分配) char *DATA_dat; -char *DATA_machins; +char DATA_machins[3]; char DATA_api[5]; char *machine_name = "Q109"; char machine_ID[3] = "23"; @@ -17,8 +17,8 @@ char MACHINE_CALL = 0; char MACHINE_USER = 0; // 字符串变量(RAM 中可修改) -char Work[15]; -char Dye[15]; +char Work[25]; +char Dye[25]; char Process[50]; char Message[40]; char Step[60]; @@ -61,32 +61,32 @@ unsigned int P9 = 0; unsigned int P10 = 0; // 步骤功能参数 -float P1 = 0.0f; -float P2 = 0.0f; -float P3 = 0.0f; -float P4 = 0.0f; -float P5 = 0.0f; -float P1S1 = 0.0f; -float P2S1 = 0.0f; -float P3S1 = 0.0f; -float P4S1 = 0.0f; -float P5S1 = 0.0f; -float P1S2 = 0.0f; -float P2S2 = 0.0f; -float P3S2 = 0.0f; -float P4S2 = 0.0f; -float P5S2 = 0.0f; -float P1S3 = 0.0f; -float P2S3 = 0.0f; -float P3S3 = 0.0f; -float P4S3 = 0.0f; -float P5S3 = 0.0f; +unsigned int P1 = 0; +unsigned int P2 =0; +unsigned int P3 =0; +unsigned int P4 =0; +unsigned int P5 =0; +unsigned int P1S1 =0; +unsigned int P2S1 =0; +unsigned int P3S1 =0; +unsigned int P4S1 =0; +unsigned int P5S1 =0; +unsigned int P1S2 =0; +unsigned int P2S2 =0; +unsigned int P3S2 =0; +unsigned int P4S2 =0; +unsigned int P5S2 =0; +unsigned int P1S3 =0; +unsigned int P2S3 =0; +unsigned int P3S3 =0; +unsigned int P4S3 =0; +unsigned int P5S3 =0; // 步骤编号字符串 -char StepID[3]; -char SIDS1[3]; -char SIDS2[3]; -char SIDS3[3]; +char StepID[4]; +char SIDS1[4]; +char SIDS2[4]; +char SIDS3[4]; // ===== 初始化函数 ===== void init_global_vars(void) { diff --git a/applications/DATA/Variable.h b/applications/DATA/Variable.h index 53c3ad9..c11f5fd 100644 --- a/applications/DATA/Variable.h +++ b/applications/DATA/Variable.h @@ -5,7 +5,7 @@ // ===== 字符串变量 ===== extern char *DATA_dat; -extern char *DATA_machins; +extern char DATA_machins[3]; extern char DATA_api[5]; extern char *machine_name; extern char machine_ID[3]; @@ -17,8 +17,8 @@ extern char MACHINE_CALL; extern char MACHINE_USER; // ===== 字符串 ===== -extern char Work[15]; -extern char Dye[15]; +extern char Work[25]; +extern char Dye[25]; extern char Process[50]; extern char Message[40]; extern char Step[60]; @@ -57,31 +57,31 @@ extern float STTB; extern float STLB; extern float STTC; extern float STLC; -extern float P1; -extern float P2; -extern float P3; -extern float P4; -extern float P5; -extern float P1S1; -extern float P2S1; -extern float P3S1; -extern float P4S1; -extern float P5S1; -extern float P1S2; -extern float P2S2; -extern float P3S2; -extern float P4S2; -extern float P5S2; -extern float P1S3; -extern float P2S3; -extern float P3S3; -extern float P4S3; -extern float P5S3; +extern unsigned int P1; +extern unsigned int P2; +extern unsigned int P3; +extern unsigned int P4; +extern unsigned int P5; +extern unsigned int P1S1; +extern unsigned int P2S1; +extern unsigned int P3S1; +extern unsigned int P4S1; +extern unsigned int P5S1; +extern unsigned int P1S2; +extern unsigned int P2S2; +extern unsigned int P3S2; +extern unsigned int P4S2; +extern unsigned int P5S2; +extern unsigned int P1S3; +extern unsigned int P2S3; +extern unsigned int P3S3; +extern unsigned int P4S3; +extern unsigned int P5S3; -extern char StepID[3]; -extern char SIDS1[3]; -extern char SIDS2[3]; -extern char SIDS3[3]; +extern char StepID[4]; +extern char SIDS1[4]; +extern char SIDS2[4]; +extern char SIDS3[4]; void init_global_vars(void); diff --git a/applications/DBSQL/DB_SQLite.c b/applications/DBSQL/DB_SQLite.c index ddda5c8..aba6272 100644 --- a/applications/DBSQL/DB_SQLite.c +++ b/applications/DBSQL/DB_SQLite.c @@ -16,274 +16,403 @@ #include #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)" - "); "; - -void db_sqlite(void *parameter) -{ - if (access(DB_NAME, F_OK) == 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)); "; + +// ------------------------ +// 内部工具函数 +// ------------------------ + +/** + * @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); { - 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 (g_db) { + sqlite3_close(g_db); + g_db = RT_NULL; } - 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");} + 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");} + } + }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); } - 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");} +} + +/** + * @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_enabled = RT_TRUE; + + 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; } - 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");} + + // 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; } - 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");} + // 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); + } + } } - }else{ - rt_kprintf("DB open failed \n"); + rt_mutex_release(state_mutex); + + // 5. 执行命令 + handle_db_command(&cmd); + + // 6. 返回结果 + if (cmd.reply_sem) { + rt_sem_release(cmd.reply_sem); } - }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); + // 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); - // 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);*/ - - // 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); - }*/ + 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) { diff --git a/applications/DBSQL/DB_SQLite.h b/applications/DBSQL/DB_SQLite.h index 34de0eb..6551beb 100644 --- a/applications/DBSQL/DB_SQLite.h +++ b/applications/DBSQL/DB_SQLite.h @@ -10,6 +10,113 @@ #ifndef APPLICATIONS_DB_DB_SQLITE_H_ #define APPLICATIONS_DB_SQLITE_SYS_H_ +#include + +#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_ */ diff --git a/rtconfig.h b/rtconfig.h index cce01d1..4cfa15d 100644 --- a/rtconfig.h +++ b/rtconfig.h @@ -109,6 +109,8 @@ #define RT_SERIAL_USING_DMA #define RT_SERIAL_RB_BUFSZ 64 #define RT_USING_PIN +#define RT_USING_RTC +#define RT_USING_SOFT_RTC #define RT_USING_SDIO #define RT_SDIO_STACK_SIZE 1024 #define RT_SDIO_THREAD_PRIORITY 15