ems/ems_c/logic/logic_peakvalley.c

230 lines
9.1 KiB
C
Raw Permalink Normal View History

2025-05-13 17:49:49 +08:00
/*****************************************************************************
* @copyright 2024-202, . POWER SUPPLY CO., LTD.
* @file logic_peakvalley.c
* @brief
* @author Gary
* @date 2024/09/21
* @remark
*****************************************************************************/
#include "logic_comm.h"
// 削峰填谷参数数据库配置
peakvalley_zone_tab_t zone_tab_obj = {0}; // 定义一个结构体变量
peakvalley_zone_tab_t* zone_tab = &zone_tab_obj; // 使指针指向该变量
/*****************************************************************************
* @brief
* @param[in] char* dateStr "MM-DD"
* @param[out] int* month
* @param[out] int* day
* @return 0
*****************************************************************************/
static int parseDate(const char* dateStr, int* month, int* day)
{
int result = sscanf(dateStr, "%d-%d", month, day); // 解析字符串获取月份和日期
return (result == 2) ? 0 : -1; // 返回0表示成功其他值表示失败
}
/*****************************************************************************
* @brief
* @param[in] pv_time_config_t *ret_params() u_int16_t slotTabLen
* @return
*****************************************************************************/
static float_t getPeakValleyPower(pv_time_config_t* ret_params, u_int16_t slotTabLen)
{
// 获取当前时间
time_t current_time;
struct tm* timeinfo;
time(&current_time); // 获取当前时间戳
timeinfo = localtime(&current_time); // 将时间戳转换为当地时间
uint32_t now_seconds = timeinfo->tm_hour * 3600 + timeinfo->tm_min * 60 + timeinfo->tm_sec; // 计算当前秒数
// EMS要求最小的时间间隔不得小于15分钟换算之后一天不可大于96个时段
if (slotTabLen > MAX_TIME_SEGMENTS)
{
// 检查传入的时间段表长度是否合法
KITLOG(LOG_LOGIC_EN, WARN_EN, "获取时段表的长度非法 len:%d\n", slotTabLen);
return 0; // 返回0表示未能获取有效功率
}
for (int loop = 0; loop < slotTabLen; loop++)
{
// 跳过开始时间和结束时间相同的时间段
if (ret_params[loop].startTime == ret_params[loop].endTime)
{
continue;
}
// 检查当前时间是否在时间段内
if (now_seconds >= ret_params[loop].startTime &&
now_seconds <= ret_params[loop].endTime)
{
return ret_params[loop].power; // 返回当前时间段的功率值
}
}
// 未命中任意时段则停机返回0
return 0;
}
/*****************************************************************************
* @brief
* @param[in] int dateMonth
* @param[in] int dateDay
* @param[in] const char* startDateStr
* @param[in] const char* endDateStr
* @return 1 0 -1
*****************************************************************************/
static int isDateInRange(int dateMonth, int dateDay, const char* startDateStr, const char* endDateStr)
{
if (NULL == startDateStr || NULL == endDateStr)
{
// 检查开始和结束日期指针是否为空
KITLOG(LOG_LOGIC_EN, ERROR_EN, "入参指针为空");
return -1; // 返回-1表示参数异常
}
int startMonth, startDay, endMonth, endDay;
if (0 != parseDate(startDateStr, &startMonth, &startDay))
{
// 解析开始日期字符串失败
KITLOG(LOG_LOGIC_EN, ERROR_EN, "开始日期字符串匹配失败");
return -1; // 返回-1表示参数解析失败
}
if (0 != parseDate(endDateStr, &endMonth, &endDay))
{
// 解析结束日期字符串失败
KITLOG(LOG_LOGIC_EN, ERROR_EN, "结束日期字符串匹配失败");
return -1; // 返回-1表示参数解析失败
}
// 日期保护,确保开始日期在结束日期之前
if (startMonth > endMonth || (startMonth == endMonth && startDay > endDay))
{
return 0; // 返回0表示不在范围内
}
// 判断是否在日期内
if (dateMonth > startMonth || (dateMonth == startMonth && dateDay >= startDay))
{
if (dateMonth < endMonth || (dateMonth == endMonth && dateDay <= endDay))
{
return 1; // 返回1表示在时间段内
}
}
return 0; // 返回0表示不在范围内
}
/*****************************************************************************
* @brief
* @return 0 -1
*****************************************************************************/
int logic_peakValleyUpdate()
{
UT_array* pvDateConfigs;
// 清空之前的时段表
if (zone_tab->peakItem != NULL)
{
for (int j = 0; j < zone_tab->zoneTabLen; ++j)
{
if (zone_tab->peakItem[j].timeCfgTab != NULL)
free(zone_tab->peakItem[j].timeCfgTab);
zone_tab->peakItem[j].timeCfgTab = NULL;
}
free(zone_tab->peakItem);
zone_tab->peakItem = NULL;
}
// 从数据库获取新的削峰填谷时段表数据
if (kit_get_pv_date_cfg_db_data(&pvDateConfigs) != 0)
{
KITLOG(LOG_LOGIC_EN, ERROR_EN, "获取削峰填谷时段表失败");
return 1; // 返回错误码
}
// 获取数据个数
size_t numConfigs = utarray_len(pvDateConfigs);
// 检查时段表长度是否合法
if (MAX_DATA_SEGMENTS < numConfigs || numConfigs <= 0)
{
KITLOG(LOG_LOGIC_EN, ERROR_EN, "时区表表长异常: %zu", numConfigs);
utarray_free(pvDateConfigs); // 释放资源
return 1; // 返回错误码
}
// 分配空间
zone_tab->peakItem = (pv_date_config_t*)calloc(numConfigs, sizeof(pv_date_config_t));
if (zone_tab->peakItem == NULL)
{
KITLOG(LOG_LOGIC_EN, ERROR_EN, "内存分配失败");
utarray_free(pvDateConfigs); // 释放资源
return 1; // 返回错误码
}
// 更新日期配置个数
zone_tab->zoneTabLen = numConfigs;
// 遍历并复制数据 使用 memcpy 整体复制结构体
for (int i = 0; i < numConfigs; ++i)
{
pv_date_config_t* srcConfig = (pv_date_config_t*)utarray_eltptr(pvDateConfigs, i);
pv_date_config_t* dstConfig = &zone_tab->peakItem[i]; // 直接访问数组元素
// 复制 timeCfgTab 前先分配内存
dstConfig->timeCfgTab = (pv_time_config_t*)calloc(srcConfig->timeCfgLen, sizeof(pv_time_config_t));
if (dstConfig->timeCfgTab == NULL)
{
KITLOG(LOG_LOGIC_EN, ERROR_EN, "内存分配失败");
// 释放已分配的内存
for (int j = 0; j < i; ++j)
{
free(zone_tab->peakItem[j].timeCfgTab);
}
free(zone_tab->peakItem);
utarray_free(pvDateConfigs); // 释放资源
return 1; // 返回错误码
}
memcpy(dstConfig, srcConfig, sizeof(pv_date_config_t)); // 整体复制结构体
memcpy(dstConfig->timeCfgTab, srcConfig->timeCfgTab, srcConfig->timeCfgLen * sizeof(pv_time_config_t));
}
utarray_free(pvDateConfigs); // 释放 UT_array 资源
return 0; // 返回成功
}
/*****************************************************************************
* @brief
* @param[in] bool sign
* @return 0 -1
*****************************************************************************/
int logicFun_peakValley()
{
// 获取任务参数
peakvalley_params_t* task_params = &stlogic.para_delivery.task_params.pkvly;
time_t current_time;
struct tm* timeinfo;
time(&current_time); // 获取当前时间
timeinfo = localtime(&current_time); // 转换为当地时间
// 获取日期
int month = timeinfo->tm_mon + 1; // 月份从0开始需要加1
int day = timeinfo->tm_mday; // 天
if (zone_tab == NULL)
{
// 检查时段表指针是否为空
KITLOG(LOG_LOGIC_EN, ERROR_EN, "入参指针为空");
return -1; // 返回-1表示失败
}
for (int loop = 0; loop < zone_tab->zoneTabLen; loop++)
{
// 检查当前日期是否在时段表中
if (1 == isDateInRange(month, day, (char*)zone_tab->peakItem[loop].startDate, (char*)zone_tab->peakItem[loop].endDate))
{
// 获取对应时间段的功率配置
task_params->power = getPeakValleyPower(zone_tab->peakItem[loop].timeCfgTab, zone_tab->peakItem[loop].timeCfgLen);
return 0; // 返回0表示成功
}
}
// 没找到合适的日期返回0
task_params->power = 0;
return 0;
}