/* * 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 "Work_TN.h" #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); } extern SYSCFG syscfg; extern wm_Def workmode; extern char Demo_Mode_NEW; /** * @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)); cJSON_AddNumberToObject(root, "TEMPERATURE", atof(sensor[s_Temp].eValue)); cJSON_AddNumberToObject(root, "HUMIDITY", atof(sensor[s_Humi].eValue)); 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, "RAY_CNT", RayTigCnt); sprintf(cache, "%d", syscfg.photim); cJSON_AddStringToObject(root, "PHO_T", cache); sprintf(cache, "%d", syscfg.dattim); cJSON_AddStringToObject(root, "DATT", cache); sprintf(cache, "%d", device_status.collecting_sh1); cJSON_AddStringToObject(root, "START_TIME", cache); sprintf(cache, "%d", device_status.collecting_eh1); cJSON_AddStringToObject(root, "END_TIME", 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) { RayTigCnt = 0; // 清空计数 RTC_SET_TigVal(0); // 清空计数 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"); } } /** * @brief 250818 新增了土壤要素 * */ char sensor_status = sensor[s_Stemp1].online + sensor[s_Shumi1].online + sensor[s_Stemp2].online + sensor[s_Shumi2].online + sensor[s_Stemp3].online + sensor[s_Shumi3].online + sensor[s_S_PH].online + sensor[s_S_sail].online + sensor[s_SWP].online; if (type == 0 && sensor_status > 0) { // 添加ENV数组 cJSON *env_array = cJSON_CreateArray(); if (env_array) { // 土壤温度1 cJSON *item1 = cJSON_CreateArray(); cJSON_AddItemToArray(item1, cJSON_CreateString(sensor[s_Stemp1].eName)); cJSON_AddItemToArray(item1, cJSON_CreateString(sensor[s_Stemp1].eValue)); cJSON_AddItemToArray(item1, cJSON_CreateString("℃")); cJSON_AddItemToArray(env_array, item1); // 土壤湿度1 cJSON *item2 = cJSON_CreateArray(); cJSON_AddItemToArray(item2, cJSON_CreateString(sensor[s_Shumi1].eName)); cJSON_AddItemToArray(item2, cJSON_CreateString(sensor[s_Shumi1].eValue)); cJSON_AddItemToArray(item2, cJSON_CreateString("%")); cJSON_AddItemToArray(env_array, item2); // 土壤温度2 cJSON *item3 = cJSON_CreateArray(); cJSON_AddItemToArray(item3, cJSON_CreateString(sensor[s_Stemp2].eName)); cJSON_AddItemToArray(item3, cJSON_CreateString(sensor[s_Stemp2].eValue)); cJSON_AddItemToArray(item3, cJSON_CreateString("℃")); cJSON_AddItemToArray(env_array, item3); // 土壤湿度2 cJSON *item4 = cJSON_CreateArray(); cJSON_AddItemToArray(item4, cJSON_CreateString(sensor[s_Shumi2].eName)); cJSON_AddItemToArray(item4, cJSON_CreateString(sensor[s_Shumi2].eValue)); cJSON_AddItemToArray(item4, cJSON_CreateString("%")); cJSON_AddItemToArray(env_array, item4); // 土壤温度3 cJSON *item5 = cJSON_CreateArray(); cJSON_AddItemToArray(item5, cJSON_CreateString(sensor[s_Stemp3].eName)); cJSON_AddItemToArray(item5, cJSON_CreateString(sensor[s_Stemp3].eValue)); cJSON_AddItemToArray(item5, cJSON_CreateString("℃")); cJSON_AddItemToArray(env_array, item5); // 土壤湿度3 cJSON *item6 = cJSON_CreateArray(); cJSON_AddItemToArray(item6, cJSON_CreateString(sensor[s_Shumi3].eName)); cJSON_AddItemToArray(item6, cJSON_CreateString(sensor[s_Shumi3].eValue)); cJSON_AddItemToArray(item6, cJSON_CreateString("%")); cJSON_AddItemToArray(env_array, item6); // 土壤PH值 cJSON *item7 = cJSON_CreateArray(); cJSON_AddItemToArray(item7, cJSON_CreateString(sensor[s_S_PH].eName)); cJSON_AddItemToArray(item7, cJSON_CreateString(sensor[s_S_PH].eValue)); cJSON_AddItemToArray(item7, cJSON_CreateString("PH")); cJSON_AddItemToArray(env_array, item7); // 盐度 cJSON *item8 = cJSON_CreateArray(); cJSON_AddItemToArray(item8, cJSON_CreateString(sensor[s_S_sail].eName)); cJSON_AddItemToArray(item8, cJSON_CreateString(sensor[s_S_sail].eValue)); cJSON_AddItemToArray(item8, cJSON_CreateString("mg/L")); cJSON_AddItemToArray(env_array, item8); // SWP cJSON *item9 = cJSON_CreateArray(); cJSON_AddItemToArray(item9, cJSON_CreateString(sensor[s_SWP].eName)); cJSON_AddItemToArray(item9, cJSON_CreateString(sensor[s_SWP].eValue)); cJSON_AddItemToArray(item9, cJSON_CreateString("KPA")); cJSON_AddItemToArray(env_array, item9); cJSON_AddItemToObject(root, "ENV", env_array); } } /** * @brief 250818 新增了土壤要素 * */ // 生成紧凑型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}; sprintf(cache_0, "%d", device_status.collecting_sh1); sprintf(cache_1, "%d", device_status.collecting_eh1); cJSON_AddStringToObject(root, "START_TIME", cache_0); cJSON_AddStringToObject(root, "END_TIME", cache_1); sprintf(cache_0, "%d", syscfg.photim); sprintf(cache_1, "%d", syscfg.dattim); cJSON_AddStringToObject(root, "PHO_T", cache_0); cJSON_AddStringToObject(root, "DATT", cache_1); // 将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 <= 60*8) { 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 >= 5 && temp <= 60*8) { 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); /*** 开始执行具体指令 ***/ }