/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2025-03-27 RuoFeng the first version */ /*********************↑ declaration ↑************************/ /** * * * * * */ /*********************↓ define ↓************************/ #define DBG_ENABLE #define DBG_COLOR #define DBG_TAG "tn" #define DBG_LEVEL DBG_INFO #include #define RSSI_TO_DBM(rssi) (2 * (rssi) - 113) /*********************↑ define ↑************************/ /** * * * * * */ /*********************↓ include ↓************************/ #include #include "rs485.h" #include "dtu_uart2.h" #include "string.h" #include "control.h" #include #include #include "protocol.h" #include "test.h" #include "cJSON.h" /*********************↑ include ↑************************/ /** * * * * * */ /*********************↓ extern ↓************************/ extern uint8_t ReFlash_RTC(void); extern Device_Status_typedef device_status; extern RTC_DateTypeDef GetDate; extern RTC_TimeTypeDef GetTime; extern Sensor sensor[MAX_SENSOR_NUM]; extern JD_Test_Sta jts; extern int cjson_getval(cJSON *json); extern Limit limit; extern uint16_t RayTigCnt; extern char CamFree; /*********************↑ extern ↑************************/ /** * * * * * */ /********************↓ declaration ↓***********************/ /********************↑ declaration ↑***********************/ /** * * * * * */ /*********************↓ global variables ↓************************/ static struct RES_Type res_c = {0}; /*********************↑ global variables ↑************************/ /** * * * * * */ /** * @brief Get the Timing object 获取时间戳 * * @param str */ void GetTiming(char *str, char len) { ReFlash_RTC(); if (len < 28) { rt_kprintf("GetTiming > str so short %d\n", len); return; } sprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d.%03d", (GetDate.Year % 2000) + 2000, GetDate.Month, GetDate.Date, GetTime.Hours, GetTime.Minutes, GetTime.Seconds, 0); } /** * @brief Get the now temphumi object * * @param temp * @param humi */ void get_now_temphumi(char *temp_c , char *humi_c) { if (sensor[s_Temp].online && strstr(sensor[s_Temp].eValue, "99.99") == NULL) { sprintf(temp_c , "%s" , sensor[s_Temp].eValue); } else { sprintf(temp_c , "%s" , device_status.tempture); } if (sensor[s_Humi].online && strstr(sensor[s_Humi].eValue, "99.99") == NULL) { sprintf(humi_c , "%s" , sensor[s_Humi].eValue); } else { sprintf(humi_c , "%s" , device_status.humidity); } } extern char Demo_Mode_NEW; extern SYSCFG syscfg; extern wm_Def workmode; /** * @brief 生成新版的状态数据包 * * @return char* 直接以字符串的形式返回 */ char *makeJson_NEW(uint8_t type) { char cache[128] = {0}; // 创建根JSON对象 cJSON *root = cJSON_CreateObject(); if (!root) return NULL; // 添加字符串类型字段 cJSON_AddStringToObject(root, "DEVICE_SERIAL_NUMBER", device_status.imei); if (type == 1) { cJSON_AddStringToObject(root, "ACTION_ID", res_c.ACTION_ID); cJSON_AddStringToObject(root, "COMMAND", res_c.COMMAND); GetTiming(res_c.TIMING, sizeof(res_c.TIMING)); cJSON_AddStringToObject(root, "TIMING", res_c.TIMING); cJSON_AddStringToObject(root, "RESULT", res_c.RESULT); } cJSON_AddStringToObject(root, "SIM", device_status.iccid); // sprintf(cache, "%d", RSSI_TO_DBM(atoi(device_status.csq))); cJSON_AddStringToObject(root, "SIGNAL", device_status.csq); sprintf(cache, "%s,%s", device_status.lng, device_status.lat); cJSON_AddStringToObject(root, "LOCATION", cache); (atoi(device_status.net) == 0) ? cJSON_AddStringToObject(root, "STATUS", "STATUS_ONLINE") : cJSON_AddStringToObject(root, "STATUS", "STATUS_OFFLINE"); cJSON_AddStringToObject(root, "STATUS_DESCRIPTION", "设备运行正常"); // 需要修改 // 但是好像没有异常的时候啊 先不改 GetTiming(cache, sizeof(cache)); cJSON_AddStringToObject(root, "UPDATE_DATE", cache); // 添加数值类型字段 cJSON_AddNumberToObject(root, "VOLTAGE", atof(device_status.voltage)); cJSON_AddNumberToObject(root, "CURRENT", atof(device_status.power)); char temp_c[6] = {0}; char humi_c[6] = {0}; get_now_temphumi(temp_c , humi_c); cJSON_AddNumberToObject(root, "TEMPERATURE", atof(temp_c)); cJSON_AddNumberToObject(root, "HUMIDITY", atof(humi_c)); // cJSON_AddNumberToObject(root, "TPS", device_status.temp_status); // cJSON_AddNumberToObject(root, "RPS", device_status.rain_status); cJSON_AddNumberToObject(root, "DEMO", Demo_Mode_NEW); cJSON_AddNumberToObject(root, "REMAIN", Get_REMAIN()); sprintf(cache, "%d", syscfg.dattim); cJSON_AddStringToObject(root, "DATT", cache); sprintf(cache, "%d", syscfg.pho_inr_day); cJSON_AddStringToObject(root, "PHO_INR_DAY", cache); sprintf(cache, "%d", syscfg.pho_t_hour); cJSON_AddStringToObject(root, "PHO_T_HOUR", cache); sprintf(cache, "%d", syscfg.pho_t_min); cJSON_AddStringToObject(root, "PHO_T_MIN", cache); sprintf(cache, "%d", limit.temhumEN); cJSON_AddStringToObject(root, "TEMP_LIMIT", cache); sprintf(cache, "%d", limit.temp_up); cJSON_AddStringToObject(root, "TEMP_UP", cache); sprintf(cache, "%d", limit.temp_dw); cJSON_AddStringToObject(root, "TEMP_DOWN", cache); Get_work_mode(); sprintf(cache, "%d", workmode); cJSON_AddStringToObject(root, "CONTROL", cache); sprintf(cache, "%s-%s", VERSION_NUM, device_status.driver_4g); cJSON_AddStringToObject(root, "VERSION", cache); cJSON_AddStringToObject(root, "HISTORY_DATA", "0"); if (type == 2 || type == 3 || type == 4) { if (type != 4) { CamFree = 1; // 拍照完成 } if(type == 4) { cJSON_AddStringToObject(root, "PIC_RES", "START"); if(device_status.camsta == 0) { cJSON_AddStringToObject(root, "CAM_STA", "linkup"); } else { cJSON_AddStringToObject(root, "CAM_STA", "linkdown"); } } else { (type == 2) ? cJSON_AddStringToObject(root, "PIC_RES", "SUCC") : cJSON_AddStringToObject(root, "PIC_RES", "FAIL"); } } // 生成紧凑型JSON字符串 char *json_str = cJSON_PrintUnformatted(root); // 清理cJSON对象 cJSON_Delete(root); DTU_Write(json_str); rt_kprintf("DTU_Write > %s \n\n", json_str); if (json_str) { free(json_str); } return NULL; // 返回的字符串需由调用者释放 } /** * @brief 组包返回执行结果 * * @param result * @return char* 一定要记得释放指针 */ char *ReportRes(uint8_t result) { // 创建根JSON对象 cJSON *root = cJSON_CreateObject(); if (!root) { rt_kprintf("Failed to create JSON root\n"); return NULL; } if (strstr(res_c.COMMAND, "00") == NULL) { return NULL; } // 添加字段到根对象 cJSON_AddStringToObject(root, "DEVICE_SERIAL_NUMBER", device_status.imei); cJSON_AddStringToObject(root, "ACTION_ID", res_c.ACTION_ID); cJSON_AddStringToObject(root, "COMMAND", res_c.COMMAND); GetTiming(res_c.TIMING, sizeof(res_c.TIMING)); cJSON_AddStringToObject(root, "TIMING", res_c.TIMING); result ? cJSON_AddStringToObject(root, "RESULT", "SUCC") : cJSON_AddStringToObject(root, "RESULT", "FAIL"); // 将JSON对象转换为字符串(格式化输出) char *json_str = cJSON_PrintUnformatted(root); // 清理cJSON对象 cJSON_Delete(root); DTU_Write(json_str); rt_kprintf("DTU_Write > %s \n\n", json_str); if (json_str) { free(json_str); } return NULL; } /** * @brief 回复结果 * */ static void Report_setpara(void) { // 创建根JSON对象 cJSON *root = cJSON_CreateObject(); if (!root) { rt_kprintf("Failed to create JSON root\n"); return; } if (strstr(res_c.COMMAND, "00") == NULL) { return; } // 添加字段到根对象 cJSON_AddStringToObject(root, "DEVICE_SERIAL_NUMBER", device_status.imei); cJSON_AddStringToObject(root, "ACTION_ID", res_c.ACTION_ID); cJSON_AddStringToObject(root, "COMMAND", res_c.COMMAND); GetTiming(res_c.TIMING, sizeof(res_c.TIMING)); cJSON_AddStringToObject(root, "TIMING", res_c.TIMING); cJSON_AddStringToObject(root, "RESULT", "SUCC"); cJSON_AddNumberToObject(root, "CONTROL", limit.LuxEN); char cache_0[8] = {0}; char cache_1[8] = {0}; char cache_2[8] = {0}; sprintf(cache_0, "%d", syscfg.pho_inr_day); sprintf(cache_1, "%d", syscfg.pho_t_hour); sprintf(cache_2, "%d", syscfg.pho_t_min); cJSON_AddStringToObject(root, "PHO_INR_DAY", cache_0); cJSON_AddStringToObject(root, "PHO_T_HOUR", cache_1); cJSON_AddStringToObject(root, "PHO_T_MIN", cache_2); sprintf(cache_0, "%d", syscfg.dattim); cJSON_AddStringToObject(root, "DATT", cache_0); // 将JSON对象转换为字符串(格式化输出) char *json_str = cJSON_PrintUnformatted(root); // 清理cJSON对象 cJSON_Delete(root); DTU_Write(json_str); rt_kprintf("DTU_Write > %s \n\n", json_str); if (json_str) { free(json_str); } } /** * @brief 执行新协议下发的指令 dev_setpara * * @param cmd json字符串 */ static void exe_dev_setpara(char *cmd) { // 解析JSON根对象 cJSON *root = cJSON_Parse(cmd); if (root == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { rt_kprintf("JSON解析错误: %s\n", error_ptr); } return; } /** * @brief 应用模式 * */ cJSON *CONTROL = cJSON_GetObjectItemCaseSensitive(root, "CONTROL"); if (CONTROL != NULL) { char temp = cjson_getval(CONTROL); if (temp >= 2) { rt_kprintf("错误的CONTROL: %d\n", temp); cJSON_Delete(root); return; } else { syscfg.en_tigmode = temp; ef_set_env_blob("syscfg", (const char *)&syscfg, sizeof(syscfg)); rt_kprintf("Change Workmod %d OK\n", temp); LOG_I("CONTROL: %d\n", temp); } } /** * @brief 开始时间 * */ cJSON *START_TIME = cJSON_GetObjectItemCaseSensitive(root, "START_TIME"); if (cJSON_IsString(START_TIME) && (strlen(START_TIME->valuestring) < 3)) { char temp = cjson_getval(START_TIME); if (temp >= 0 && temp <= 24) { device_status.collecting_sh1 = temp; ef_set_env_blob("collecting_sh1", &device_status.collecting_sh1, sizeof(device_status.collecting_sh1)); LOG_I("START_TIME: %s\n", START_TIME->valuestring); } else { LOG_E("时控开始设置错误!!!"); } } /** * @brief 结束时间 * */ cJSON *END_TIME = cJSON_GetObjectItemCaseSensitive(root, "END_TIME"); if (cJSON_IsString(END_TIME) && (strlen(START_TIME->valuestring) < 3)) { char temp = cjson_getval(END_TIME); if (temp >= 0 && temp <= 24) { device_status.collecting_eh1 = temp; ef_set_env_blob("collecting_eh1", &device_status.collecting_eh1, sizeof(device_status.collecting_eh1)); LOG_I("END_TIME: %s\n", END_TIME->valuestring); } else { LOG_E("时控结束设置错误!!!"); } } /** * @brief 图片间隔 * */ cJSON *PHO_T = cJSON_GetObjectItemCaseSensitive(root, "PHO_T"); if (cJSON_IsString(PHO_T)) { char temp = cjson_getval(PHO_T); if (temp >= 5 && temp <= 240) { syscfg.photim = temp; ef_set_env_blob("syscfg", &syscfg, sizeof(syscfg)); LOG_I("照片上传间隔:%d\n", temp); } else { LOG_E("照片上传间隔设置错误!!!\n"); } } /** * @brief 数据间隔 * */ cJSON *DATT = cJSON_GetObjectItemCaseSensitive(root, "DATT"); if (cJSON_IsString(DATT) && (strlen(DATT->valuestring) < 3)) { char temp = cjson_getval(DATT); if (temp >= 10 && temp <= 120) { syscfg.dattim = temp; ef_set_env_blob("syscfg", &syscfg, sizeof(syscfg)); LOG_I("DATT: %s\n", DATT->valuestring); } else { LOG_E("数据上传间隔设置错误!!!\n"); } } cJSON_Delete(root); Report_setpara(); } /** * @brief 执行具体的指令 并回复结果 * */ static void execute_NewCmd(char *cmd) { if (atoi(res_c.COMMAND) > dev_typemax) { rt_kprintf("execute_NewCmd Err %s \n", res_c.COMMAND); return; } switch (atoi(res_c.COMMAND)) { case dev_on: Recode_e_code(e_CMD_list, dev_on, "下发指令执行"); device_status.ds = ON; ef_set_env_blob("ds", &device_status.ds, sizeof(device_status.ds)); ef_get_env_blob("ds", &device_status.ds, sizeof(device_status.ds), NULL); if (device_status.ds == ON) { rt_kprintf("dev_on execute\n"); ReportRes(1); } else { ReportRes(0); device_status.ds = ON; ef_set_env_blob("ds", &device_status.ds, sizeof(device_status.ds)); } break; case dev_off: Recode_e_code(e_CMD_list, dev_off, "下发指令执行"); device_status.ds = OFF; ef_set_env_blob("ds", &device_status.ds, sizeof(device_status.ds)); ef_get_env_blob("ds", &device_status.ds, sizeof(device_status.ds), NULL); if (device_status.ds == OFF) { rt_kprintf("dev_off execute\n"); ReportRes(1); } else { ReportRes(0); device_status.ds = OFF; ef_set_env_blob("ds", &device_status.ds, sizeof(device_status.ds)); } break; case dev_reboot: Recode_e_code(e_CMD_list, dev_reboot, "下发指令执行"); ReportRes(1); rt_kprintf("dev_reboot execute\n"); rt_hw_cpu_reset(); break; case dev_takepho: Recode_e_code(e_CMD_list, dev_takepho, "下发指令执行"); jts.takephoto_test = ON; ReportRes(1); rt_kprintf("dev_takepho execute\n"); break; case dev_sta: Recode_e_code(e_CMD_list, dev_sta, "下发指令执行"); rt_kprintf("dev_sta execute\n"); makeJson_NEW(1); break; case dev_readcfg: Recode_e_code(e_CMD_list, dev_readcfg, "下发指令执行"); // rtu进行回复 break; case dev_setcfg: Recode_e_code(e_CMD_list, dev_setcfg, "下发指令执行"); // rtu进行回复 break; case dev_setpara: Recode_e_code(e_CMD_list, dev_setpara, "下发指令执行"); exe_dev_setpara(cmd); break; default: break; } } /** * @brief 解析新协议的指令 * * @param cmd 待解析的JSON字符串 */ void prase_NewCmd(char *cmd) { // 校验输入有效性 if (cmd == NULL) { rt_kprintf("输入字符串为空\n"); return; } // 解析JSON根对象 cJSON *root = cJSON_Parse(cmd); if (root == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { rt_kprintf("JSON解析错误: %s\n", error_ptr); } return; } // 解析设备序列号 cJSON *device_sn = cJSON_GetObjectItemCaseSensitive(root, "DEVICE_SERIAL_NUMBER"); if (cJSON_IsString(device_sn) && (device_sn->valuestring != NULL)) { rt_kprintf("设备序列号: %s\n", device_sn->valuestring); if (strlen(device_sn->valuestring) != 15) { rt_kprintf("错误的序列号: %s %d\n", device_sn->valuestring, strlen(device_sn->valuestring)); cJSON_Delete(root); return; } } else { rt_kprintf("未找到DEVICE_SERIAL_NUMBER字段或类型错误\n"); cJSON_Delete(root); return; } // 解析指令ID cJSON *action_id = cJSON_GetObjectItemCaseSensitive(root, "ACTION_ID"); if (cJSON_IsString(action_id) && (action_id->valuestring != NULL)) { rt_kprintf("指令ID: %s\n", action_id->valuestring); sprintf(res_c.ACTION_ID, "%s", action_id->valuestring); } else { rt_kprintf("未找到ACTION_ID字段或类型错误\n"); } // 解析指令代码 cJSON *command = cJSON_GetObjectItemCaseSensitive(root, "COMMAND"); if (cJSON_IsString(command) && (command->valuestring != NULL)) { rt_kprintf("指令代码: %s\n", command->valuestring); if (atoi(command->valuestring) >= dev_typemax) { rt_kprintf("错误的指令代码: %s\n", command->valuestring); } else { sprintf(res_c.COMMAND, "%s", command->valuestring); } } else { rt_kprintf("未找到COMMAND字段或类型错误\n"); } // 解析执行时间 cJSON *timing = cJSON_GetObjectItemCaseSensitive(root, "TIMING"); if (cJSON_IsString(timing) && (timing->valuestring != NULL)) { rt_kprintf("执行时间: %s\n", timing->valuestring); } else { rt_kprintf("未找到TIMING字段或类型错误\n"); } // 释放JSON对象 cJSON_Delete(root); /*** 开始执行具体指令 ***/ execute_NewCmd(cmd); /*** 开始执行具体指令 ***/ }