Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
+340
View File
@@ -0,0 +1,340 @@
#include "meter_calculate/calculate_task.h"
#include "app_init/app_init.h"
#include "app_init/task_lock.h"
#include "mylog/mylog.h"
#include "wdt_task/wdt_task.h"
#include "publicdata/publicdata.h"
#include "flash_file_mgr/meter_calculate_flash_impl.h"
#include "flash_file_mgr/unsettled_order_mng.h"
#include "app_rtc/app_rtc.h"
#include <string.h>
#define METERFEE_TASK_ID (TASK_ID_Meterfee)
#define METERFEE_SLEEP_TIME_MS() (MY_GET_SLEEP_TIME(METERFEE_TASK_ID))
#define METERFEE_LOCK_INIT() (u8_task_lock_ctrl(METERFEE_TASK_ID, TASK_LOCK_OP_INIT))
#define METERFEE_LOCK_TAKE() (u8_task_lock_ctrl(METERFEE_TASK_ID, TASK_LOCK_OP_TAKE))
#define METERFEE_LOCK_GIVE() (u8_task_lock_ctrl(METERFEE_TASK_ID, TASK_LOCK_OP_GIVE))
#define METERFEE_FEED_DOG() (v_wdt_setFlag(METERFEE_TASK_ID))
#define METERFEE_LOG(fmt, ...) MYLOG_MSG(METERFEE_TASK_ID, (fmt), ##__VA_ARGS__)
S_METERING_BILLING_CTRL s_metering_ctrl;
#if 1 //计量费率控制
/**
* ************************************************************************
* @brief - 订单数据周期更新 -更新结束电量、结束soc、充电时间等信息
*
* @param[in] u8_gunNo - 枪号 0-N
*
*
* @author jiankalka
* @date 2025-09-12
* ************************************************************************
*/
static void v_meterlog_log_updata(U8_T u8_gunNo)
{
S_LOG_DATA *s_gun_log = &s_metering_ctrl.s_gun_log[u8_gunNo];
Comm_Time time;
U8_T u8_soc = u32_meterlog_get_sys_data(u8_gunNo,E_METERLOG_GET_DATA_GUN_SOC,0);
GetCurrentTime(&time);
U32_T u32_time = xDate2Seconds(&time); //获取时间戳
if(s_gun_log->StartChargeTime.iYear == 0)
memcpy(&s_gun_log->StartChargeTime, &time,sizeof(Comm_Time));
U32_T u32_start_time = xDate2Seconds(&s_gun_log->StartChargeTime); //获取起始时间时间戳
// 修复后的充电时间计算
s_gun_log->u16_ChargedTime = (u32_time >= u32_start_time)
? (u32_time - u32_start_time) / 60 // 正常情况
: (u32_start_time - u32_time) / 60; // 处理时间反转情况
//获取结束时间值
memcpy(&s_gun_log->EndChargeTime, &time,sizeof(Comm_Time)); //充电开始时间
s_gun_log->u64_endKWh = u64_meterlog_get_meter_data(u8_gunNo,0); //当前电表数据
if(u8_soc != 0)
s_gun_log->u8_endSoc = u8_soc; //SOC
if(s_gun_log->u8_startSoc == 0)
s_gun_log->u8_startSoc = s_gun_log->u8_endSoc;
}
/**
* ************************************************************************
* @brief - 实时获取当前费率信息 - 计算当前时段 获取费率信息
*
*
*
* @author jiankalka
* @date 2025-09-12
* ************************************************************************
*/
static void v_meterlog_real_fee_updata()
{
Comm_Time time;
U8_T u8_period_time;
GetCurrentTime(&time); //获取当前时间
u8_period_time = (time.ucHour*60 + time.ucMin) / 15; //计算当前所处时段 最大96
//METERFEE_LOG("u8_period_time=%d\n",u8_period_time);
if(u8_period_time >= 96 ) //异常数值
{
if(u8_cheak_fault_flag(E_FAULT_17009,E_WHOLE_HOST)==0)
{
METERFEE_LOG("Time invalid, now %d-%d-%d %d:%d; period=%d", time.iYear, time.ucMonth, time.ucDay, time.ucHour, time.ucMin, u8_period_time);
v_meterlog_set_fault(0,2,1,time.ucHour,time.ucMin); //时间不合法
return;
}
}
else
{
if(u8_cheak_fault_flag(E_FAULT_17009,E_WHOLE_HOST) == 1)
{
v_meterlog_set_fault(0,2,0,time.ucHour,time.ucMin);
}
}
//赋值当前费率信息
s_metering_ctrl.s_real_fee_data[0].u8_period_time = u8_period_time;
s_metering_ctrl.s_real_fee_data[0].u32_money_rate = u32_meterlog_get_sys_data(u8_period_time,E_METERLOG_GET_DATA_FEE_RATE_DATA,0); //费率电费信息 抢号代表时段位置 0-95;参数0代表充电费率 1代表放电费率 精度 0.0001元
s_metering_ctrl.s_real_fee_data[0].u32_money_service = u32_meterlog_get_sys_data(u8_period_time,E_METERLOG_GET_DATA_FEE_SERVER_DATA,0); //费率服务费信息 抢号代表时段位置 0-95;参数0代表充电费率 1代表放电费率 精度 0.0001元
s_metering_ctrl.s_real_fee_data[1].u8_period_time = u8_period_time; //放电
s_metering_ctrl.s_real_fee_data[1].u32_money_rate = u32_meterlog_get_sys_data(u8_period_time,E_METERLOG_GET_DATA_FEE_RATE_DATA,1); //费率电费信息 抢号代表时段位置 0-95;参数0代表充电费率 1代表放电费率 精度 0.0001元
s_metering_ctrl.s_real_fee_data[1].u32_money_service = u32_meterlog_get_sys_data(u8_period_time,E_METERLOG_GET_DATA_FEE_SERVER_DATA,1); //费率服务费信息 抢号代表时段位置 0-95;参数0代表充电费率 1代表放电费率 精度 0.0001元
}
/**
* ************************************************************************
* @brief - 枪周期充电电量、计量计算
*
* @param[in] u8_gunNo - 枪号
*
*
* @author jiankalka
* @date 2025-09-12
* ************************************************************************
*/
static void v_meterlog_charge_calculate(U8_T u8_gunNo)
{
S_CHAR_DATA *s_char_data = &s_metering_ctrl.s_char_data[u8_gunNo]; //获取枪控制信息
S_LOG_DATA *s_gun_log = &s_metering_ctrl.s_gun_log[u8_gunNo]; //获取枪订单信息
S_REAL_FEE_DATA *s_real_fee_data = &s_metering_ctrl.s_real_fee_data[s_char_data->u8_discharge_flag]; //获取当前费率信息 默认已经更新正确
U32_T u64_meter_data = u64_meterlog_get_meter_data(u8_gunNo,0); //获取枪电表值 精度 0.0001kwh
U32_T u32_cyc_pow = 0; //本次循环电量 精度 0.0001kwh
U32_T u32_cyc_money = 0; //本次循环费用 精度 0.0001kwh
//计算周期电表差值
if(s_char_data->u64_whm_start_energy == 0) //本次充电 首次计量
{
s_char_data->u64_whm_start_energy = u64_meter_data;
return;
}
else if(s_char_data->u64_whm_start_energy > u64_meter_data && u64_meter_data !=0 ) //上次电表电量 大于本次 则说明电表电量 超出上限进行了归0
{
u32_cyc_pow = METER_MAX_ELE - s_char_data->u64_whm_start_energy + u64_meter_data;
}
else //正常计算差值
{
u32_cyc_pow = u64_meter_data - s_char_data->u64_whm_start_energy;
}
if(u32_cyc_pow > 10000 ) // 跳变大于10度判定电表异常
{
if(u8_cheak_fault_flag(E_FAULT_17007, (E_FAULT_SITE)((U16_T)E_GUN + (U16_T)u8_gunNo)) == 0U)//无告警
{
METERFEE_LOG("[%d]Gun meter jump fault, delta=%d, thr=%d\n", u8_gunNo, u32_cyc_pow, 10000);
v_meterlog_set_fault(u8_gunNo,0,1,s_char_data->u64_whm_start_energy,u64_meter_data); //设置系统故障
}
return;
}
//更新存储的电量,本次存储电量作为下一循环的起始电量
s_char_data->u64_whm_start_energy = u64_meter_data;
s_gun_log->u32_used_energy += u32_cyc_pow;
s_gun_log->u32_part_energy[s_real_fee_data->u8_period_time] += u32_cyc_pow; //将本次循环电量累加到本时段电量中
u32_cyc_money = (u32_cyc_pow*(s_real_fee_data->u32_money_rate)) / 10000; //周期电费 精度 0.0001kwh
s_gun_log->u32_used_money += u32_cyc_money; //电费累加
u32_cyc_money = (u32_cyc_pow*(s_real_fee_data->u32_money_service)) / 10000; //周期电费 精度 0.0001kwh
s_gun_log->u32_used_service += u32_cyc_money;
//METERFEE_LOG("[%d]Gun period=%d, rate=%d, svc=%d\n", u8_gunNo, s_real_fee_data->u8_period_time, s_real_fee_data->u32_money_rate, s_real_fee_data->u32_money_service);
METERFEE_LOG("[%d]Gun addE(0.0001kWh)=%d, totalE=%d, ChgTime=%d,\n", u8_gunNo, u32_cyc_pow, s_gun_log->u32_used_energy,s_gun_log->u16_ChargedTime);
//METERFEE_LOG(" fee=%d, svcFee=%d\n", s_gun_log->u32_used_money, s_gun_log->u32_used_service);
}
/**
* ************************************************************************
* @brief -计量计费流程
*
*
*
*
* @author jiankalka
* @date 2025-09-24
* ************************************************************************
*/
static void v_meterlog_ctrl()
{
U8_T u8_gunNo;
S_CHAR_DATA *s_char_ctrl = NULL;
if(s_metering_ctrl.u16_timer % NUM_5000 != 0) //5秒 计算一次
return;
v_meterlog_real_fee_updata(); //更新当前费率信息
//遍历所有的枪 依次进行计量判断
for (u8_gunNo = 0; u8_gunNo < s_metering_ctrl.u8_gunCnt; u8_gunNo++)
{
s_char_ctrl = &s_metering_ctrl.s_char_data[u8_gunNo]; //获取枪控制数据
if(s_char_ctrl->u8_billing_flag == 1) //进行充电计量计费
{
v_meterlog_charge_calculate(u8_gunNo); //周期计量计费
v_meterlog_log_updata(u8_gunNo); //更新充电结束信息
/* 充电中:每 60 秒将订单临时记录写入 EEPROM,支持掉电续传 */
{
U32_T now = get_current_seconds();
if (s_char_ctrl->u32_last_temp_save_sec == 0 ||
u32_safe_seconds_since(s_char_ctrl->u32_last_temp_save_sec) >= 60)
{
v_meterlog_flash_save_log(0, u8_gunNo);
s_char_ctrl->u32_last_temp_save_sec = now;
}
}
}
else //不进行计量计费
{
s_char_ctrl->u64_whm_start_energy = 0; //周期电表电量值清零
s_char_ctrl->u32_last_temp_save_sec = 0;
if(u8_cheak_fault_flag(E_FAULT_17007, (E_FAULT_SITE)((U16_T)E_GUN + (U16_T)u8_gunNo)) == 1U) //若电表跳变异常,不计量计费时恢复
{
v_meterlog_set_fault(u8_gunNo,0,0,0,0); //设置系统故障恢复
}
}
}
}
/**
* ************************************************************************
* @brief -计量计费判断
*
*
*
* @author jiankalka
* @date 2025-09-24
* ************************************************************************
*/
static void v_meterlog_action_cheak()
{
U8_T u8_gunNo;
S_CHAR_DATA *s_char_ctrl = NULL;
S_LOG_DATA *s_gun_log = NULL;
//终端充电状态 0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
U8_T u8_flow_state;
//遍历所有的枪 依次进行计量判断
for (u8_gunNo = 0; u8_gunNo < s_metering_ctrl.u8_gunCnt; u8_gunNo++)
{
s_char_ctrl = &s_metering_ctrl.s_char_data[u8_gunNo]; //获取枪控制数据
s_gun_log = &s_metering_ctrl.s_gun_log[u8_gunNo]; //获取枪订单信息
u8_flow_state = u32_meterlog_get_sys_data(u8_gunNo,E_METERLOG_GET_DATA_GUN_FLOW_STATE,0);
if(u8_flow_state > 1 && u8_flow_state != 10) //后续考虑是否需要增加 充电后5秒钟再进行一次计量的判断--计量计费检测
{
if(s_char_ctrl->u8_billing_flag == 0)
{
s_char_ctrl->u8_billing_flag = 1; //开始计量计费
METERFEE_LOG("[%d]Gun(0-N) metering start\n", u8_gunNo);
}
if(u8_flow_state == 7)
s_gun_log->u8_charge_flag = 1; //进入充电中标志
s_char_ctrl->u32_billing_time = get_current_seconds(); //更新超时起始时间
}
else
{
if(u8_flow_state == 0 || u8_flow_state == 10)
{
if(u32_safe_seconds_since(s_char_ctrl->u32_billing_time) > 7) //处于充电完成状态7S后停止计量,确保最后一次计量完成
{
if(s_char_ctrl->u8_billing_flag != 0)
{
s_char_ctrl->u8_billing_flag = 0;
v_set_plat_log_flag(u8_gunNo); //设置平台订单上送标志
v_meterlog_flash_save_log(1 , u8_gunNo); //设置订单信息存储
METERFEE_LOG("[%d]Gun(0-N) metering stop\n", u8_gunNo);
}
}
}
else
{
s_char_ctrl->u32_billing_time = get_current_seconds(); //更新超时起始时间
}
}
}
}
#endif
void v_metering_billing_data_init(void)
{
memset(&s_metering_ctrl , 0 ,sizeof(S_METERING_BILLING_CTRL));
s_metering_ctrl.u8_gunCnt = u32_meterlog_get_sys_data(0, E_METERLOG_GET_DATA_GUN_CNT , 0); //获取枪数量
// 初始化充电订单Flash存储模块
v_chg_order_flash_init();
//v_chg_order_clear_all();
v_unsettled_order_init();
v_meterlog_restore_temp_from_eeprom();
//Calculate_LOG("充电订单Flash存储模块初始化完成\r\n");
}
void v_meterfee_task(void *arg)
{
uint16_t sleep_time_ms;
uint32_t last_send_time;
uint32_t current_time;
(void)arg;
(void)METERFEE_LOCK_INIT();
sleep_time_ms = METERFEE_SLEEP_TIME_MS();
last_send_time = get_current_seconds();
v_metering_billing_data_init();
for (;;) {
METERFEE_FEED_DOG();
current_time = get_current_seconds();
if ((TASK_RUN_PRINT_TIME != 0U) && (u32_safe_seconds_since(last_send_time) >= TASK_RUN_PRINT_TIME)) {
if (METERFEE_LOCK_TAKE() == 1U) {
METERFEE_LOG("meter fee task is runing, sleep time is %ums", sleep_time_ms);
(void)METERFEE_LOCK_GIVE();
}
last_send_time = current_time;
}
v_meterlog_action_cheak();
v_meterlog_ctrl();
if (s_metering_ctrl.u16_timer < 0xFF00U) {
s_metering_ctrl.u16_timer += sleep_time_ms;
} else {
s_metering_ctrl.u16_timer = 0U;
}
mSleep(sleep_time_ms);
}
}