/***************************************************************************** * @copyright 2024-2024, . POWER SUPPLY CO., LTD. * @file mw_schedule_save.h * @brief 定时落库功能,用于定期将RTDB数据保存到数据库。 * @author Gary * @date 2024/10/17 * @remark 初修订 *****************************************************************************/ #define _POSIX_C_SOURCE 199309L #define UPGRADE_START_MESSAGE 1 #define UPGRADE_END_MESSAGE 0 #define EMS_CONFIG_START_MESSAGE 1 #define EMS_CONFIG_END_MESSAGE 0 #define _XOPEN_SOURCE 700 #include #include #include #include #include #include #include #include #include #include #include #include "bsp_rtdb.h" #include "bsp_data_mode.h" #include "kit_db.h" #include "kit_log.h" #include "utextend.h" #include "mw_schedule_handle.h" #include "drv_4g.h" #include "drv_wifi.h" #include "bsp_ntp.h" uint32_t exeCount = 0; // 线程执行次数计数器,用于取余数 UT_array* timedDataConfigs, * faultsDataConfigs; // 时序数据配置、故障数据配置 // 时序数据的ICD结构定义 static UT_icd timed_data_storage_icd = { sizeof(timed_data_storage_t), NULL, NULL, NULL, }; // 故障数据的ICD结构定义 static UT_icd faults_data_storage_icd = { sizeof(faults_data_storage_t), NULL, NULL, NULL, }; // 功率数据的ICD结构定义 static UT_icd power_data_storage_icd = { sizeof(power_data_storage_t), NULL, NULL, NULL, }; /***************************************************************************** * @brief 将 YYYY/DD/MM HH:MM:SS 格式的字符串转换为 timeval 结构体 * @param[in] timeString: YYYY/DD/MM HH:MM:SS 格式的时间字符串 * @param[out] tv: 转换后的 timeval 结构体指针 * @return 0: 成功;1: 失败 (无效的时间字符串格式或转换错误) *****************************************************************************/ static int stringToTimeval(const char *timeString, struct timeval *tv) { struct tm tm = {0}; // 初始化 tm 结构体 char *strptime_result; time_t t; // 检查字符串长度 if (strlen(timeString) != 19) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:时间字符串长度错误: %s\n", timeString); return 1; } // 使用 strptime 解析时间字符串,注意格式字符串要与 timeString 格式完全匹配 strptime_result = strptime(timeString, "%Y/%m/%d %H:%M:%S", &tm); // 修改为 %m/%d if (strptime_result == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:strptime 解析时间字符串失败: %s\n", timeString); return 1; } // 将 struct tm 转换为 time_t t = mktime(&tm); if (t == -1) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:mktime 转换失败: %s\n", timeString); return 1; } tv->tv_sec = t; tv->tv_usec = 0; return 0; } /***************************************************************************** * @brief 获取RTDB参数 * @param[in] devType:设备类型 * @param[in] pointId:点号 * @param[in] value:值数组指针 * @param[in] dataType:数组类型 * @return 无 *****************************************************************************/ static void logic_getValue(dev_type_e devType, uint16_t pointId, void* value, data_type_e dataType) { switch (dataType) { case Uint8: { // 对于 uint8_t 类型 uint8_t* uint8Value = (uint8_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { uint8Value[i] = (uint8_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Int8: { // 对于 int8_t 类型 int8_t* int8Value = (int8_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { int8Value[i] = (int8_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Uint16: { // 对于 uint16_t 类型 uint16_t* uint16Value = (uint16_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { uint16Value[i] = (uint16_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Int16: { // 对于 int16_t 类型 int16_t* int16Value = (int16_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { int16Value[i] = (int16_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Uint32: { // 对于 uint32_t 类型 uint32_t* uint32Value = (uint32_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { uint32Value[i] = (uint32_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Int32: { // 对于 int32_t 类型 int32_t* int32Value = (int32_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { int32Value[i] = (int32_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Uint64: { // 对于 uint64_t 类型 uint64_t* uint64Value = (uint64_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { uint64Value[i] = (uint64_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Int64: { // 对于 int64_t 类型 int64_t* int64Value = (int64_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { int64Value[i] = (int64_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Float32: { // 对于 float_t (Float32) 类型 float_t* floatValue = (float_t*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { floatValue[i] = (float_t)getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } case Float64: { // 对于 double (Float64) 类型 double* doubleValue = (double*)value; for (uint16_t i = 0; i < gStDevTypeNum[devType]; i++) { doubleValue[i] = getRtdbPointValue(Rtdb_ShMem, devType, i, pointId); } break; } default: // 不支持的类型 return; } return; } /***************************************************************************** * @brief 封装的删除功率数据函数 * @param[in] timestamp: 删除之前数据时间戳 *****************************************************************************/ static void deletePowerData(time_t timestamp) { struct tm tm_time; localtime_r(×tamp, &tm_time); char time_str[32]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time); // 调用删除数据库函数 int ret = kit_del_power_data_by_date(time_str); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str); } } /***************************************************************************** * @brief 封装的删除时序数据函数 * @param[in] interval: 存储间隔 * @param[in] timestamp: 删除之前数据时间戳 *****************************************************************************/ static void deleteTimedData(int interval, time_t timestamp) { struct tm tm_time; localtime_r(×tamp, &tm_time); char time_str[32]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time); // 调用删除数据库函数 int ret = kit_del_timed_data_by_date(interval, time_str); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, interval: %d, date: %s", interval, time_str); } } /***************************************************************************** * @brief 封装的删除故障数据函数 * @param[in] interval: 存储间隔 * @param[in] timestamp: 删除之前数据时间戳 *****************************************************************************/ static void deleteFaultsData(time_t timestamp) { struct tm tm_time; localtime_r(×tamp, &tm_time); char time_str[32]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time); // 调用删除数据库函数 int ret = kit_del_faults_data_by_date(time_str); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str); } } /***************************************************************************** * @brief 封装的删除断点数据函数 * @param[in] timestamp: 删除之前数据时间戳 *****************************************************************************/ static void deleteBreakData(time_t timestamp) { struct tm tm_time; localtime_r(×tamp, &tm_time); char time_str[32]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time); // 调用删除数据库函数 int ret = kit_del_break_data_by_date(time_str); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "数据删除失败, date: %s", time_str); } } /***************************************************************************** * @brief 每天定时删除业务数据间隔 *****************************************************************************/ static void delDbBusDataInterval() { time_t now; time(&now); struct tm tm_time; localtime_r(&now, &tm_time); tm_time.tm_hour += 8; // 加8个小时,考虑时区 time_t oneDayAgo = now - 24 * 60 * 60; // 1天前 time_t oneWeekAgo = now - 7 * 24 * 60 * 60; // 7天前 time_t twoWeekAgo = now - 14 * 24 * 60 * 60; // 14天前 time_t threeWeekAgo = now - 21 * 24 * 60 * 60; // 21天前 time_t oneMonthAgo = now - 30 * 24 * 60 * 60; // 30天前 time_t twoMonthAgo = now - 2 * 30 * 24 * 60 * 60; // 60天前 time_t threeMonthAgo = now - 3 * 30 * 24 * 60 * 60; // 90天前 time_t fiveMonthAgo = now - 5 * 30 * 24 * 60 * 60; // 150天前 time_t sixMonthsAgo = now - 6 * 30 * 24 * 60 * 60; // 180天前 // 删除功率数据 deletePowerData(oneDayAgo); // 删除断点续传数据 deleteBreakData(oneWeekAgo); // 删除时序数据 deleteTimedData(500, oneDayAgo); deleteTimedData(1000, oneWeekAgo); deleteTimedData(2000, twoWeekAgo); deleteTimedData(3000, threeWeekAgo); deleteTimedData(4000, threeWeekAgo); deleteTimedData(5000, oneMonthAgo); deleteTimedData(6000, oneMonthAgo); deleteTimedData(7000, oneMonthAgo); deleteTimedData(8000, oneMonthAgo); deleteTimedData(9000, oneMonthAgo); deleteTimedData(10000, twoMonthAgo); deleteTimedData(15000, threeMonthAgo); deleteTimedData(20000, fiveMonthAgo); deleteTimedData(30000, sixMonthsAgo); // 删除故障数据 deleteFaultsData(sixMonthsAgo); } /***************************************************************************** * @brief 定时将RTDB数据保存到数据库 * @param[in] storageIntervalType:存储间隔类型 *****************************************************************************/ static void saveRTDBToDbInterval(storage_interval_type_e storageIntervalType) { UT_array* timedDatas = NULL; // 为时序数据动态数组分配空间 utarray_new(timedDatas, &timed_data_storage_icd); for (int i = 0; i < utarray_len(timedDataConfigs); ++i) { timed_data_config_t* p_config = (timed_data_config_t*)utarray_eltptr(timedDataConfigs, i); if (p_config != NULL && p_config->storageInterval == storageIntervalType) { timed_data_storage_t data = { 0 }; data.devType = p_config->devType; // 设备种类 data.devDbId = p_config->devDbId; // 设备数据库Id data.storageInterval = p_config->storageInterval; // 存储间隔 data.pointDbId = p_config->pointDbId; // 点位Id data.timedValue = getRtdbPointValue(Rtdb_ShMem, data.devType, p_config->devId - 1, p_config->pointId); // 从实时库获取时序数据 // if (data.timedValue == 0 || data.timedValue == 128) // { // KITLOG(LOG_WM_EN, ERROR_EN, "getRtdbPointValue 失败"); // continue; // } utarray_push_back(timedDatas, &data); } } // 插入时序数据 if (utarray_len(timedDatas) > 0 && kit_insert_timed_data(timedDatas) != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "kit_insert_timed_data 失败"); } } /***************************************************************************** * @brief 定时将故障数据保存到数据库 *****************************************************************************/ static void saveFaultsDataInterval() { UT_array* faultsDatas = NULL; // 为故障数据动态数组分配空间 utarray_new(faultsDatas, &faults_data_storage_icd); for (int i = 0; i < utarray_len(faultsDataConfigs); ++i) { faults_data_config_t* p_config = (faults_data_config_t*)utarray_eltptr(faultsDataConfigs, i); if (p_config != NULL) { faults_data_storage_t data = { 0 }; data.faultsValue = getRtdbPointValue(Rtdb_ShMem, data.devType, p_config->devId - 1, p_config->pointId); // 从实时库获取时序数据 if (data.faultsValue != 1) // 不是故障时,直接跳过 { continue; } data.devType = p_config->devType; // 设备种类 data.devDbId = p_config->devDbId; // 设备数据库Id data.pointDbId = p_config->pointDbId; // 点位Id utarray_push_back(faultsDatas, &data); } } // 插入时序数据 if (utarray_len(faultsDatas) > 0 && kit_insert_faults_data(faultsDatas) != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "kit_insert_faults_data 失败"); } } /***************************************************************************** * @brief 每分钟定时保存功率数据 *****************************************************************************/ static void savePowerDataInterval() { // 定义存储功率数据的变量 float_t pccTotalActivePwr[MAX_NUM_CABINT], pccTotalReactivePwr[MAX_NUM_CABINT], pccTotalApparentPwr[MAX_NUM_CABINT], pccTotalPwrFactor[MAX_NUM_CABINT], bsTotalActivePwr[MAX_NUM_CABINT], bsTotalReactivePwr[MAX_NUM_CABINT], bsTotalApparentPwr[MAX_NUM_CABINT], bsTotalPwrFactor[MAX_NUM_CABINT], pcsTotalActivePwr[MAX_NUM_CABINT], pcsTotalReactivePwr[MAX_NUM_CABINT], pcsTotalApparentPwr[MAX_NUM_CABINT], pcsTotalPwrFactor[MAX_NUM_CABINT]; UT_array* powerDatas; utarray_new(powerDatas, &power_data_storage_icd); // 初始化powerDatas // pcc电表 logic_getValue(kDev_Type_Pccmeter, kPCC_TotalActivePwr, pccTotalActivePwr, Float32); // pcc电表总有功功率 logic_getValue(kDev_Type_Pccmeter, kPCC_TotalReactivePwr, pccTotalReactivePwr, Float32); // pcc电表总无功功率 logic_getValue(kDev_Type_Pccmeter, kPCC_TotalApparentPwr, pccTotalApparentPwr, Float32); // pcc电表总视在功率 logic_getValue(kDev_Type_Pccmeter, kPCC_TotalPwrFactor, pccTotalPwrFactor, Float32); // pcc电表总功率因数 // bs储能表 logic_getValue(kDev_Type_Bsmeter, kBs_TotalActivePwr, bsTotalActivePwr, Float32); // bs储能表总有功功率 logic_getValue(kDev_Type_Bsmeter, kBs_TotalReactivePwr, bsTotalReactivePwr, Float32); // bs储能表总无功功率 logic_getValue(kDev_Type_Bsmeter, kBs_TotalApparentPwr, bsTotalApparentPwr, Float32); // bs储能表总视在功率 logic_getValue(kDev_Type_Bsmeter, kBs_TotalPwrFactor, bsTotalPwrFactor, Float32); // bs储能表总功率因数 // pcs电表 logic_getValue(kDev_Type_PCS, kPcs_TotalActivePwr, pcsTotalActivePwr, Float32); // PCS总有功功率 logic_getValue(kDev_Type_PCS, kPcs_TotalReactivePwr, pcsTotalReactivePwr, Float32); // PCS总无功功率 logic_getValue(kDev_Type_PCS, kPcs_TotalApparentPwr, pcsTotalApparentPwr, Float32); // PCS总视在功率 logic_getValue(kDev_Type_PCS, kPcs_TotalPwrFactor, pcsTotalPwrFactor, Float32); // PCS总功率因数 // 遍历bs储能表 for (int i = 0; i < gStDevTypeNum[kDev_Type_Pccmeter]; ++i) { // pcc电表总有功功率 power_data_storage_t pccTotalActivePwrData = { 0 }; pccTotalActivePwrData.devType = kDev_Type_Pccmeter; // 设备种类 pccTotalActivePwrData.devId = i; // 设备编号 pccTotalActivePwrData.pointId = kPCC_TotalActivePwr; // 点位编号 pccTotalActivePwrData.value = pccTotalActivePwr[i]; // 值 utarray_push_back(powerDatas, &pccTotalActivePwrData); // pcc电表总无功功率 power_data_storage_t pccTotalReactivePwrData = { 0 }; pccTotalReactivePwrData.devType = kDev_Type_Pccmeter; // 设备种类 pccTotalReactivePwrData.devId = i; // 设备编号 pccTotalReactivePwrData.pointId = kPCC_TotalReactivePwr; // 点位编号 pccTotalReactivePwrData.value = pccTotalReactivePwr[i]; // 值 utarray_push_back(powerDatas, &pccTotalReactivePwrData); // pcc电表总视在功率 power_data_storage_t pccTotalApparentPwrData = { 0 }; pccTotalApparentPwrData.devType = kDev_Type_Pccmeter; // 设备种类 pccTotalApparentPwrData.devId = i; // 设备编号 pccTotalApparentPwrData.pointId = kPCC_TotalApparentPwr; // 点位编号 pccTotalApparentPwrData.value = pccTotalApparentPwr[i]; // 值 utarray_push_back(powerDatas, &pccTotalApparentPwrData); // pcc电表总功率因数 power_data_storage_t pccTotalPwrFactorData = { 0 }; pccTotalPwrFactorData.devType = kDev_Type_Pccmeter; // 设备种类 pccTotalPwrFactorData.devId = i; // 设备编号 pccTotalPwrFactorData.pointId = kPCC_TotalPwrFactor; // 点位编号 pccTotalPwrFactorData.value = pccTotalPwrFactor[i]; // 值 utarray_push_back(powerDatas, &pccTotalPwrFactorData); } // 遍历bs储能表 for (int i = 0; i < gStDevTypeNum[kDev_Type_Bsmeter]; ++i) { // bs储能表总有功功率 power_data_storage_t bsTotalActivePwrData = { 0 }; bsTotalActivePwrData.devType = kDev_Type_Bsmeter; // 设备种类 bsTotalActivePwrData.devId = i; // 设备编号 bsTotalActivePwrData.pointId = kBs_TotalActivePwr; // 点位编号 bsTotalActivePwrData.value = bsTotalActivePwr[i]; // 值 utarray_push_back(powerDatas, &bsTotalActivePwrData); // bs储能表总无功功率 power_data_storage_t bsTotalReactivePwrData = { 0 }; bsTotalReactivePwrData.devType = kDev_Type_Bsmeter; // 设备种类 bsTotalReactivePwrData.devId = i; // 设备编号 bsTotalReactivePwrData.pointId = kBs_TotalReactivePwr; // 点位编号 bsTotalReactivePwrData.value = bsTotalReactivePwr[i]; // 值 utarray_push_back(powerDatas, &bsTotalReactivePwrData); // bs储能表总视在功率 power_data_storage_t bsTotalApparentPwrData = { 0 }; bsTotalApparentPwrData.devType = kDev_Type_Bsmeter; // 设备种类 bsTotalApparentPwrData.devId = i; // 设备编号 bsTotalApparentPwrData.pointId = kBs_TotalApparentPwr; // 点位编号 bsTotalApparentPwrData.value = bsTotalApparentPwr[i]; // 值 utarray_push_back(powerDatas, &bsTotalApparentPwrData); // bs储能表总功率因数 power_data_storage_t bsTotalPwrFactorData = { 0 }; bsTotalPwrFactorData.devType = kDev_Type_Bsmeter; // 设备种类 bsTotalPwrFactorData.devId = i; // 设备编号 bsTotalPwrFactorData.pointId = kBs_TotalPwrFactor; // 点位编号 bsTotalPwrFactorData.value = bsTotalPwrFactor[i]; // 值 utarray_push_back(powerDatas, &bsTotalPwrFactorData); } // 遍历pcs for (int i = 0; i < gStDevTypeNum[kDev_Type_PCS]; ++i) { // PCS总有功功率 power_data_storage_t pcsTotalActivePwrData = { 0 }; pcsTotalActivePwrData.devType = kDev_Type_PCS; // 设备种类 pcsTotalActivePwrData.devId = i; // 设备编号 pcsTotalActivePwrData.pointId = kPcs_TotalActivePwr; // 点位编号 pcsTotalActivePwrData.value = pcsTotalActivePwr[i]; // 值 utarray_push_back(powerDatas, &pcsTotalActivePwrData); // PCS总无功功率 power_data_storage_t pcsTotalReactivePwrData = { 0 }; pcsTotalReactivePwrData.devType = kDev_Type_PCS; // 设备种类 pcsTotalReactivePwrData.devId = i; // 设备编号 pcsTotalReactivePwrData.pointId = kPcs_TotalReactivePwr; // 点位编号 pcsTotalReactivePwrData.value = pcsTotalReactivePwr[i]; // 值 utarray_push_back(powerDatas, &pcsTotalReactivePwrData); // PCS总视在功率 power_data_storage_t pcsTotalApparentPwrData = { 0 }; pcsTotalApparentPwrData.devType = kDev_Type_PCS; // 设备种类 pcsTotalApparentPwrData.devId = i; // 设备编号 pcsTotalApparentPwrData.pointId = kPcs_TotalApparentPwr; // 点位编号 pcsTotalApparentPwrData.value = pcsTotalApparentPwr[i]; // 值 utarray_push_back(powerDatas, &pcsTotalApparentPwrData); // PCS总功率因数 power_data_storage_t pcsTotalPwrFactorData = { 0 }; pcsTotalPwrFactorData.devType = kDev_Type_PCS; // 设备种类 pcsTotalPwrFactorData.devId = i; // 设备编号 pcsTotalPwrFactorData.pointId = kPcs_TotalPwrFactor; // 点位编号 pcsTotalPwrFactorData.value = pcsTotalPwrFactor[i]; // 值 utarray_push_back(powerDatas, &pcsTotalPwrFactorData); } // 调用保存功率数据库函数 int ret = kit_insert_power_data(powerDatas); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "批量插入插入功率数据失败"); } } /********************************************************************* * @brief 初始化系统4G配置 * @param[in] fourthg_dev_config:4G相关配置 * @return 0-成功 1-失败 *********************************************************************/ static int sys4GInitHandle(ems_dev_config_t *fourthg_dev_config) { int ret = 0; drv_4g_t fourthgInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)fourthg_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "enable"); fourthgInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 在使能关闭时,直接返回 if (fourthgInfo.enable == 0) { return ret; } item = cJSON_GetObjectItem(json_obj, "cmdContent"); strncpy((char *)fourthgInfo.cmdContent, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_CMD_4G_LEN); fourthgInfo.cmdContent[MAX_CMD_4G_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 cJSON_Delete(json_obj); // 释放JSON对象 ret = drvOpen4G(&fourthgInfo); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); return 1; } return ret; } /********************************************************************* * @brief 初始化系统Wifi配置 * @param[in] wifi_dev_config: wifi配置信息 * @return 0-成功 1-失败 *********************************************************************/ static int sysWifiInitHandle(ems_dev_config_t *wifi_dev_config) { int ret = 0; drv_wifi_t wifiInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)wifi_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "enable"); wifiInfo.enable = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 在使能关闭时,直接返回 if (wifiInfo.enable == 0) { return ret; } item = cJSON_GetObjectItem(json_obj, "wifiName"); strncpy((char *)wifiInfo.wifiName, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_NAME_LEN); wifiInfo.wifiName[MAX_WIFI_NAME_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 item = cJSON_GetObjectItem(json_obj, "wifiPassword"); strncpy((char *)wifiInfo.wifiPassword, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_WIFI_PASS_LEN); wifiInfo.wifiPassword[MAX_WIFI_PASS_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 cJSON_Delete(json_obj); // 释放JSON对象 ret = drvOpenWifi(&wifiInfo); if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); return 1; } return ret; } /********************************************************************* * @brief EMS时间处理初始化函数,根据配置信息设置系统时间(NTP或手动) * @param[in] rtc_dev_config: 设备配置信息 (包含NTP和手动时间设置参数,通常为JSON格式) * @return 0: 成功;1: 失败 (内存分配失败,JSON解析失败,NTP同步失败,或设置系统时间失败) *********************************************************************/ static int systimeInitHandle(ems_dev_config_t *rtc_dev_config) { int ret = 0; ems_dev_rtc_config_t rtcInfo = {0}; // 使用局部变量,函数结束时自动释放内存 cJSON *json_obj = cJSON_Parse((const char *)rtc_dev_config->content); // 解析JSON配置字符串 if (json_obj == NULL) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:解析JSON配置失败: %s\n", cJSON_GetErrorPtr()); return 1; } cJSON *item; // 安全地获取JSON对象中的各个字段 item = cJSON_GetObjectItem(json_obj, "isNtp"); rtcInfo.isNtp = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; // 判断是否使用 NTP 自动对时 if (rtcInfo.isNtp) { item = cJSON_GetObjectItem(json_obj, "port"); rtcInfo.port = (item != NULL && cJSON_IsNumber(item)) ? item->valueint : 0; item = cJSON_GetObjectItem(json_obj, "address"); strncpy((char *)rtcInfo.address, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", MAX_ADDR_LEN); rtcInfo.address[MAX_ADDR_LEN - 1] = '\0'; // 确保字符串以'\0'结尾 ret = sync_ntp_timestamp((char *)rtcInfo.address, rtcInfo.port,(char *)AdvancedSettingTable[kLinux_Password].value); // 调用NTP对时函数 if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:NTP同步失败: %s\n", strerror(errno)); } } else { item = cJSON_GetObjectItem(json_obj, "manualTime"); strncpy((char *)rtcInfo.manualTime, (item != NULL && cJSON_IsString(item)) ? item->valuestring : "", sizeof(rtcInfo.manualTime)); rtcInfo.manualTime[sizeof(rtcInfo.manualTime) - 1] = '\0'; // 确保字符串以'\0'结尾 struct timeval tv; if (stringToTimeval((const char *)rtcInfo.manualTime, &tv) != 0) { return 1; // stringToTimeval函数已经打印了错误信息 } time_t seconds = tv.tv_sec; ret = setSysTime(seconds, (char *)AdvancedSettingTable[kLinux_Password].value); // 使用bsp_rtc.c中的setSysTime函数设置系统时间 if (ret != 0) { KITLOG(LOG_APP_EN, ERROR_EN, "错误:设置系统时间失败\n"); return 1; } } cJSON_Delete(json_obj); // 释放JSON对象 return ret; } /********************************************************************* * @brief 修改EMS的基础设置到系统 * @param[in] void * @return 0-成功 1-失败 *********************************************************************/ static void changeEmsConfig(void) { // EMS修改标志位被修改 if(EMS_CONFIG_START_MESSAGE == readWebSign(kSign_ShMem, kSign_EmsConfig)) { UT_array *emsDevConfigs = {0}; int ret = 0; if (0 != kit_get_config_db_data(&emsDevConfigs)) { return; } utarray_foreach(emsDevConfigs, ems_dev_config_t *, p_emsDevConfig) { switch (p_emsDevConfig->type) { case kEms_Config_Uart: // 系统串口不需要初始化 break; case kEms_Config_Net: // // 初始化系统的IP、MAC地址、网关等配置 // ret = netInitHandble(p_emsDevConfig); break; case kEms_Config_DI: break; case kEms_Config_DO: break; case kEms_Config_Rtc: // 初始化系统时间将rtc时钟同步到linux系统 ret = systimeInitHandle(p_emsDevConfig); break; case kEms_Config_Wifi: ret = sysWifiInitHandle(p_emsDevConfig); break; case kEms_Config_4G: ret = sys4GInitHandle(p_emsDevConfig); break; default: printf("Unknown EMS device config type: %d\n", p_emsDevConfig->type); ret = 1; break; } if (ret != 0) { // 初始化失败,释放资源并返回错误 utarray_free(emsDevConfigs); emsDevConfigs = NULL; return; } } // 释放数组内存 utarray_free(emsDevConfigs); emsDevConfigs = NULL; return; } } /***************************************************************************** * @brief 安装升级包 *****************************************************************************/ static void installUpgradePackage() { // 读取升级是否需要标志位 if(UPGRADE_START_MESSAGE == readWebSign(kSign_ShMem, kSign_SysUpdate)) { upgrade_record_t p_upgradeRecord = {0}; if(0 == kit_get_upgrade_record(&p_upgradeRecord)) { char buffer[1000]; // 接收执行返回值 char command[MAX_UPGRADE_PATH_LEN + 8]; // 命令字符串 snprintf(command, MAX_UPGRADE_PATH_LEN + 8, "dpkg -i %s", p_upgradeRecord.path); // 使用 kit_popen_exec 执行"dpkg i " if (kit_popen_exec(command, buffer, sizeof(buffer)) != 0) { snprintf((char *)p_upgradeRecord.errMsg, MAX_UPGRADE_ERR_MSG_LEN, "%s", buffer); p_upgradeRecord.status = kUpgrade_Err; // 升级失败 kit_update_upgrade_record(&p_upgradeRecord); // 更新升级记录 KITLOG(LOG_DRIVER_EN, ERROR_EN, "EMS升级失败\n"); return; } // 设置EMS自启动 if (kit_popen_exec("systemctl enable company-ems-start", buffer, sizeof(buffer)) != 0) { KITLOG(LOG_DRIVER_EN, ERROR_EN, "EMS自启动设置失败\n"); return; } // LINUX重启 if (kit_popen_exec("reboot", buffer, sizeof(buffer)) != 0) { KITLOG(LOG_DRIVER_EN, ERROR_EN, "重启失败\n"); return; } p_upgradeRecord.status = kUpgrade_Succ; // 升级成功 kit_update_upgrade_record(&p_upgradeRecord); // 更新升级记录 // 写入升级结束标志位 writeWebSign(kSign_ShMem, kSign_SysUpdate, UPGRADE_END_MESSAGE); } } } /***************************************************************************** * @brief 每1秒钟执行一次的任务 * @param[in] arg:线程执行参数 *****************************************************************************/ static void* oneSecondTaskHandle(void* arg) { struct timespec start, end; struct timespec interval = { .tv_sec = 1, .tv_nsec = 0 }; struct timespec tv; while (1) { clock_gettime(CLOCK_MONOTONIC, &start); if (exeCount % 1 == 0) // 1秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_1s); // 定时落库 saveFaultsDataInterval(); // 保存故障 changeEmsConfig(); // 更新EMS基础配置 installUpgradePackage(); // 安装升级包 } if (exeCount % 2 == 0) // 2秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_2s); } if (exeCount % 3 == 0) // 3秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_3s); } if (exeCount % 4 == 0) // 4秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_4s); } if (exeCount % 5 == 0) // 5秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_5s); } if (exeCount % 6 == 0) // 6秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_6s); } if (exeCount % 7 == 0) // 7秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_7s); } if (exeCount % 8 == 0) // 8秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_8s); } if (exeCount % 9 == 0) // 9秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_9s); } if (exeCount % 10 == 0) // 10秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_10s); } if (exeCount % 15 == 0) // 15秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_15s); } if (exeCount % 20 == 0) // 20秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_20s); } if (exeCount % 30 == 0) // 30秒执行一次 { saveRTDBToDbInterval(kStorage_Interval_30s); } if (exeCount % 60 == 0) // 60秒执行一次 { savePowerDataInterval(); // 每分钟定时保存功率数据 } if (exeCount % 86400 == 0) // 86400秒执行一次(一天) { delDbBusDataInterval(); // 每天定时删除业务数据间隔 } // 获取循环结束时间并计算执行时间 clock_gettime(CLOCK_MONOTONIC, &end); long elapsed_ns = (end.tv_sec - start.tv_sec) * 1e9 + (end.tv_nsec - start.tv_nsec); long sleep_ns = (interval.tv_sec * 1e9 + interval.tv_nsec) - elapsed_ns; // 如果任务执行时间小于1秒,休眠剩余时间 if (sleep_ns > 0) { tv.tv_sec = sleep_ns / 1e9; tv.tv_nsec = sleep_ns % (long)1e9; nanosleep(&tv, NULL); } // 执行次数 exeCount = (exeCount + 1) % MAX_EXE_COUNT; } return NULL; } /***************************************************************************** * @brief 创建定时存储任务 * @return 0-成功 1-失败 *****************************************************************************/ void creatScheduledStorageTask() { int ret = 0; pthread_t tid_one_sec; // 定义线程描述符 // 从数据库里查询到所有时序数据存储的配置 ret = kit_get_tdata_config(&timedDataConfigs); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "获取时序数据存储的配置失败!"); return (void)1; } // 从数据库获取故障点位配置 ret = kit_get_faults_config(&faultsDataConfigs); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "获取故障点位配置失败!"); return (void)1; } // 创建每1秒钟执行一次的线程 ret = pthread_create(&tid_one_sec, NULL, oneSecondTaskHandle, NULL); if (ret != 0) { KITLOG(LOG_WM_EN, ERROR_EN, "创建每1秒钟执行一次的线程失败"); return (void)1; // 创建失败,返回错误 } return (void)0; }