#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 :当前SOC;type=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 :当前SOC;type=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 充电中 { 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