Files
CCU621M/app/plat_comm/impl/bs_public_impl.c
T

1552 lines
56 KiB
C
Raw 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.
#include "plat_comm/impl/bs_public_impl.h"
#include "publicdata/publicdata.h"
#include "flowctrl/flow_interface.h"
#include "plat_comm/plat_comm_task.h"
#include "mdu_comm/mdu_interface.h"
#if EC200A_4G_EN
#include "plat_comm/4g_module/ec200a_4g.h"
#include "plat_comm/4g_module/ec200a_4g_ftp.h"
#endif
#if WH_GM5_EN
#include "plat_comm/4g_module/bs_wh_gm5.h"
#endif
#include "meter_calculate/meter_coll_task.h"
#include "bsp_include.h"
#if LWIP_FTP_UPGRADE_ENABLE
/* LwIP FTP 升级(网线):状态机+周期调用 */
#include "plat_comm/lwip_module/lwip_ftp_upgrade.h"
#endif
#include "collect_ctrl/collect_task.h"
#include "app_fatfs/fatfs_init.h"
#include "app_fatfs/fatfs_card.h"
#include "plat_comm/ocpp/bs_ocpp_configuration.h"
#if BS_OCPP_EN
#include "plat_comm/ocpp/BS_ocpp_ctrl.h"
#include "plat_comm/ocpp/BS_ocpp_mv_offline_bridge.h"
#endif
#include "flash_file_mgr/unsettled_order_mng.h"
#include "flash_file_mgr/meter_calculate_flash_impl.h"
#include "bms/bms_interface.h"
#define BS_PUBLIC_PRINTF_LOG(fmt, ...) \
MYLOG_MSG(OCPP_PRINT_FLAG,fmt, ##__VA_ARGS__) //任务打印
T_FTP_UPDATE_INFO t_ftp_update_info;
/* 当 FATFS 卡功能关闭时,使用 Flash 卡库并保证初始化一次 */
static U8_T u8_card_storage_ready(void)
{
#if FATFS_ENABLE_CARD
return 1;
#else
CardStatus status = card_init();
return (status == CARD_STATUS_OK || status == CARD_STATUS_ALREADY_INIT) ? 1u : 0u;
#endif
}
/* 本地鉴权查卡:最多 3 次,成功即返回;每次失败后间隔 100ms 再试 */
static U8_T u8_card_find_with_retry(const char *id_tag, CardInfo *card_info)
{
U8_T attempt;
for (attempt = 0; attempt < 3; attempt++) {
if (card_find(id_tag, card_info) == CARD_STATUS_OK) {
return 1;
}
if (attempt + 1 < 3) {
mSleep(100);
}
}
return 0;
}
/**
* ************************************************************************
* @brief - 获取系统字符串格式数据
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] e_dataType - 数据类型-区分数据内容 详看定义枚举内容
* @param[in] u8_dataPara - 数据参数 根据数据内容自行定义
* @param[in] u8_getData - 数据获取缓存数组
* @param[in] u8_len - 数据获取最大长度
*
* @return U8_T - 1获取成功 0获取失败
*
* @author jiankalka
* @date 2025-09-02
*
* 数据说明参数 E_STR_PILE_NO 获取桩编号,0获取平台1桩编号 1获取平台2桩编号
* ************************************************************************
*/
U8_T u8_get_str_data(U8_T u8_gunNo,E_GET_SYS_STR e_dataType,U8_T u8_dataPara,char *u8_getData,U8_T u8_len)
{
U8_T res = 0;
SYS_FIX_CFG_T *t_sys_fix_cfg = &g_t_share_data.t_sys_fix_cfg; //获取系统参数结构体指针地址
SYS_VAR_CFG_T *t_sys_var_cfg = &g_t_share_data.t_sys_var_cfg;
memset(u8_getData , 0 , u8_len); //清空
switch(e_dataType){
case E_STR_PILE_NO:{ //桩编号
if(u8_dataPara == 0)
strncpy((char *)u8_getData , (char *)&t_sys_fix_cfg->s_net_cfg.u8_platA_pileNum[0] , u8_len);
else
strncpy((char *)u8_getData , (char *)&t_sys_fix_cfg->s_net_cfg.u8_platB_pileNum[0] , u8_len);
break;
}
case E_STR_SOFTWARE_VERSION:{ //软件版本号
if(u8_dataPara == 0)
strncpy((char *)u8_getData , (char *)&t_sys_var_cfg->custom_ver[0] , u8_len);
else
strncpy((char *)u8_getData , (char *)&Software_Version[0] , u8_len);
break;
}
case E_STR_HARDWARE_VERSION:{ //硬件版本号
strncpy((char *)u8_getData , (char *)&Hardware_Version[0] , u8_len);
break;
}
case E_STR_LOG_preTradeNo:{ //订单流水号 type=0,平台流水号;type=1,设备流水号
S_LOG_DATA s_log;
memset(&s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息
if(u8_dataPara == 0)
strncpy((char *)u8_getData , (char *)&s_log.u8_preTradeNo[0] , u8_len);
else
strncpy((char *)u8_getData , (char *)&s_log.u8_tradeNo[0] , u8_len);
break;
}
case E_STR_LOG_vin:{ //订单VIN
S_LOG_DATA s_log;
memset(&s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息
strncpy((char *)u8_getData , (char *)&s_log.u8_vinCode[0] , u8_len);
break;
}
case E_STR_LOG_user_id:{ //订单用户标识
S_LOG_DATA s_log;
memset(&s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息
strncpy((char *)u8_getData , (char *)&s_log.u8_user_id[0] , u8_len);
break;
}
case E_STR_SDK_PARA_product_key: //国网sdk 产品密钥
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.product_key ,u8_len);
break;
}
case E_STR_SDK_PARA_device_name: //国网sdk 资产吗
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.device_name ,u8_len);
break;
}
case E_STR_SDK_PARA_device_secret: //国网sdk 设备秘钥
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.device_secret ,u8_len);
break;
}
case E_STR_SDK_PARA_device_reg_code: //国网sdk 注册码
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.device_reg_code ,u8_len);
break;
}
case E_STR_SDK_PARA_device_uid: //国网sdk 出厂编码
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.device_uid ,u8_len);
break;
}
case E_STR_SDK_PARA_firmware_version: //国网sdk 固件版本信息
{
//strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_sdk_data.firmware_version ,u8_len);
break;
}
case E_STR_SDK_SIM_ID: //sim卡号
{
#if EC200A_4G_EN
u8_get_sim_card((U8_T*)u8_getData , u8_len);
#endif
#if WH_GM5_EN
v_GM5_get_sim((U8_T*)u8_getData);
#endif
break;
}
case E_STR_METER_ADDR: //获取电表号 0直流电表 1交流电表
{
u8_get_meter_id_str(u8_gunNo ,u8_dataPara ,(U8_T*)u8_getData , u8_len);
break;
}
case E_STR_FEE_ID: //计费模型ID
{
strncpy((char *)u8_getData , (char *)t_sys_var_cfg->s_fee_model.u8_model_no ,u8_len);
break;
}
case E_STR_QR_DISPLAY: //枪二维码 u8_gunNo=0/1
{
if (u8_gunNo >= GUN_MAX_CNT) {
break;
}
strncpy((char *)u8_getData,
(char *)t_sys_var_cfg->QRDisplay[u8_gunNo],
u8_len);
res = (U8_T)strlen((char *)u8_getData);
break;
}
default:
break;
}
return res;
}
U8_T u8_set_str_data(U8_T u8_gunNo, E_GET_SYS_STR e_dataType, U8_T u8_dataPara,
const char *pu8_data, U8_T u8_len)
{
SYS_VAR_CFG_T *t_sys_var_cfg = &g_t_share_data.t_sys_var_cfg;
(void)u8_dataPara;
if (pu8_data == NULL || u8_len == 0U) {
return 0U;
}
switch (e_dataType) {
case E_STR_QR_DISPLAY:
if (u8_gunNo >= GUN_MAX_CNT) {
return 0U;
}
if (u8_len >= (U8_T)sizeof(t_sys_var_cfg->QRDisplay[0])) {
return 0U;
}
(void)memset(t_sys_var_cfg->QRDisplay[u8_gunNo], 0,
sizeof(t_sys_var_cfg->QRDisplay[u8_gunNo]));
(void)memcpy(t_sys_var_cfg->QRDisplay[u8_gunNo], pu8_data, u8_len);
t_sys_var_cfg->QRDisplay[u8_gunNo][u8_len] = '\0';
v_flash_save_cfg_data();
return 1U;
default:
break;
}
return 0U;
}
/** 二维码更新标志(CCU621 暂未对接 UI,预留接口) */
void v_ccu_set_qrcode_flag(U8_T u8_gunNo, U8_T flag)
{
(void)u8_gunNo;
(void)flag;
}
/**
* ************************************************************************
* @brief - 订单信息获取--仅支持订单包含订单数据的内容 -订单数据需要获取订单结构体 因此单独拿出来避免函数重复使用
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] e_datatype - 数据类型
* @param[in] u8_dataPara - 参数
*
* @return U32_T -
*
* @author jiankalka
* @date 2025-09-24
* ************************************************************************
*/
static U32_T u32_bs_get_log_info(U8_T u8_gunNo,E_GET_SYS_DATA e_datatype,U8_T u8_dataPara)
{
U32_T u32_res = 0;
S_LOG_DATA s_log;
memset(&s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息
switch (e_datatype)
{
//订单信息
case E_BS_GET_SYS_DATA_LOG_ENERGY : //订单电量 0.001kWh 三位小数精度 type=0 :已充电量;type=1 :电表起始值,type=2,电表终止值
{
if(u8_dataPara == 0)
u32_res = s_log.u32_used_energy/10;
else if(u8_dataPara == 1)
u32_res = s_log.u64_startKWh/10;
else if(u8_dataPara == 2)
u32_res = s_log.u64_endKWh/10;
break;
}
case E_BS_GET_SYS_DATA_LOG_STOP_REASON : //充电订单停止原因
{
u32_res = s_log.e_stop_reason[0];
break;
}
case E_BS_GET_SYS_DATA_LOG_charge_flag : //订单充电标志 0未充电 1已经充电
{
u32_res = s_log.u8_charge_flag;
break;
}
case E_BS_GET_SYS_DATA_SOC_DATA: //SOC 数据 type=0 :当前SOCtype=1 :启动时SOC;type=2 :结束时SOC
{
if(u8_dataPara == 0)
u32_res = s_log.u8_endSoc;
else if(u8_dataPara == 1)
u32_res = s_log.u8_startSoc;
else if(u8_dataPara == 2)
u32_res = s_log.u8_endSoc;
break;
}
case E_BS_GET_SYS_DATA_LOG_CHARGE_TIME: //充电时间 min
{
u32_res = s_log.u16_ChargedTime;
break;
}
default:
break;
}
return u32_res;
}
/**
* ************************************************************************
* @brief - 获取系统整形、浮点型格式数据
*
* @param[in] u8_gunNo - 抢号 0-N
* @param[in] e_datatype - 数据类型-区分数据内容 详看定义枚举内容
* @param[in] u8_dataPara - 数据参数 根据数据内容自行定义
*
* @return TYPE_DATA - 共用体类型 - 返回不同类型数据,使用时注意数据类型
* typedef union {
* U8_T u8_data;
* S8_T s8_data;
* U16_T u16_data;
* S16_T s16_data;
* U32_T u32_data;
* F32_T f32_data;
* U64_T u64_data;
* }TYPE_DATA;
* @author jiankalka
* @date 2025-09-02
*
* 数据说明参数 E_BS_GET_SYS_DATA_NET_TYPE 获取网路类型,0获取平台1 1获取平台2
* ************************************************************************
*/
U32_T u32_bs_get_sys_data(U8_T u8_gunNo,E_GET_SYS_DATA e_datatype,U8_T u8_dataPara)
{
U32_T u32_res = 0;
SYS_FIX_CFG_T *t_sys_fix_cfg = &g_t_share_data.t_sys_fix_cfg; //获取系统参数结构体指针地址
switch(e_datatype){
//桩信息
case E_BS_GET_SYS_DATA_GUN_NUM: //枪数量
{
u32_res = t_sys_fix_cfg->u8_gunCnt;
break;
}
case E_BS_GET_SYS_DATA_NET_TYPE: //联网类型 0:4G 1:网线
{
if(u8_dataPara == 0)
u32_res = t_sys_fix_cfg->s_net_cfg.u_net_comm_para.bits.bit_netA_type;
else
u32_res = t_sys_fix_cfg->s_net_cfg.u_net_comm_para.bits.bit_netB_type;
break;
}
case E_BS_GET_SYS_DATA_PLAT_EN: //平台使能 u8_gunNo=0平台A 1平台B
{
if(u8_gunNo == 0)
u32_res = t_sys_fix_cfg->s_net_cfg.u_net_comm_para.bits.bit_platA_en;
else
u32_res = t_sys_fix_cfg->s_net_cfg.u_net_comm_para.bits.bit_platB_en;
break;
}
case E_BS_GET_SYS_DATA_NOW_FAULT_ALARM_NUM: //type=0当前故障数量/type=1当前告警数量
{
REAL_FAULT_DATA_T rl_data;
v_get_fault_data(&rl_data);
if(u8_dataPara == 0)
u32_res = rl_data.u8_fault_cnt;
else
u32_res = rl_data.u8_warn_cnt;
break;
}
case E_BS_GET_SYS_DATA_NOW_FAULT_ALARM_DATA: //获取故障内容 参数 0-N 获取故障位置 CURR_FAULT_MAX_CNT
{
REAL_FAULT_DATA_T rl_data;
v_get_fault_data(&rl_data);
if(u8_dataPara >= CURR_FAULT_MAX_CNT)
u8_dataPara = CURR_FAULT_MAX_CNT - 1;
u32_res = rl_data.fault_data[u8_dataPara].e_mag;
break;
}
case E_BS_GET_SYS_DATA_4G_signal_quality: //4G信号强度
{
#if EC200A_4G_EN
u32_res = u8_UAT_check_signal_quality();
#endif
#if WH_GM5_EN
u32_res = (U32_T)s8_UAT_check_signal_quality();
#endif
break;
}
case E_BS_GET_SYS_DATA_RATED_POWER: //额定功率 单位w
{
u32_res = t_sys_fix_cfg->u16_ratePow * 1000;
break;
}
case E_BS_GET_SYS_DATA_PILE_PUT_PARA: //充电桩输出参数 单位0.1V/0.1A 0最大电压 1最小电压 2最大电流 3最小电流
{
if(u8_dataPara == 0)
u32_res = t_sys_fix_cfg->u16_mdu_max_vol;
else if(u8_dataPara == 1)
u32_res = t_sys_fix_cfg->u16_min_volt;
else if(u8_dataPara == 2)
u32_res = t_sys_fix_cfg->u16_max_cur;
else if(u8_dataPara == 3)
u32_res = 0;
break;
}
//枪信息
case E_BS_GET_SYS_DATA_GUN_FLOW_STATE: //终端充电状态 0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
{
u32_res = u16_flow_put_data(u8_gunNo , E_FLOW_PUT_DATA_GUN_REAL_STATE,0);
break;
}
case E_BS_GET_SYS_DATA_GUN_STATE: //枪状态信息 type=0 :枪连接状态;
{
if(u8_dataPara == 0)
u32_res = u8_get_gun_yx_data(YX_GUN_LINK,u8_gunNo); //type=0 :抢连接状态;
else if(u8_dataPara == 1)
u32_res = u8_get_gun_yx_data(YX_GUN_LOCK,u8_gunNo); //type=1 :电子锁状态;
else if(u8_dataPara == 2)
u32_res = 0; //type=2 :枪空座归位状态;
else if(u8_dataPara == 3)
u32_res = u8_get_gun_yx_data(YX_GUN_DC_KM_POS,u8_gunNo); //type=3 :正母线直流输出接触器状态
else if(u8_dataPara == 4)
u32_res = u8_get_gun_yx_data(YX_GUN_DC_KM_NEG,u8_gunNo); //type=4 :负母线直流输出接触器状态
break;
}
case E_BS_GET_SYS_DATA_GUN_TEMP_POS : //充电枪正极温度 单位0.1度 0-100最小为0
{
u32_res = f32_get_gun_yc_data(ADC_GUN_TEMP_PLUS,u8_gunNo)*10;
break;
}
case E_BS_GET_SYS_DATA_GUN_TEMP_NEG : //充电枪负极温度 单位0.1度 0-100最小为0
{
u32_res = f32_get_gun_yc_data(ADC_GUN_TEMP_MINUS,u8_gunNo)*10;
break;
}
case E_BS_GET_SYS_DATA_PILE_TEMP : //环境温度 精确到小数点后1位,-50℃偏差
{
u32_res = (f32_get_sys_yc_data(ADC_PILE_TEMP1)*10)+500; //获取模块上送温度值- 单位 度,范围0-100,注意最低为0度
break;
}
case E_BS_GET_SYS_DATA_METER_CUR : //电表电流 单位0.1A
{
u32_res = u64_get_meter_data(u8_gunNo,0,E_METER_DATA_CUR)/1000; //电表采集电压值 精度 0.0001
break;
}
case E_BS_GET_SYS_DATA_METER_VOL : //电表电压 单位0.1V
{
u32_res = u64_get_meter_data(u8_gunNo,0,E_METER_DATA_VOL)/1000; //电表采集电压值 精度 0.0001
break;
}
//订单信息
case E_BS_GET_SYS_DATA_LOG_ENERGY : //订单电量 0.001kWh 三位小数精度 type=0 :已充电量;type=1 :电表起始值,type=2,电表终止值
case E_BS_GET_SYS_DATA_LOG_STOP_REASON : //充电订单停止原因
case E_BS_GET_SYS_DATA_LOG_charge_flag : //订单充电标志 0未充电 1已经充电
case E_BS_GET_SYS_DATA_SOC_DATA: //SOC 数据 type=0 :当前SOCtype=1 :启动时SOC;type=2 :结束时SOC
case E_BS_GET_SYS_DATA_LOG_CHARGE_TIME: //充电时间 min
{
u32_res = u32_bs_get_log_info(u8_gunNo,e_datatype,u8_dataPara); //统一获取订单信息
break;
}
//bms信息
case E_BS_GET_SYS_DATA_BMS_CELL_MAX_VOL : //最高单体动力蓄电池电压
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_NEED_VOL : //电压需求 单位0.1V
{
//u32_res = u16_ccu_put_data(u8_gunNo , E_CCU_DATA_needVol);
u32_res = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_VOL,0);
break;
}
case E_BS_GET_SYS_DATA_BMS_NEED_CUR : //电流需求 单位0.1A
{
//u32_res = u16_ccu_put_data(u8_gunNo , E_CCU_DATA_needCur);
u32_res = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_CUR,0);
break;
}
case E_BS_GET_SYS_DATA_BMS_CHARGE_VOL : //BMS充电电压测量值
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_CHARGE_CUR : //BMS充电电流测量值
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_CHARGE_MAX_VOL : //最高允许充电总电压
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_CELL_CHARGE_MAX_VOL : //单体动力蓄电池最高允许充电电压
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_CHARGE_MAX_CUR : //最高允许充电电流
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_RATED_VOL : //整车动力蓄电池系统额定总电压
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_VOL : //整车动力蓄当前电池总电压
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_RATED_C10 : //整车动力蓄电池系统额定容量
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_RATED_ENERY : //动力蓄电池标称总能量
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_ID : //电池编号信息 0最高单体动力蓄电池电压所在编号 1最高动力蓄电池温度检测点编号 2最低动力蓄电池温度检测点编号
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_TEMP : //单位 0.1度0-100最小为0 0 电池最高温度 1最低温度
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_REMAIN_TIME : //剩余充电时间 min
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_MAX_TEMP : //最高动力蓄电池温度
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_MIN_TEMP : //最低动力蓄电池温度
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_BMS_BATT_ALLOW_MAX_TEMP : //最高允许动力蓄电池温度
{
u32_res = 0;
break;
}
case E_BS_GET_SYS_DATA_UNIX_TIMESTAMP:
{
Comm_Time ctTime;
GetCurrentTime(&ctTime);
u32_res = xDate2Seconds(&ctTime);
break;
}
default:
break;
}
return u32_res;
}
U8_T u8_set_sys_data(U8_T u8_gunNo, E_GET_SYS_DATA e_datatype, U32_T u32_val, U8_T u8_dataPara)
{
Comm_Time ctTime;
(void)u8_gunNo;
(void)u8_dataPara;
switch (e_datatype) {
case E_BS_GET_SYS_DATA_UNIX_TIMESTAMP:
xSeconds2Date(u32_val, &ctTime);
v_bs_set_time(&ctTime);
return 1U;
default:
break;
}
return 0U;
}
U64_T u64_bs_get_sys_data(U8_T u8_gunNo,E_GET_SYS_DATA e_datatype)
{
U64_T u64_ret = 0;
switch (e_datatype)
{
case E_BS_GET_SYS_DATA_MEMTER_ELECT : //电表电量 0.0001kWh
{
u64_ret = u64_get_meter_data(u8_gunNo,0,E_METER_DATA_POWER);
break;
}
default:
break;
}
return u64_ret;
}
/**
* ************************************************************************
* @brief - SDK三元组获取或设置
*
* @param[in] u8_type - 0设置三元组 1获取三元组
* @param[in] s_set_sdk_data - 三元组数据
*
*
* @author jiankalka
* @date 2025-09-19
* ************************************************************************
*/
void v_bs_gwsdk_set_para(U8_T u8_type, S_SDK_DATA *s_sdk_data)
{
int i=0;
S_SDK_DATA *s_sys_sdk_data = &g_t_share_data.t_sys_var_cfg.s_sdk_data;
if(u8_type == 0) //设置三元组
{
memcpy(s_sys_sdk_data->product_key, s_sdk_data->product_key, sizeof(s_sys_sdk_data->product_key));
memcpy(s_sys_sdk_data->device_name, s_sdk_data->device_name, sizeof(s_sys_sdk_data->device_name));
memcpy(s_sys_sdk_data->device_secret, s_sdk_data->device_secret, sizeof(s_sys_sdk_data->device_secret));
//
////保存参数到DATAFLASH,三元组数据存储
v_flash_save_cfg_data();
//
v_sys_reboot(); //系统重启
}
else //获取三元组
{
memcpy(s_sdk_data->product_key, s_sys_sdk_data->product_key, sizeof(s_sys_sdk_data->product_key));
memcpy(s_sdk_data->device_name, s_sys_sdk_data->device_name, sizeof(s_sys_sdk_data->device_name));
memcpy(s_sdk_data->device_secret, s_sys_sdk_data->device_secret, sizeof(s_sys_sdk_data->device_secret));
memcpy(s_sdk_data->device_reg_code, s_sys_sdk_data->device_reg_code, sizeof(s_sys_sdk_data->device_reg_code));
memcpy(s_sdk_data->device_uid, s_sys_sdk_data->device_uid, sizeof(s_sys_sdk_data->device_uid));
}
}
/**
* ************************************************************************
* @brief - 设置系统时间
*
* @param[in] currtime - 时间
*
*
* @author jiankalka
* @date 2025-09-22
* ************************************************************************
*/
void v_bs_set_time(Comm_Time *currtime)
{
v_rtc_set_time(currtime);//CPU时间设定
}
void v_bs_save_fee_data(U8_T u8_flag, S_FEE_MODEL *s_fee_model)
{
if(s_fee_model == NULL)
return;
if(u8_flag == 1)
{
memcpy(&g_t_share_data.t_sys_var_cfg.s_fee_model , s_fee_model , sizeof(S_FEE_MODEL));
v_flash_save_cfg_data(); //存储flash
}
else
{
memcpy(s_fee_model ,&g_t_share_data.t_sys_var_cfg.s_fee_model , sizeof(S_FEE_MODEL));
}
}
#if 1 //充电状态相关
/**
* ************************************************************************
* @brief - 获取终端状态 0 空闲 1开始充电 2充电中 3充电完成
*
* @param[in] u8_gunNo - 抢号 0-N
*
* @return U8_T - 0 空闲 1开始充电 2充电中 3充电完成
*
* @author jiankalka
* @date 2025-09-19
* ************************************************************************
*/
U8_T u8_bs_get_flow_state(U8_T u8_gunNo)
{
//枪运行状态 0空闲 1插枪 2绝缘启机 3绝缘停止 4预充启动 5充电中 6充电停止 7停止完成
//终端充电状态 0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成
U8_T u8_flow_state = u32_bs_get_sys_data(u8_gunNo,E_BS_GET_SYS_DATA_GUN_FLOW_STATE,0);
U8_T u8_gun_state = 0;
if(u8_flow_state == 7 || u8_flow_state == 8) //充电中
{
u8_gun_state = 2;
}
else if(u8_flow_state >= 2 && u8_flow_state < 7) //启动中
{
u8_gun_state = 1;
}
else if(u8_flow_state == 9 || u8_flow_state == 10) //停止完成
{
u8_gun_state = 3;
}
else
u8_gun_state = 0;
return u8_gun_state;
}
/**
* ************************************************************************
* @brief - 检查状态变位状态 - 充电状态变化时 立即上送充电状态
*
*
*
* @author jiankalka
* @date 2025-09-19
* ************************************************************************
*/
void v_cheak_state_change() //
{
// 插枪变位/流程状态变位检测,用于实时状态上传
U8_T i;
/* u8_flow_state / u8_flow_state_old 含义(来自 E_BS_GET_SYS_DATA_GUN_FLOW_STATE):
* 0:空闲 1:充电启动 2:绝缘启动 3:绝缘计算完成 4:绝缘检测模块停止
* 5:开始预充 6:预充完成 7:充电中 8:BMS通讯超时 9:充电停止 10:充电停止完成
*
* u8_flow_state_old[i]:该枪“上一次轮询”的流程状态
* u8_flow_state :该枪“本次轮询”的流程状态
*/
static U8_T u8_flow_state_old[GUN_MAX_CNT] = {0};
static U8_T u8_gunLink_old[GUN_MAX_CNT] = {0};
U8_T u8_flow_state ,u8_gunLink;
for(i=0; i<GUN_MAX_CNT; i++)
{
u8_flow_state = u32_bs_get_sys_data(i,E_BS_GET_SYS_DATA_GUN_FLOW_STATE,0);
u8_gunLink = u32_bs_get_sys_data(i,E_BS_GET_SYS_DATA_GUN_STATE,0); //抢连接
if(u8_flow_state != u8_flow_state_old[i] || u8_gunLink != u8_gunLink_old[i])
{
U8_T flow_state_changed = (u8_flow_state != u8_flow_state_old[i]) ? 1 : 0;
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[i].u8_pile_state_change_flag = 1;//变为标志置一
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[i].u8_pile_state_change_flag = 1;//变为标志置一
/* txFlag_startResult 置1时机(仅 flow_state 变化时):
* 1) old < 7 && new == 7 :从“非充电中(启动阶段)”进入“充电中”
* 2) old == 10 && new == 7:从“停止完成”再次进入“充电中”
* 说明:用于触发 StartTransaction 上送。
*/
if(flow_state_changed &&
(((u8_flow_state_old[i] < 7) && (u8_flow_state == 7)) ||
((u8_flow_state_old[i] == 10) && (u8_flow_state == 7)))) //停止完成/启动中 -> 充电中
{
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[i].txFlag_startResult = 1;//变为标志置一
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[i].txFlag_startResult = 1;//变为标志置一
}
/* txFlag_stopResult 置1时机(仅 flow_state 变化时):
* 1) old 在 (0,7](即启动阶段或充电中)
* 2) new 为 0/9/10(空闲/充电停止/充电停止完成)
* 说明:用于触发 StopTransaction 上送。
* 注意:要求 old>0,可避免 0->0(仅插拔枪)误触发 stopResult。
*/
else if(flow_state_changed &&
(u8_flow_state_old[i] > 0 && u8_flow_state_old[i] <= 7) &&
(u8_flow_state == 0 || u8_flow_state == 9 ||u8_flow_state == 10)) //启动中 或者充电中 变为停止充电 则为停止结果
{
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[i].txFlag_stopResult = 1;//变为标志置一
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[i].txFlag_stopResult = 1;//变为标志置一
printf("gun %d stop result\n",i);
}
BS_PUBLIC_PRINTF_LOG("gun %d flow state change %d->%d, gunLink change %d->%d",i,u8_flow_state_old[i],u8_flow_state,u8_gunLink_old[i],u8_gunLink);
u8_flow_state_old[i] = u8_flow_state;
u8_gunLink_old[i] = u8_gunLink;
}
}
}
void v_bs_get_gun_log_data(U8_T u8_gunNo , S_LOG_DATA *s_log)
{
v_meterlog_put_char_log_data(u8_gunNo,s_log);
}
void v_bs_get_fee_part_data(U8_T u8_gunNo,U8_T flag,S_LOG_DATA *t_log,U32_T *u32_part_energy,F32_T *f32_rate,F32_T *f32_sevice) //获取时段电量、电费
{
U8_T i,j,fee_num = g_t_share_data.t_sys_var_cfg.s_fee_model.u8_feeCnt;
U8_T u8_type_cnt = 0,u8_old_type = g_t_share_data.t_sys_var_cfg.s_fee_model.u8_fee_type[0]; //第一个时段的类型
*u32_part_energy = 0;
*f32_rate = 0;
*f32_sevice = 0;
//SDK协议不考虑 夸24小时(费率时间从0开始)
//计算寻找 需要的费率时段数 遍历96时段的费率类型,变更时为更新费率(注意,第一时段和最后一时段需要周期计算)
for(i=0;i<96;i++)
{
if(u8_type_cnt == flag) //费率条数 为查询的费率条数 退出寻找计算
break;
if(i!= 95 && g_t_share_data.t_sys_var_cfg.s_fee_model.u8_fee_type[i+1] != u8_old_type)
{
u8_type_cnt += 1; //费率时段数加一
u8_old_type = g_t_share_data.t_sys_var_cfg.s_fee_model.u8_fee_type[i+1];
}
}
if(u8_type_cnt == flag) //费率条数为需要查找的费率
{
*f32_rate = (float)(g_t_share_data.t_sys_var_cfg.s_fee_model.s_fee_data[u8_old_type-1].u32_rate/100000.0);
*f32_sevice = (float)(g_t_share_data.t_sys_var_cfg.s_fee_model.s_fee_data[u8_old_type-1].u32_sevice/100000.0);
for(j=i;j<96;j++)//计算该时段累计电量值
{
*u32_part_energy += t_log->u32_part_energy[j];
if(j == 95 || g_t_share_data.t_sys_var_cfg.s_fee_model.u8_fee_type[j+1] != u8_old_type)
break;
}
}
}
void v_bs_logUploadOk_updateInfo(U16_T u16_cmplte_bill_index)
{
}
#endif
#if 1 //设置 获取 联网状态
void v_bs_log_txFlag_tradUpload(U8_T u8_gunNo) //设置充电订单上送标志
{
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[u8_gunNo].txFlag_tradUpload = 1;
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[u8_gunNo].txFlag_tradUpload = 1;
}
void v_bs_log_txFlag_autoStart(U8_T u8_gunNo) //设置充电鉴权上送标志
{
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[u8_gunNo].txFlag_autoStart = 1;
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[u8_gunNo].txFlag_autoStart = 1;
s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[u8_gunNo].txFlag_autoRwsult = 0;
s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[u8_gunNo].txFlag_autoRwsult = 0;
}
/**
* ************************************************************************
* @brief - 对外输出 鉴权结果
*
* @param[in] u8_gunNo - 0-N
*
* @return U8_T - 0无 1鉴权成功 2鉴权失败
*
* @author jiankalka
* @date 2025-12-04
* ************************************************************************
*/
U8_T u8_bs_get_txFlag_autoRwsult(U8_T u8_gunNo) //对外获取鉴权结果
{
if(s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[u8_gunNo].txFlag_autoRwsult != 0)
return s_bs_task_ctrl.s_bs_ctrl[0].s_gundata[u8_gunNo].txFlag_autoRwsult;
if(s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[u8_gunNo].txFlag_autoRwsult != 0)
return s_bs_task_ctrl.s_bs_ctrl[1].s_gundata[u8_gunNo].txFlag_autoRwsult;
return 0;
}
/**
* ************************************************************************
* @brief - 联网状态获取
*
*
* @return U8_T - 0 未联网 1已经联网
*
* @author jiankalka
* @date 2025-12-04
* ************************************************************************
*/
U8_T u8_bs_get_log_on_flag()
{
if(s_bs_task_ctrl.s_bs_ctrl[0].u8_log_on_flag)
return 1;
if(s_bs_task_ctrl.s_bs_ctrl[1].u8_log_on_flag)
return 1;
return 0;
}
U8_T u8_bs_get_update_flag()
{
if(s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag ||
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag ) //远程升级
{
return 1;
}
return 0;
}
//获取枪禁用状态
U8_T u8_bs_get_gun_disable_flag(U8_T u8_gunNo)
{
U8_T u8_disable_flag = 0;
#if BS_OCPP_EN
//获取枪禁用状态
if(s_ocpp_flash_cfg_data.s_ocpp_charge_data.s8_ChangeAvailability[u8_gunNo] < 0)
{
u8_disable_flag = 1;
}
#endif
return u8_disable_flag;
}
#endif
#if 1 //充电桩控制
/**
* ************************************************************************
* @brief - 充电启停控制
*
* @param[in] u8_gunNo - 枪号
* @param[in] u8_type - 枪号 执行标志 0启动充电执行;1修改参数执行(当flag为1时,不需要修改的数据为)0xFF )
* @param[in] s_ctrl_data - 充电控制数据
*
*
* @author jiankalka
* @date 2025-11-26
* ************************************************************************
*/
void v_bs_charge_action_ctrl(U8_T u8_gunNo,E_CTRL_TYPE e_type, S_BS_CHAR_CTRL *s_ctrl_data)
{
if(e_type == E_CHAR_CTRL_START)//启动充电
{
S_CHAR_LOG_START_DATA s_log_start_data;
S_FLOW_CHARGE_CTRL_INFO e_charge_ctrl_info;
memset(&s_log_start_data , 0 ,sizeof(S_CHAR_LOG_START_DATA));
memset(&e_charge_ctrl_info , 0, sizeof(S_FLOW_CHARGE_CTRL_INFO));
//控制充电启动
e_charge_ctrl_info.e_cmd = CMD_ON;
e_charge_ctrl_info.e_start_res = (START_REASON)(s_ctrl_data->u16_ctrl_res); //启动
e_charge_ctrl_info.e_sdk_chargMode = s_ctrl_data->e_start_mode; //不做限制
e_charge_ctrl_info.u32_limit_data = s_ctrl_data->u16_limit; //限制参数 默认精度 0.01
v_flow_start_stop_ctrl(u8_gunNo,&e_charge_ctrl_info);
//控制写入订单信息
s_log_start_data.e_start_reason = (START_REASON)(s_ctrl_data->u16_ctrl_res); //启动方式
s_log_start_data.e_user_type = s_ctrl_data->e_user_type; //用户类型
s_log_start_data.u32_balance_begin = s_ctrl_data->u32_balance_begin; //启动充电前金额 0.0001元
strncpy((char *)s_log_start_data.u8_preTradeNo , (char *)s_ctrl_data->u8_preTradeNo , EVS_MAX_TRADE_LEN);
strncpy((char *)s_log_start_data.u8_tradeNo , (char *)s_ctrl_data->u8_tradeNo , EVS_MAX_TRADE_LEN);
strncpy((char *)s_log_start_data.u8_user_id , (char *)s_ctrl_data->u8_user_id , NUM_32);
v_meterlog_set_start_char_log_info(u8_gunNo,&s_log_start_data);
}
else if(e_type == E_CHAR_CTRL_STOP)//停止充电
{
S_FLOW_CHARGE_CTRL_INFO e_charge_ctrl_info;
memset(&e_charge_ctrl_info , 0, sizeof(S_FLOW_CHARGE_CTRL_INFO));
e_charge_ctrl_info.e_cmd = CMD_OFF;
e_charge_ctrl_info.e_stop_res = (E_FAULT_INFO)(s_ctrl_data->u16_ctrl_res); //停止
v_flow_start_stop_ctrl(u8_gunNo,&e_charge_ctrl_info);
v_meterlog_set_stop_char_log_info(u8_gunNo , s_ctrl_data->u16_ctrl_res);
}
else //修改数据
{
if(s_ctrl_data->u8_preTradeNo[0] != 0xFF)
v_meterlog_set_char_log_info(u8_gunNo,E_METERLOG_SET_LOG_INFO_char_preTradeNo, NULL,&s_ctrl_data->u8_preTradeNo[0]); //平台交易流水号
if(s_ctrl_data->u8_tradeNo[0] != 0xFF)
v_meterlog_set_char_log_info(u8_gunNo,E_METERLOG_SET_LOG_INFO_char_tradeNo, NULL,&s_ctrl_data->u8_tradeNo[0]); //设备交易流水号
//用户类型
if((s_ctrl_data->e_user_type&0xFF) != 0xFF)
v_meterlog_set_char_log_info(u8_gunNo,E_METERLOG_SET_LOG_INFO_u32_user_type,(U32_T *)&s_ctrl_data->e_user_type,NULL);
//用户标识
if(s_ctrl_data->u8_user_id[0] != 0xFF)
v_meterlog_set_char_log_info(u8_gunNo,E_METERLOG_SET_LOG_INFO_char_user_id,NULL,&s_ctrl_data->u8_user_id[0]);
//卡内或账户余额
if((s_ctrl_data->u32_balance_begin&0xFF) != 0xFF)
v_meterlog_set_char_log_info(u8_gunNo,E_METERLOG_SET_LOG_INFO_u32_balance_begin,(U32_T *)&s_ctrl_data->u32_balance_begin,NULL);
}
}
/**
* ************************************************************************
* @brief - 平台下发接枪锁动作
*
* @param[in] u8_gunNo - 枪号
* @param[in] u8_type - 类型 0解锁 1上锁
*
*
* @author jiankalka
* @date 2025-11-26
* ************************************************************************
*/
void v_remote_gunLock_ctrl(U8_T u8_gunNo,U8_T u8_type)
{
}
/***************************************************
函数功能: 平台下发远程重启命令
输入参数: U8_T type 重启类型 0软重启 1硬重启
输出参数:
****************************************************/
void v_remote_reboot(U8_T type) //平台下发远程重启命令
{
if(type == 0){
v_sys_reboot();
}
else{
//Sleep(1000);
//v_oprt_yk(YK_RESTART_ON); //硬重
}
return;
}
#endif
/**
* ************************************************************************
* @brief - 添加卡号
*
* @param[in] card_id -
*
* @return U8_T -
*
* @author jiankalka
* @date 2026-01-16
* ************************************************************************
*/
U8_T u8_card_info_add(char *card_id)
{
#if FATFS_ENABLE_CARD
U32_T u32_balance = 5000;
U8_T ret = cache_add_card(card_id, u32_balance);
return ret ? 1 : 0; /* 0成功 1失败 */
#else
CardInfo card_info = {0};
CardStatus status;
if (card_id == NULL || card_id[0] == '\0') {
return 1;
}
if (u8_card_storage_ready() == 0) {
return 1;
}
strncpy(card_info.card_num, card_id, CARD_NUM_MAX_LEN - 1);
card_info.card_num[CARD_NUM_MAX_LEN - 1] = '\0';
card_info.balance = 5000;
card_info.status = 1;
status = card_add(&card_info);
return (status == CARD_STATUS_OK || status == CARD_STATUS_CARD_EXIST) ? 0 : 1;
#endif
}
/**
* ************************************************************************
* @brief - 清空卡号
*
*
*
* @author jiankalka
* @date 2026-01-16
* ************************************************************************
*/
void v_card_info_clear(void)
{
#if FATFS_ENABLE_CARD
card_clear_all();
#else
if (u8_card_storage_ready() == 1) {
(void)card_clear_all();
}
#endif
}
/**
* ************************************************************************
* @brief - ftp 升级动作
*
*
*
* @author jiankalka
* @date 2025-11-29
* ************************************************************************
*/
void v_ftp_update_action()
{
if(t_ftp_update_info.u8_init_flag == 0)
{
/* 根据网络类型初始化:
- 0: 4G 模块,通过 v_ftp_ctrl_init() 完成 AT 配置
- 1: 网线(LwIP),不需要 4G AT 初始化 */
if (t_ftp_update_info.u8_netType == 0) {
#if EC200A_4G_EN
v_ftp_ctrl_init();
#endif
}
#if LWIP_FTP_UPGRADE_ENABLE
else{
/* 首次进入网线升级:初始化状态机 */
lwip_ftp_upgrade_init_from_tftp();
}
#endif
t_ftp_update_info.u8_init_flag = 1;
}
#if BS_OCPP_EN
if(s_bs_task_ctrl.ocpp_data.u8_log_file_upload == 1) //上传日志文件标志置一
{
/* 日志上传:
- 目前仅在 4G 模块链路上使用 u8_ec200a_4g_ftp_log_upload()
- 网线 LwIP 通道的日志上传暂未实现,如有需要可参考 4G 流程扩展 */
if (t_ftp_update_info.u8_netType == 0) {
#if EC200A_4G_EN
u8_ec200a_4g_ftp_log_upload(); // 4G 模块日志上传
#endif
} else {
BS_PUBLIC_PRINTF_LOG("lwip ftp: log upload not implemented, netType=%d — clear flags\r\n",
t_ftp_update_info.u8_netType);
#if BS_OCPP_EN
v_ocpp_set_diag_upload_notify_pending(OCPP_DIAG_NOTIFY_PENDING_UPLOAD_FAILED);
#endif
/* 否则 Plat_Comm 永久停在 u8_updata_flag 分支,OCPP 无后续收发 */
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0;
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0;
s_bs_task_ctrl.ocpp_data.u8_log_file_upload = 0;
}
}
else
#endif
{
/* 固件下载(程序升级):
- 4G:沿用原有 u8_ec200a_4g_ftp_update(),内部状态机+AT命令
- 网线(LwIP):走 lwip_ftp_upgrade_step(),状态机按周期推进,避免阻塞 v_Plat_Comm */
if (t_ftp_update_info.u8_netType == 0) {
#if EC200A_4G_EN
u8_ec200a_4g_ftp_update(); // 4G 模块远程升级流程
#endif
}
#if LWIP_FTP_UPGRADE_ENABLE
else {
/* LwIP FTP:使用状态机,每次仅推进一小步 */
int ret = lwip_ftp_upgrade_step();
if (ret == 1) {
/* 升级成功:清远程升级标志,设置结果 */
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0;
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0;
t_ftp_update_info.u8_update_result = 0;
BS_PUBLIC_PRINTF_LOG("lwip ftp: fw upgrade done ok, size=%lu\r\n",
(unsigned long)t_ftp_update_info.u32_file_size);
} else if (ret < 0) {
/* 升级失败:清远程升级标志,设置结果为失败 */
s_bs_task_ctrl.s_bs_ctrl[0].u8_updata_flag = 0;
s_bs_task_ctrl.s_bs_ctrl[1].u8_updata_flag = 0;
t_ftp_update_info.u8_update_result = 1;
BS_PUBLIC_PRINTF_LOG("lwip ftp: fw upgrade fail, ret=%d\r\n", ret);
}
}
#endif
}
}
/**
* ************************************************************************
* @brief - 获取未结算订单信息
*
* @param[in] u8_type 0 获取订单信息且查数量 1仅查数量
* s_log - 未结算订单数据地址
*
* @return U8_T - 0 没有为结算订单 >0 存在未结算订单 且为未结算订单数量
*
* @author jiankalka
* @date 2026-01-19
* ************************************************************************
*/
S8_T s8_plat_get_unsettled_order( S_LOG_DATA *s_log,U8_T u8_type)
{
S8_T unsettledCount = 0;
U32_T unsettledIndexes[UNSETTLED_MAX_CNT]; // 3字节压缩存储
U8_T i;
if (s_log == NULL)
{
return 0;
}
//先检查掉电存储订单
for (i = 0; i < GUN_MAX_CNT; i++)
{
#if BS_OCPP_EN
/* 充电中 EEPROM 为周期快照(TEMP_CHG_FLAG_UNSETTLED),非掉电未结单 */
if (u8_bs_get_flow_state(i) == 2u) {
continue;
}
#endif
if(v_check_temp_chg_record_valid(i) == 1) //有有效记录
{
unsettledCount = v_read_temp_chg_record_from_eeprom(i,s_log,NULL);//获取订单信息
#if BS_OCPP_EN
if (u8_ocpp_unsettled_is_live_charging_session(s_log) != 0U) {
continue;
}
if (u8_ocpp_skip_unsettled_stop_for_live_tx(s_log) != 0U) {
v_clear_temp_chg_record_in_eeprom(i);
continue;
}
#endif
s_log->e_stop_reason[0] = E_FAULT_13073; //异常掉电
BS_PUBLIC_PRINTF_LOG("Load pwr-loss order gun=%u txId=%s\r\n",
(unsigned)i, (char *)s_log->u8_preTradeNo);
v_clear_temp_chg_record_in_eeprom(i); //清楚记录
return 1; //存在为结算订单
}
}
// 获取未结算订单数量
unsettledCount = u16_get_unsettled_order_count();
if (unsettledCount == 0)
{
return 0;
}
if(u8_type == 1) //仅查数量
{
return unsettledCount;
}
// 获取未结算订单索引列表
v_get_unsettled_order_indexes(unsettledIndexes, (U16_T *)&unsettledCount);
{
U32_T currentIndex = unsettledIndexes[0];
#if BS_OCPP_EN
U16_T ui;
/* 优先处理 Flash 中仍有离线 MV 待补发的订单,避免先结旧单而跳过本笔离线采样 */
for (ui = 0U; ui < (U16_T)unsettledCount; ui++) {
S_LOG_DATA probe;
(void)memset(&probe, 0, sizeof(probe));
if (v_read_chg_order_record(&probe, unsettledIndexes[ui]) != 0U) {
continue;
}
if (u8_ocpp_mv_offline_map_pending_for_log(&probe) != 0U) {
currentIndex = unsettledIndexes[ui];
BS_PUBLIC_PRINTF_LOG("Unsettled: pick idx=%u (offline MV pending)\r\n",
currentIndex);
break;
}
}
#endif
/* 仅从 Flash 读出订单;勿在此 u8_platform_settlement_confirm —— 须 StopTransaction 上送成功后再删未结索引 */
U8_T readResult = v_read_chg_order_record(s_log, currentIndex);
if (readResult != 0)
{
BS_PUBLIC_PRINTF_LOG("Unsettled: read fail, idx=%u\n", currentIndex);
mSleep(100);
return -1;
}
BS_PUBLIC_PRINTF_LOG("Unsettled: read ok, idx=%u\n", currentIndex);
}
return unsettledCount;
}
/**
* ************************************************************************
* @brief - 平台结算确认接口封装
*
*
* @param[in] u8_gunNo - 订单上送确认枪号
*
* @author jiankalka
* @date 2026-01-20
* ************************************************************************
*/
void v_bs_platform_settlement_confirm(U8_T u8_gunNo)
{
S_LOG_DATA s_log;
memset(&s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息
U32_T orderIndex = s_log.u32_index;
U8_T ret = u8_platform_settlement_confirm(orderIndex);
if(ret == 0){} //成功
}
/**
* ************************************************************************
* @brief - 获取实时订单信息
*
* @param[in] s_log - 订单信息
* @param[in] u8_gunNo - 抢号 0-1
*
* @return U8_T - 0失败 1成功
*
* @author jiankalka
* @date 2026-01-21
* ************************************************************************
*/
U8_T u8_plat_get_real_order(S_LOG_DATA *s_log,U8_T u8_gunNo)
{
if(s_log == NULL)
return 0;
memset(s_log , 0 ,sizeof(S_LOG_DATA));
v_meterlog_put_char_log_data(u8_gunNo,s_log); //获取订单信息
return 1;
}
#if BS_OCPP_EN
const char *HeartbeatInterval = "HeartbeatInterval";
const char *MeterValueSampleInterval = "MeterValueSampleInterval";
const char *chargePointVendor = "chargePointVendor";
/**
* ************************************************************************
* @brief -离线本地鉴权检查
*
*
*
* @author jiankalka
* @date 2026-01-20
* ************************************************************************
*/
void v_ocpp_offline_local_authentication_check(U8_T u8_gunNo)
{
U8_T bs_id = s_bs_task_ctrl.ocpp_data.id;
char u8_str_data[BS_BUF_SIZE_64] = {0};
CardInfo card_info;
s_bs_task_ctrl.ocpp_data.s_timerCnt[OCPP_TIMER_Authorize_GUNA+u8_gunNo].u16_timeNUM = 10; //秒
s_bs_task_ctrl.ocpp_data.s_timerCnt[OCPP_TIMER_Authorize_GUNA+u8_gunNo].u16_timerCnt = \
s_bs_task_ctrl.ocpp_data.s_timerCnt[OCPP_TIMER_Authorize_GUNA+u8_gunNo].u16_timeNUM;//ocpp平台 设置 发送周期 鉴权报文发送周期
if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_LocalAuthListEnabled == 1) // ! 是否启用本地授权列表
{
u8_get_str_data(u8_gunNo,E_STR_LOG_user_id,0,u8_str_data,BS_BUF_SIZE_64); //获取用户ID
if(s_bs_task_ctrl.s_bs_ctrl[bs_id].u8_log_on_flag) //在线
{
if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_LocalPreAuthorize == 1) // !在线时是否无需等待中央系统授权即可本地启动交易
{
/* 本地鉴权 并直接返回结果 */
#if FATFS_ENABLE_CARD
if (u8_card_find_with_retry(u8_str_data, &card_info)) {
BS_PUBLIC_PRINTF_LOG("Local auth ok %s\n",u8_str_data);
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
} else {
BS_PUBLIC_PRINTF_LOG("Local auth fail %s\n",u8_str_data);
}
#else
if (u8_card_storage_ready() == 1) {
if (u8_card_find_with_retry(u8_str_data, &card_info)) {
BS_PUBLIC_PRINTF_LOG("Local auth ok %s\n",u8_str_data);
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
} else {
BS_PUBLIC_PRINTF_LOG("Local auth fail %s\n",u8_str_data);
}
} else {
BS_PUBLIC_PRINTF_LOG("Local auth skipped: card storage init failed\r\n");
}
#endif
}
}
else //离线
{
if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_LocalAuthorizeOffline == 1) // ! 离线时是否允许本地授权启动交易
{
/* 本地鉴权 并直接返回结果 */
#if FATFS_ENABLE_CARD
if (u8_card_find_with_retry(u8_str_data, &card_info))
{
BS_PUBLIC_PRINTF_LOG("Offline local auth ok %s\n",u8_str_data);
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
}
else
{
BS_PUBLIC_PRINTF_LOG("Offline local auth fail %s, allowUnknown=%d\n",u8_str_data,s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_AllowOfflineTxForUnknownId);
if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_AllowOfflineTxForUnknownId == 1) //! 是否允许未知ID用户离线启动交易 -离线时直接启动不鉴权
{
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
}
}
#else
if (u8_card_storage_ready() == 1) {
if (u8_card_find_with_retry(u8_str_data, &card_info))
{
BS_PUBLIC_PRINTF_LOG("Offline local auth ok %s\n",u8_str_data);
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
}
else
{
BS_PUBLIC_PRINTF_LOG("Offline local auth fail %s, allowUnknown=%d\n",u8_str_data,s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_AllowOfflineTxForUnknownId);
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 2;
if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_AllowOfflineTxForUnknownId == 1) //! 是否允许未知ID用户离线启动交易 -离线时直接启动不鉴权
{
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0; //无需再去鉴权了
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1; //鉴权成功
}
}
} else if(s_ocpp_flash_cfg_data.s_ocpp_config_data.u8_AllowOfflineTxForUnknownId == 1) {
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoStart = 0;
s_bs_task_ctrl.s_bs_ctrl[bs_id].s_gundata[u8_gunNo].txFlag_autoRwsult = 1;
} else {
BS_PUBLIC_PRINTF_LOG("Offline local auth: card storage init failed\r\n");
}
#endif
}
}
}
}
/**
* ************************************************************************
* @brief - 获取OCPP 配置信息 - 将相关配置信息 赋值到字符串中
*
* @param[in] mag - 字符串地址
* @param[in] u16_len - 字符串缓存长度
*
*
* @author jiankalka
* @date 2026-01-22
* ************************************************************************
*/
void v_get_ocpp_cfg_info(char *mag , U16_T u16_len)
{
U16_T u16_index = 0;
memset(mag , 0 , u16_len);
u16_index += snprintf(&mag[u16_index],u16_len,"cardVer=%d&&ChangeAvailability=%d,%d&&",
s_ocpp_flash_cfg_data.s_ocpp_charge_data.card_ver,
s_ocpp_flash_cfg_data.s_ocpp_charge_data.s8_ChangeAvailability[0],
s_ocpp_flash_cfg_data.s_ocpp_charge_data.s8_ChangeAvailability[1]);
u16_index += snprintf(&mag[u16_index],u16_len,"%s=%d&&%s=%d&&",
HeartbeatInterval,
s_ocpp_flash_cfg_data.s_ocpp_config_data.u16_HeartbeatInterval,
MeterValueSampleInterval,
s_ocpp_flash_cfg_data.s_ocpp_config_data.u16_MeterValueSampleInterval);
u16_index += snprintf(&mag[u16_index],u16_len,"%s=%s&&",chargePointVendor,
s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor);
}
/**
* ************************************************************************
* @brief - 设置信息
*
* @param[in] key - 关键字
* @param[in] data - 数据内容
*
* @return U8_T - 1成功 0失败
*
* @author jiankalka
* @date 2026-01-22
* ************************************************************************
*/
U8_T u8_set_ocpp_cfg_info(const char *key,const char *data)
{
U8_T u8_ret = 0;
#if 1
if(strcmp(key , HeartbeatInterval) == 0)
{
//将字符串转化为整数
int res_data = atoi(data);
//判断有效性
if(res_data < 0 || res_data > 0xffff)
{
return u8_ret;
}
//赋值
s_ocpp_flash_cfg_data.s_ocpp_config_data.u16_HeartbeatInterval = res_data;
u8_ret = 1;
}
else if(strcmp(key , MeterValueSampleInterval) == 0)
{
//将字符串转化为整数
int res_data = atoi(data);
//判断有效性
if(res_data < 0 || res_data > 0xffff)
{
return u8_ret;
}
//赋值
s_ocpp_flash_cfg_data.s_ocpp_config_data.u16_MeterValueSampleInterval = res_data;
u8_ret = 1;
}
else if(strcmp(key , chargePointVendor) == 0)
{
memset(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor,0,sizeof(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor));
strncpy(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor,data,sizeof(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor)-1);
u8_ret = 1;
}
#endif
return u8_ret;
}
/**
* ************************************************************************
* @brief - 获取当前实时文件名称
*
* @param[in] fileName -
* @param[in] len -
*
*
* @author jiankalka
* @date 2026-01-22
* ************************************************************************
*/
void v_ocpp_get_real_log_file_name(char *fileName,int len)
{
#if FATFS_EN
v_app_fatfs_log_real_file_name(fileName,len,0);
#else
(void)fileName; (void)len;
#endif
}
//设置充电枪状态初始化
void v_ocpp_set_gun_flow_real_state_init(U8_T u8_gunNo)
{
v_flow_set_gun_flow_real_state_init(u8_gunNo);
}
#endif