forked from gary/ems
2
0
Fork 0
sun_ems/ems_c/mw/mw_schedule_handle.c

948 lines
38 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************************
* @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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#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(&timestamp, &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(&timestamp, &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(&timestamp, &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(&timestamp, &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_config4G相关配置
* @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;
}