#include "BS_ocpp_configuration.h" #include "plat_comm/plat_comm_task.h" #include "bsp_include.h" #include "publicdata/publicdata.h" #include "app_fatfs/fatfs_card.h" #define OCPP_CONFIG_PRINTF_LOG(fmt, ...) \ MYLOG_MSG(OCPP_PRINT_FLAG,fmt, ##__VA_ARGS__) //任务打印 #if BS_OCPP_EN S_OCPP_FLASH_CFG_DATA s_ocpp_flash_cfg_data; OCPP_CONFIG *private_config_data = &s_ocpp_flash_cfg_data.s_ocpp_config_data; //内部指针引用,初始化时赋值全局变量的值 //保存unknown的Key串 char *unknown_tmpbuf[GetConfiguration_NUM] = {NULL}; static const char *phase_to_str(OCPP_CONNECTOR_PHASE phase) { switch (phase) { case ENUM_NotApplicable: return "NotApplicable"; case ENUM_Unknown: return "Unknown"; case ENUM_RST: return "RST"; case ENUM_RTS: return "RTS"; case ENUM_SRT: return "SRT"; case ENUM_STR: return "STR"; case ENUM_TRS: return "TRS"; case ENUM_TSR: return "TSR"; default: return "NotApplicable"; } } static U8_T str_to_phase(const char *value, OCPP_CONNECTOR_PHASE *phase) { if (value == NULL || phase == NULL) return 0; if (strcmp(value, "0") == 0 || strcmp(value, "NotApplicable") == 0) { *phase = ENUM_NotApplicable; return 1; } if (strcmp(value, "1") == 0 || strcmp(value, "Unknown") == 0) { *phase = ENUM_Unknown; return 1; } if (strcmp(value, "RST") == 0) { *phase = ENUM_RST; return 1; } if (strcmp(value, "RTS") == 0) { *phase = ENUM_RTS; return 1; } if (strcmp(value, "SRT") == 0) { *phase = ENUM_SRT; return 1; } if (strcmp(value, "STR") == 0) { *phase = ENUM_STR; return 1; } if (strcmp(value, "TRS") == 0) { *phase = ENUM_TRS; return 1; } if (strcmp(value, "TSR") == 0) { *phase = ENUM_TSR; return 1; } return 0; } static U8_T extract_phase_item(const char *src, char index, char *out, U16_T out_len) { char pattern[4] = {0}; const char *start; U16_T i = 0; if (src == NULL || out == NULL || out_len == 0) return 0; pattern[0] = index; pattern[1] = '.'; pattern[2] = '\0'; start = strstr(src, pattern); if (start == NULL) return 0; start += 2; while (*start && *start != ',' && i < (out_len - 1)) { out[i++] = *start++; } out[i] = '\0'; return (i > 0) ? 1 : 0; } static U8_T parse_connector_phase_rotation(const char *value, OCPP_CONNECTOR_PHASE phase_out[3], const OCPP_CONNECTOR_PHASE phase_curr[3]) { OCPP_CONNECTOR_PHASE p0 = phase_curr[0]; OCPP_CONNECTOR_PHASE p1 = phase_curr[1]; OCPP_CONNECTOR_PHASE p2 = phase_curr[2]; char v0[24] = {0}; char v1[24] = {0}; char v2[24] = {0}; U8_T has_indexed = 0; has_indexed |= extract_phase_item(value, '0', v0, sizeof(v0)); has_indexed |= extract_phase_item(value, '1', v1, sizeof(v1)); has_indexed |= extract_phase_item(value, '2', v2, sizeof(v2)); if (has_indexed) { if ((v0[0] != '\0' && str_to_phase(v0, &p0) == 0) || (v1[0] != '\0' && str_to_phase(v1, &p1) == 0) || (v2[0] != '\0' && str_to_phase(v2, &p2) == 0)) { return 0; } phase_out[0] = p0; phase_out[1] = p1; phase_out[2] = p2; return 1; } if (str_to_phase(value, &p1) == 0) return 0; phase_out[0] = p1; phase_out[1] = p1; phase_out[2] = p1; return 1; } /** 去掉字符串首尾空格/制表(就地) */ static void str_trim_inplace(char *s) { size_t len; size_t start = 0; if (s == NULL || s[0] == '\0') return; len = strlen(s); while (start < len && (s[start] == ' ' || s[start] == '\t')) start++; if (start > 0) memmove(s, s + start, len - start + 1); len = strlen(s); while (len > 0 && (s[len - 1] == ' ' || s[len - 1] == '\t' || s[len - 1] == '\r' || s[len - 1] == '\n')) s[--len] = '\0'; } /** 逗号分隔 CSL 中与 measurand 完全一致的 token 是否存在(避免 strstr 子串误匹配,如 Current.Import 命中 Current.Offered) */ static U8_T meter_values_csl_has_token(const char *value_csl, const char *measurand_str) { const char *p; char token[160]; U16_T ti; if (value_csl == NULL || measurand_str == NULL || measurand_str[0] == '\0') return 0; p = value_csl; while (*p != '\0') { while (*p == ' ' || *p == '\t') p++; ti = 0; while (*p != '\0' && *p != ',' && ti + 1 < sizeof(token)) token[ti++] = *p++; token[ti] = '\0'; str_trim_inplace(token); if (token[0] != '\0' && strcmp(token, measurand_str) == 0) return 1; if (*p == ',') p++; } return 0; } /** 统计逗号分隔列表中非空 token 数量(去首尾空格后) */ static U16_T meter_values_csl_count_nonempty_tokens(const char *value_csl) { const char *p; char token[160]; U16_T ti; U16_T n = 0; if (value_csl == NULL) return 0; p = value_csl; while (*p != '\0') { while (*p == ' ' || *p == '\t') p++; ti = 0; while (*p != '\0' && *p != ',' && ti + 1 < sizeof(token)) token[ti++] = *p++; token[ti] = '\0'; str_trim_inplace(token); if (token[0] != '\0') n++; if (*p == ',') p++; } return n; } // MeterValues测量项 串数组(标准字符串 只读不可修改。顺序对应枚举顺序,固定不可变更) const char *OCPP_measurand_str[] = { // ------------------- 能量累计类(Register)- 文档7.31 核心计费累计项 ------------------- /*{ENUM_EnergyActiveExportRegister, */OCPP_STR_EnergyActiveExportRegister ,//}, /*{ENUM_EnergyActiveImportRegister, */OCPP_STR_EnergyActiveImportRegister ,//}, /*{ENUM_EnergyReactiveExportRegister, */OCPP_STR_EnergyReactiveExportRegister ,//}, /*{ENUM_EnergyReactiveImportRegister, */OCPP_STR_EnergyReactiveImportRegister ,//}, // ------------------- 能量时段类(Interval)- 文档7.31 时钟对齐时段项 ------------------- /*{ENUM_EnergyActiveExportInterval, */OCPP_STR_EnergyActiveExportInterval ,//}, /*{ENUM_EnergyActiveImportInterval, */OCPP_STR_EnergyActiveImportInterval ,//}, /*{ENUM_EnergyReactiveExportInterval, */OCPP_STR_EnergyReactiveExportInterval ,//}, /*{ENUM_EnergyReactiveImportInterval, */OCPP_STR_EnergyReactiveImportInterval ,//}, // ------------------- 功率类 - 文档7.31 实时功率监控项 ------------------- /*{ENUM_PowerActiveExport, */OCPP_STR_PowerActiveExport ,//}, /*{ENUM_PowerActiveImport, */OCPP_STR_PowerActiveImport ,//}, /*{ENUM_PowerOffered, */OCPP_STR_PowerOffered ,//}, /*{ENUM_PowerReactiveExport, */OCPP_STR_PowerReactiveExport ,//}, /*{ENUM_PowerReactiveImport, */OCPP_STR_PowerReactiveImport ,//}, /*{ENUM_PowerFactor, */OCPP_STR_PowerFactor ,//}, // ------------------- 电流类 - 文档7.31 实时电流监控项 ------------------- /*{ENUM_CurrentImport, */OCPP_STR_CurrentImport ,//}, /*{ENUM_CurrentExport, */OCPP_STR_CurrentExport ,//}, /*{ENUM_CurrentOffered, */OCPP_STR_CurrentOffered ,//}, // ------------------- 电气参数类 - 文档7.31 基础电气特性项 ------------------- /*{ENUM_Voltage, */OCPP_STR_Voltage ,//}, /*{ENUM_Frequency, */OCPP_STR_Frequency ,//}, // ------------------- 物理/状态量类 - 文档7.31 非电气计量项 ------------------- /*{ENUM_Temperature, */OCPP_STR_Temperature ,//}, /*{ENUM_SoC, */OCPP_STR_SOC ,//}, /*{ENUM_RPM, */OCPP_STR_RPM ,//}, }; //OCPP可配置参数结构体数组 const OCPP_CONFIG_INFO OCPP_config_info[] = { {ENUM_NULL, ENUM_SUPPORT_NOT, ENUM_TYPE_INT, "NULL"}, // -------------------------------------------------------- // 核心配置参数(数据类型与功能说明) // -------------------------------------------------------- {ENUM_ALLOW_OFFLINE_TX_FOR_UNKNOWN_ID, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_ALLOW_OFFLINE_TX_FOR_UNKNOWN_ID}, /* 可选 允许未知用户ID的离线交易 (布尔: 0/1) */ {ENUM_AUTHORIZATION_CACHE_ENABLED, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_AUTHORIZATION_CACHE_ENABLED}, /* 可选 启用本地授权缓存 (布尔: 0/1) */ {ENUM_AUTHORIZE_REMOTE_TX_REQUESTS, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_AUTHORIZE_REMOTE_TX_REQUESTS}, /* 必选 允许远程启动充电事务 (布尔: 0/1) */ {ENUM_BLINK_REPEAT, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_BLINK_REPEAT}, /* 可选 充电桩指示灯闪烁次数 (整数: 次数) */ {ENUM_CLOCK_ALIGNED_DATA_INTERVAL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CLOCK_ALIGNED_DATA_INTERVAL}, /* 必选 时钟对齐的数据上报间隔 (整数: 秒) */ {ENUM_CONNECTION_TIME_OUT, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CONNECTION_TIMEOUT}, /* 必选 TCP连接超时时间 (整数: 秒) */ {ENUM_CONNECTOR_PHASE_ROTATION, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_CONNECTOR_PHASE_ROTATION}, /* 必选 连接器相位旋转配置 (字符串: L1/L2/L3顺序) */ {ENUM_CONNECTOR_PHASE_ROTATION_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CONNECTOR_PHASE_ROTATION_MAX_LENGTH}, /* 可选 相位旋转配置最大长度 (整数: 字节数) */ {ENUM_GET_CONFIGURATION_MAX_KEYS, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_GET_CONFIGURATION_MAX_KEYS}, /* 必选 GetConfiguration请求最大返回Key数 (整数: 数量) */ {ENUM_HEARTBEAT_INTERVAL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_HEARTBEAT_INTERVAL}, /* 必选 心跳间隔 (整数: 秒) */ {ENUM_LIGHT_INTENSITY, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_LIGHT_INTENSITY}, /* 可选 充电桩灯光亮度 (整数: 百分比) */ {ENUM_LOCAL_AUTHORIZE_OFFLINE, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_LOCAL_AUTHORIZE_OFFLINE}, /* 必选 本地离线授权模式 (布尔: 0/1) */ {ENUM_LOCAL_PRE_AUTHORIZE, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_LOCAL_PRE_AUTHORIZE}, /* 必选 本地预授权模式 (布尔: 0/1) */ {ENUM_MAX_ENERGY_ON_INVALID_ID, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_MAX_ENERGY_ON_INVALID_ID}, /* 可选 无效ID用户的最大允许充电能量 (整数: Wh) */ {ENUM_METER_VALUES_ALIGNED_DATA, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_METER_VALUES_ALIGNED_DATA}, /* 必选 对齐数据上报的测量项列表 (字符串: 逗号分隔的measurand值) */ {ENUM_METER_VALUES_ALIGNED_DATA_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_METER_VALUES_ALIGNED_DATA_MAX_LENGTH}, /* 可选 对齐数据列表最大长度 (整数: 字符数) */ {ENUM_METER_VALUES_SAMPLED_DATA, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_METER_VALUES_SAMPLED_DATA}, /* 必选 采样数据上报的测量项列表 (字符串: 逗号分隔的measurand值) */ {ENUM_METER_VALUES_SAMPLED_DATA_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_METER_VALUES_SAMPLED_DATA_MAX_LENGTH}, /* 可选 采样数据列表最大长度 (整数: 字符数) */ {ENUM_METER_VALUE_SAMPLE_INTERVAL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_METER_VALUE_SAMPLE_INTERVAL}, /* 必选 采样间隔 (整数: 秒) */ {ENUM_MINIMUM_STATUS_DURATION, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_MINIMUM_STATUS_DURATION}, /* 可选 状态最小持续时间 (整数: 秒) */ {ENUM_NUMBER_OF_CONNECTORS, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_NUMBER_OF_CONNECTORS}, /* 必选 充电桩连接器数量 (整数: 数量) */ {ENUM_RESET_RETRIES, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_RESET_RETRIES}, /* 必选 复位重试次数 (整数: 次数) */ {ENUM_STOP_TRANSACTION_ON_EV_SIDE_DISCONNECT, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_STOP_TXN_ON_EV_SIDE_DISCONNECT}, /* 必选 EV端断开时停止事务 (布尔: 0/1) */ {ENUM_STOP_TRANSACTION_ON_INVALID_ID, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_STOP_TXN_ON_INVALID_ID}, /* 必选 无效ID时停止事务 (布尔: 0/1) */ {ENUM_STOP_TXN_ALIGNED_DATA, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_STOP_TXN_ALIGNED_DATA}, /* 必选 事务停止时的对齐数据项 (字符串: 逗号分隔的measurand值) */ {ENUM_STOP_TXN_ALIGNED_DATA_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_STOP_TXN_ALIGNED_DATA_MAX_LENGTH}, /* 可选 停止事务对齐数据最大长度 (整数: 字符数) */ {ENUM_STOP_TXN_SAMPLED_DATA, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_STOP_TXN_SAMPLED_DATA}, /* 必选 停止事务时的采样数据项 (字符串: 逗号分隔的measurand值) */ {ENUM_STOP_TXN_SAMPLED_DATA_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_STOP_TXN_SAMPLED_DATA_MAX_LENGTH}, /* 可选 停止事务采样数据最大长度 (整数: 字符数) */ {ENUM_SUPPORTED_FEATURE_PROFILES, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_SUPPORTED_FEATURE_PROFILES}, /* 必选 支持的功能配置文件 (字符串: 逗号分隔的FeatureProfile值) */ {ENUM_SUPPORTED_FEATURE_PROFILES_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_SUPPORTED_FEATURE_PROFILES_MAX_LENGTH}, /* 可选 功能配置文件列表最大长度 (整数: 字符数) */ {ENUM_TRANSACTION_MESSAGE_ATTEMPTS, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_TRANSACTION_MESSAGE_ATTEMPTS}, /* 必选 事务消息重试次数 (整数: 次数) */ {ENUM_TRANSACTION_MESSAGE_RETRY_INTERVAL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_TRANSACTION_MESSAGE_RETRY_INTERVAL}, /* 必选 事务消息重试间隔 (整数: 秒) */ {ENUM_UNLOCK_CONNECTOR_ON_EV_SIDE_DISCONNECT, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_UNLOCK_CONNECTOR_ON_EV_DISCONNECT}, /* 必选 EV端断开时解锁连接器 (布尔: 0/1) */ {ENUM_WEB_SOCKET_PING_INTERVAL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_WEBSOCKET_PING_INTERVAL}, /* 可选 WebSocket Ping间隔 (整数: 秒) */ // -------------------------------------------------------- // 本地授权与充电配置管理 // -------------------------------------------------------- {ENUM_LOCAL_AUTH_LIST_ENABLED, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_LOCAL_AUTH_LIST_ENABLED}, /* 必选 启用本地授权列表 (布尔: 0/1) */ {ENUM_LOCAL_AUTH_LIST_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_LOCAL_AUTH_LIST_MAX_LENGTH}, /* 必选 本地授权列表的最大条目数 (整数) */ {ENUM_SEND_LOCAL_LIST_MAX_LENGTH, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_SEND_LOCAL_LIST_MAX_LENGTH}, /* 必选 发送本地列表的最大条目数 (整数) */ // -------------------------------------------------------- // 连接器与充电行为控制 // -------------------------------------------------------- {ENUM_RESERVE_CONNECTOR_ZERO_SUPPORTED, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_RESERVE_CONNECTOR_ZERO_SUPPORTED}, /* 可选 是否支持预留连接器0 (布尔: 0/1) */ // -------------------------------------------------------- // 充电计划与配置限制 // -------------------------------------------------------- {ENUM_CHARGE_PROFILE_MAX_STACK_LEVEL, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CHARGE_PROFILE_MAX_STACK_LEVEL}, /* 必选 充电配置最大堆叠层级 (整数) */ {ENUM_CHARGING_SCHEDULE_ALLOWED_RATE_UNIT, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_CHARGING_SCHEDULE_ALLOWED_RATE_UNIT}, /* 必选 充电速率允许单位 (字符串: "A"或"W") */ {ENUM_CHARGING_SCHEDULE_MAX_PERIODS, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CHARGING_SCHEDULE_MAX_PERIODS}, /* 必选 充电计划最大时段数 (整数) */ {ENUM_CONNECTOR_SWITCH_3TO1_PHASE_SUPPORTED, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_CONNECTOR_SWITCH_3TO1_PHASE_SUPPORTED}, /* 可选 是否支持三相切单相充电 (布尔: 0/1) */ {ENUM_MAX_CHARGING_PROFILES_INSTALLED, ENUM_SUPPORT_YES, ENUM_TYPE_INT, KEY_MAX_CHARGING_PROFILES_INSTALLED}, /* 必选 最大可安装充电配置数 (整数) */ // -------------------------------------------------------- // 各平台私有配置 // -------------------------------------------------------- {ENUM_QRCODE_TEXT_CONNECTOR1, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_QRCODE_TEXT_CONNECTOR1}, /* 枪1二维码 */ {ENUM_QRCODE_TEXT_CONNECTOR2, ENUM_SUPPORT_YES, ENUM_TYPE_CSL, KEY_QRCODE_TEXT_CONNECTOR2}, /* 枪2二维码 */ }; /******************************************************************************* * 名称: u8_find_OCPP_configID * 功能: 根据字符串查找对应OCPP配置参数的枚举变量 * 参数: *mag OCPP配置参数的键的字符串 * 返回: 返回该键在OCPP_CONFIG_KEY_ID的对应枚举量,若返回ENUM_NULL则未找到该键 * 说明: ******************************************************************************/ OCPP_CONFIG_KEY_ID u8_find_OCPP_configID(const char *mag) { if(mag == NULL) return ENUM_NULL; OCPP_CONFIG_KEY_ID ret = ENUM_NULL; for(U8_T i = 1; i < ENUM_OCPP_CONFIG; i++) { if(strcmp(OCPP_config_info[i].str_data, mag) == 0) { ret = OCPP_config_info[i].u8_keyID; break; } } return ret; } /******************************************************************************* * 名称: find_OCPP_configMag * 功能: 根据配置参数的枚举号 找对应字符串 并赋值 * 参数: keyID 配置参数的枚举号 * *mag 要赋值串的指针头 * u16_len 被赋值的key串最大长度 * 返回: - * 说明: ******************************************************************************/ void find_OCPP_configMag(OCPP_CONFIG_KEY_ID keyID, char *mag, U16_T u16_len) { if(mag == NULL) return; for(U8_T i = 1; i < ENUM_OCPP_CONFIG; i++) { if(OCPP_config_info[i].u8_keyID == keyID) { memset(mag , 0, u16_len); snprintf(mag , u16_len , "%s" , OCPP_config_info[i].str_data); break; } } return; } /******************************************************************************* * 名称: u8_check_OCPP_configSupport * 功能: 根据配置参数的枚举号 找是否支持 * 参数: keyID 配置参数的枚举号 * 返回: 是否支持标志 * 说明: ******************************************************************************/ OCPP_CONFIG_SUPPORT u8_check_OCPP_configSupport(OCPP_CONFIG_KEY_ID keyID) { OCPP_CONFIG_SUPPORT ret = ENUM_SUPPORT_NOT; for(U8_T i = 1; i < ENUM_OCPP_CONFIG; i++) { if(OCPP_config_info[i].u8_keyID == keyID) { ret = OCPP_config_info[i].u8_support; break; } } return ret; } /******************************************************************************* * 名称: u8_get_bool_value * 功能: 根据字符串查找对应bool值 * 参数: *mag bool字符串 * 返回: 0-false,1-true,0xff-非bool值 * 说明: ******************************************************************************/ U8_T u8_get_bool_value(const char *mag) { if(strcmp(STR_TRUE, mag) == 0) return 1; if(strcmp(STR_true, mag) == 0) return 1; if(strcmp(STR_1 , mag) == 0) return 1; if(strcmp(STR_FALSE, mag) == 0) return 0; if(strcmp(STR_false, mag) == 0) return 0; if(strcmp(STR_0 , mag) == 0) return 0; return 0xff; } /******************************************************************************* * 名称: operate_get_bool * 功能: bool类型键的获取值操作,将键值转为字符串,并赋值到应答value串 * 参数: value 键值 * *value_mag 配置参数值的字符串 * u16_len 配置参数值的字符串的最大长度 * 返回: * 说明: ******************************************************************************/ void operate_get_bool(U8_T value, char *value_mag , U16_T u16_len) { // 将布尔值(U8_T)转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%s" , value ? STR_true : STR_false); } /******************************************************************************* * 名称: operate_set_bool * 功能: bool类型键的修改值操作,将字符串转为bool值,并赋值到value * 参数: *value 需要被修改的参数 * *value_mag bool字符串 * ocpp_key 被修改的键 * 返回: 参数修改结果 0-Rejected 1-Accepted 2-RebootRequired 3-NotSupported * 说明: ******************************************************************************/ OCPP_SETCONFIG_RET operate_set_bool(U8_T *value, char *value_mag, OCPP_CONFIG_KEY_ID ocpp_key) { // 布尔值解析,0=false,1=true,0xff=非布尔值 U8_T res_data = u8_get_bool_value(value_mag); //无效bool值,无法修改参数,返回0-Rejected if(res_data == 0xff) { OCPP_CONFIG_PRINTF_LOG("Set keyID(%d): invalid bool (%s), reject\n", ocpp_key, value_mag); return ENUM_Rejected; } // 赋值 *value = res_data; OCPP_CONFIG_PRINTF_LOG("Set keyID(%d): bool=%d\n", ocpp_key, res_data); return ENUM_Accepted; } /******************************************************************************* * 名称: operate_set_integer * 功能: integer类型键的修改值操作,将字符串转为integer值,并赋值到value * 参数: *value 需要被修改的参数 * *value_mag integer字符串 * ocpp_key 被修改的键 * 返回: 参数修改结果 0-Rejected 1-Accepted 2-RebootRequired 3-NotSupported * 说明: ******************************************************************************/ OCPP_SETCONFIG_RET operate_set_integer(U16_T *value, char *value_mag, OCPP_CONFIG_KEY_ID ocpp_key) { //将字符串转化为整数 int res_data = atoi(value_mag); //判断有效性 if(res_data < 0 || res_data > 0xffff) { OCPP_CONFIG_PRINTF_LOG("Set keyID(%d): invalid int (%d), reject\n", ocpp_key, res_data); return ENUM_Rejected; } //赋值 *value = res_data; OCPP_CONFIG_PRINTF_LOG("Set keyID(%d): int=%d\n", ocpp_key, res_data); return ENUM_Accepted; } /******************************************************************************* * 名称: u8_OCPP_config_operate * 功能: 对OCPP配置参数进行读或写 * 参数: operate_type 操作类型,ENUM_TYPE_GET--获取参数,ENUM_TYPE_GET--设置参数 * *key_mag 配置参数键的字符串 * *value_mag 配置参数值的字符串 * u16_len 配置参数值的字符串的最大长度 * 返回: 参数修改时:0-Rejected 1-Accepted 2-RebootRequired 3-NotSupported * 参数获取时 0-readonly-false 1-readonly-ture * 说明: ******************************************************************************/ U8_T u8_OCPP_config_operate(OCPP_CONFIG_OPERATE operate_type, const char *key_mag, char *value_mag , U16_T u16_len) { //空指针 或 操作类型不存在 则return 3 if(key_mag == NULL || value_mag == NULL || (operate_type != ENUM_TYPE_GET && operate_type != ENUM_TYPE_SET)) return ENUM_NotSupported; OCPP_CONFIG_KEY_ID ocpp_key = u8_find_OCPP_configID(key_mag); //获取键 //ENUM_TYPE_SET:未找到键或不支持键则return 3 if(operate_type == ENUM_TYPE_SET && OCPP_config_info[ocpp_key].u8_support == ENUM_SUPPORT_NOT) return ENUM_NotSupported; int res_data; U8_T ret = ENUM_Accepted; switch (ocpp_key) { //////////////////////////////////////////////////////////////// //必选 bool类型 //////////////////////////////////////////////////////////////// case ENUM_AUTHORIZE_REMOTE_TX_REQUESTS: // 必选 远程启动交易是否需要预授权 (布尔: 0=不需要/1=需要) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_AuthorizeRemoteTxRequests, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_AuthorizeRemoteTxRequests), value_mag, ocpp_key); } } break; case ENUM_LOCAL_AUTHORIZE_OFFLINE: // 必选 离线时是否允许本地授权启动交易 (布尔: 0=不允许/1=允许) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_LocalAuthorizeOffline, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_LocalAuthorizeOffline), value_mag, ocpp_key); } } break; case ENUM_LOCAL_PRE_AUTHORIZE: // 必选 在线时是否无需等待中央系统授权即可本地启动交易 (布尔: 0=需要等待/1=无需等待) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_LocalPreAuthorize, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_LocalPreAuthorize), value_mag, ocpp_key); } } break; case ENUM_STOP_TRANSACTION_ON_EV_SIDE_DISCONNECT: // 必选 EV端断开时是否自动停止交易 (布尔: 0=不自动停止/1=自动停止) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_StopTransactionOnEVSideDisconnect, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_StopTransactionOnEVSideDisconnect), value_mag, ocpp_key); } } break; case ENUM_STOP_TRANSACTION_ON_INVALID_ID: // 必选 收到无效授权状态时是否停止当前交易 (布尔: 0=不停止/1=停止) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_StopTransactionOnInvalidId, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_StopTransactionOnInvalidId), value_mag, ocpp_key); } } break; case ENUM_UNLOCK_CONNECTOR_ON_EV_SIDE_DISCONNECT: // 必选 EV端断开时是否解锁充电点侧连接器 (布尔: 0=不解锁/1=解锁) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_UnlockConnectorOnEVSideDisconnect, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_UnlockConnectorOnEVSideDisconnect), value_mag, ocpp_key); } } break; case ENUM_LOCAL_AUTH_LIST_ENABLED: // 必选 是否启用本地授权列表 (布尔: 0=不启用/1=启用) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_LocalAuthListEnabled, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_LocalAuthListEnabled), value_mag, ocpp_key); } } break; //////////////////////////////////////////////////////////////// //必选 integer类型 //////////////////////////////////////////////////////////////// case ENUM_CLOCK_ALIGNED_DATA_INTERVAL: // 必选 时钟对齐数据间隔 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ClockAlignedDataInterval; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_ClockAlignedDataInterval), value_mag, ocpp_key); } } break; case ENUM_CONNECTION_TIME_OUT: // 必选 准备状态超时自动取消交易时间 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ConnectionTimeOut; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_ConnectionTimeOut), value_mag, ocpp_key); } } break; case ENUM_GET_CONFIGURATION_MAX_KEYS: // 必选 单个GetConfiguration请求最大键数量 (整数: 个) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_GetConfigurationMaxKeys; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_HEARTBEAT_INTERVAL: // 必选 心跳间隔 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_HeartbeatInterval; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_HeartbeatInterval), value_mag, ocpp_key); } } break; case ENUM_METER_VALUE_SAMPLE_INTERVAL: // 必选 计量数据采样间隔 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_MeterValueSampleInterval; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_MeterValueSampleInterval), value_mag, ocpp_key); } } break; case ENUM_NUMBER_OF_CONNECTORS: // 必选 充电点物理连接器数量 (整数: 个) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_NumberOfConnectors; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_RESET_RETRIES: // 必选 充电点复位失败后重试次数 (整数: 次) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ResetRetries; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_ResetRetries), value_mag, ocpp_key); } } break; case ENUM_TRANSACTION_MESSAGE_ATTEMPTS: // 必选 交易消息提交失败后重试次数 (整数: 次) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_TransactionMessageAttempts; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_TransactionMessageAttempts), value_mag, ocpp_key); } } break; case ENUM_TRANSACTION_MESSAGE_RETRY_INTERVAL: // 必选 交易消息重试间隔 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_TransactionMessageRetryInterval; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_TransactionMessageRetryInterval), value_mag, ocpp_key); } } break; case ENUM_LOCAL_AUTH_LIST_MAX_LENGTH: // 必选 本地授权列表最大存储条目数 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_LocalAuthListMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_SEND_LOCAL_LIST_MAX_LENGTH: // 必选 单个SendLocalList请求最大发送条目数 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_SendLocalListMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_CHARGE_PROFILE_MAX_STACK_LEVEL: // 必选 充电配置最大堆叠层级 (整数: 层) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ChargeProfileMaxStackLevel; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_CHARGING_SCHEDULE_MAX_PERIODS: // 必选 单个充电计划最大时段数 (整数: 个) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ChargingScheduleMaxPeriods; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_MAX_CHARGING_PROFILES_INSTALLED: // 必选 同时可安装的充电配置最大数量 (整数: 个) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_MaxChargingProfilesInstalled; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; //////////////////////////////////////////////////////////////// //必选 CSL类型 //////////////////////////////////////////////////////////////// case ENUM_CONNECTOR_PHASE_ROTATION: // 必选 停止事务时的采样数据项 (字符串: 逗号分隔的measurand值) { if(operate_type == ENUM_TYPE_GET) //获取值 { memset(value_mag , 0, u16_len); snprintf(value_mag, u16_len, "0.%s,1.%s,2.%s", phase_to_str(private_config_data->enum_ConnectorPhaseRotation[0]), phase_to_str(private_config_data->enum_ConnectorPhaseRotation[1]), phase_to_str(private_config_data->enum_ConnectorPhaseRotation[2])); ret = ENUM_RnW; //可读写 } else //修改值 { OCPP_CONNECTOR_PHASE phase_new[3] = {0}; if (parse_connector_phase_rotation(value_mag, phase_new, private_config_data->enum_ConnectorPhaseRotation)) { private_config_data->enum_ConnectorPhaseRotation[0] = phase_new[0]; private_config_data->enum_ConnectorPhaseRotation[1] = phase_new[1]; private_config_data->enum_ConnectorPhaseRotation[2] = phase_new[2]; ret = ENUM_Accepted; } else { OCPP_CONFIG_PRINTF_LOG("Set meter phase seq unsupported(%s), reject\n", value_mag); ret = ENUM_Rejected; } } } break; case ENUM_METER_VALUES_ALIGNED_DATA: // 必选 对齐数据上报的测量项列表 (字符串: 逗号分隔的measurand值) case ENUM_METER_VALUES_SAMPLED_DATA: // 必选 采样数据上报的测量项列表 (字符串: 逗号分隔的measurand值) case ENUM_STOP_TXN_ALIGNED_DATA: // 必选 事务停止时的对齐数据项 (字符串: 逗号分隔的measurand值) case ENUM_STOP_TXN_SAMPLED_DATA: // 必选 停止事务时的采样数据项 (字符串: 逗号分隔的measurand值) { //不同数据单元对应不同bit位 计算对应bit是哪一位 U8_T p_bit = 0; switch(ocpp_key) { case ENUM_METER_VALUES_ALIGNED_DATA: p_bit = 0; break; case ENUM_METER_VALUES_SAMPLED_DATA: p_bit = 1; break; case ENUM_STOP_TXN_ALIGNED_DATA: p_bit = 2; break; case ENUM_STOP_TXN_SAMPLED_DATA: p_bit = 3; break; default: break; } if(operate_type == ENUM_TYPE_GET) //获取值 { //遍历所有测量项 遇到需要的则拼接字符串 for(U8_T i = 0; i < ENUM_measurand_Num; i++) { //当前遍历到的测量项 需要包含在该数据单元 if(private_config_data->u8_MeterValuesMeasurandNeed[i] & (1 << p_bit)) { U16_T value_len = strlen(value_mag); //已拼接过字符串,从后面加逗号继续拼接 if(value_len) { snprintf(value_mag + value_len, u16_len - value_len , ",%s" , OCPP_measurand_str[i]); } else //第一次 直接赋值 { memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%s" , OCPP_measurand_str[i]); } } } ret = ENUM_RnW; //可读写 } else //修改值 { U16_T max_allowed = 0; if (ocpp_key == ENUM_METER_VALUES_SAMPLED_DATA) max_allowed = private_config_data->u16_MeterValuesSampledDataMaxLength; else if (ocpp_key == ENUM_METER_VALUES_ALIGNED_DATA) max_allowed = private_config_data->u16_MeterValuesAlignedDataMaxLength; else if (ocpp_key == ENUM_STOP_TXN_SAMPLED_DATA) max_allowed = private_config_data->u16_StopTxnSampledDataMaxLength; else if (ocpp_key == ENUM_STOP_TXN_ALIGNED_DATA) max_allowed = private_config_data->u16_StopTxnAlignedDataMaxLength; if (max_allowed > 0) { U16_T tok_cnt = meter_values_csl_count_nonempty_tokens(value_mag); if (tok_cnt > max_allowed) { OCPP_CONFIG_PRINTF_LOG("CSL key %d: measurand cnt %u > MaxLength %u, reject\n", ocpp_key, (unsigned)tok_cnt, (unsigned)max_allowed); ret = ENUM_Rejected; break; } } OCPP_CONFIG_PRINTF_LOG("Set cfg: ENUM_measurand_Num list:\n"); for (U8_T i = 0, str_find; i < ENUM_measurand_Num; i++) { str_find = meter_values_csl_has_token(value_mag, OCPP_measurand_str[i]) ? 1 : 0; private_config_data->u8_MeterValuesMeasurandNeed[i] &= ~(1 << p_bit); if (str_find) { private_config_data->u8_MeterValuesMeasurandNeed[i] |= (1 << p_bit); OCPP_CONFIG_PRINTF_LOG("%d, ", i); } } OCPP_CONFIG_PRINTF_LOG("\n"); } } break; case ENUM_SUPPORTED_FEATURE_PROFILES: // 必选 停止事务时的采样数据项 (字符串: 逗号分隔的measurand值) { if(operate_type == ENUM_TYPE_GET) //获取值 { //只读键 固定回复 memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%s" , "Core,FirmwareManagement,LocalAuthListManagement,Reservation,SmartCharging,RemoteTrigger"); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_CHARGING_SCHEDULE_ALLOWED_RATE_UNIT: // 必选 停止事务时的采样数据项 (字符串: 逗号分隔的measurand值) { if(operate_type == ENUM_TYPE_GET) //获取值 { //只读键 固定回复 memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%s" , "Power"); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; //////////////////////////////////////////////////// //可选 bool类型 //////////////////////////////////////////////////// case ENUM_ALLOW_OFFLINE_TX_FOR_UNKNOWN_ID: // 可选 是否允许未知ID用户离线启动交易 (布尔: 0=不允许/1=允许) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_AllowOfflineTxForUnknownId, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_AllowOfflineTxForUnknownId), value_mag, ocpp_key); } } break; case ENUM_AUTHORIZATION_CACHE_ENABLED: // 可选 是否启用本地授权缓存 (布尔: 0=不启用/1=启用) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_AuthorizationCacheEnabled, value_mag, u16_len); ret = ENUM_RnW; //可读写 } else // 修改值 { //bool类型键的修改值操作 ret = operate_set_bool(&(private_config_data->u8_AuthorizationCacheEnabled), value_mag, ocpp_key); } } break; case ENUM_RESERVE_CONNECTOR_ZERO_SUPPORTED: // 可选 是否支持对0号连接器进行预约 (布尔: 0=不支持/1=支持) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_ReserveConnectorZeroSupported, value_mag, u16_len); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_CONNECTOR_SWITCH_3TO1_PHASE_SUPPORTED: // 可选 是否支持交易期间三相切单相充电 (布尔: 0=不支持/1=支持) { if(operate_type == ENUM_TYPE_GET) // 获取值 { //bool类型键的获取值操作 operate_get_bool(private_config_data->u8_ConnectorSwitch3to1PhaseSupported, value_mag, u16_len); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; //////////////////////////////////////////////////// //可选 integer类型 //////////////////////////////////////////////////// case ENUM_BLINK_REPEAT: // 可选 充电点指示灯闪烁次数 (整数: 次) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_BlinkRepeat; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_BlinkRepeat), value_mag, ocpp_key); } } break; case ENUM_CONNECTOR_PHASE_ROTATION_MAX_LENGTH: // 可选 相位旋转配置最大条目数 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_ConnectorPhaseRotationMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_LIGHT_INTENSITY: // 可选 充电点灯光亮度 (整数: 百分比) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_LightIntensity; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_LightIntensity), value_mag, ocpp_key); } } break; case ENUM_MAX_ENERGY_ON_INVALID_ID: // 可选 无效ID用户最大允许充电能量 (整数: Wh) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_MaxEnergyOnInvalidId; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_MaxEnergyOnInvalidId), value_mag, ocpp_key); } } break; case ENUM_METER_VALUES_ALIGNED_DATA_MAX_LENGTH: // 可选 时钟对齐计量项列表最大长度 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { res_data = private_config_data->u16_MeterValuesAlignedDataMaxLength; memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; } else { ret = operate_set_integer(&(private_config_data->u16_MeterValuesAlignedDataMaxLength), value_mag, ocpp_key); if (ret == ENUM_Accepted) { if (private_config_data->u16_MeterValuesAlignedDataMaxLength > MeterValuesRequest_SV_NUM) private_config_data->u16_MeterValuesAlignedDataMaxLength = MeterValuesRequest_SV_NUM; if (private_config_data->u16_MeterValuesAlignedDataMaxLength == 0) private_config_data->u16_MeterValuesAlignedDataMaxLength = MeterValuesRequest_SV_NUM; } } } break; case ENUM_METER_VALUES_SAMPLED_DATA_MAX_LENGTH: // 可选 采样计量项列表最大长度 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { res_data = private_config_data->u16_MeterValuesSampledDataMaxLength; memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; } else { ret = operate_set_integer(&(private_config_data->u16_MeterValuesSampledDataMaxLength), value_mag, ocpp_key); if (ret == ENUM_Accepted) { if (private_config_data->u16_MeterValuesSampledDataMaxLength > MeterValuesRequest_SV_NUM) private_config_data->u16_MeterValuesSampledDataMaxLength = MeterValuesRequest_SV_NUM; if (private_config_data->u16_MeterValuesSampledDataMaxLength == 0) private_config_data->u16_MeterValuesSampledDataMaxLength = MeterValuesRequest_SV_NUM; } } } break; case ENUM_MINIMUM_STATUS_DURATION: // 可选 状态稳定后发送通知的最短持续时间 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_MinimumStatusDuration; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_MinimumStatusDuration), value_mag, ocpp_key); } } break; case ENUM_STOP_TXN_ALIGNED_DATA_MAX_LENGTH: // 可选 交易停止时对齐计量项最大长度 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_StopTxnAlignedDataMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_STOP_TXN_SAMPLED_DATA_MAX_LENGTH: // 可选 交易停止时采样计量项最大长度 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_StopTxnSampledDataMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_SUPPORTED_FEATURE_PROFILES_MAX_LENGTH: // 可选 支持功能配置文件列表最大长度 (整数: 条) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_SupportedFeatureProfilesMaxLength; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_R_Only; //只读 } else //修改值 { //只读键不支持修改 OCPP_CONFIG_PRINTF_LOG("RO keyId:%d, set NS\n",ocpp_key); ret = ENUM_NotSupported; } } break; case ENUM_WEB_SOCKET_PING_INTERVAL: // 可选 WebSocket Ping间隔 (整数: 秒) { if(operate_type == ENUM_TYPE_GET) //获取值 { //获取 赋值给value_mag res_data = private_config_data->u16_WebSocketPingInterval; //将整数转化为字符串并赋值给应答value memset(value_mag , 0, u16_len); snprintf(value_mag , u16_len , "%d" , res_data); ret = ENUM_RnW; //可读写 } else //修改值 { //integer类型键的修改值操作 ret = operate_set_integer(&(private_config_data->u16_WebSocketPingInterval), value_mag, ocpp_key); } } break; // //私有 // case ENUM_QRCODE_TEXT_CONNECTOR1: // 私有 枪1二维码 { if(operate_type == ENUM_TYPE_GET) //获取值 { //将二维码字符串赋值给应答value snprintf(value_mag , NUM_64 , "%s" , private_config_data->QRCodeConnector1); ret = ENUM_RnW; //可读写 } else //修改值 { //将二维码字符串赋值 snprintf(private_config_data->QRCodeConnector1 , NUM_64 , "%s" , value_mag); ret = ENUM_Accepted; } } break; case ENUM_QRCODE_TEXT_CONNECTOR2: // 私有 枪2二维码 { if(operate_type == ENUM_TYPE_GET) //获取值 { //将二维码字符串赋值给应答value snprintf(value_mag , NUM_64 , "%s" , private_config_data->QRCodeConnector2); ret = ENUM_RnW; //可读写 } else //修改值 { //将二维码字符串赋值 snprintf(private_config_data->QRCodeConnector2 , NUM_64 , "%s" , value_mag); ret = ENUM_Accepted; } } break; default: break; } return ret; } /** * ************************************************************************ * @brief - OCPP flash 存储数据 写入 * * * * @author jiankalka * @date 2026-01-15 * ************************************************************************ */ void v_flash_save_ocpp_cfg_data(void) { U8_T u8_head[8],err; U16_T u16_len, u16_crc, i, j; U32_T u32_addr = DATAFLASH_OCPP_CFG_DATA_ADDR; u16_len = sizeof(S_OCPP_FLASH_CFG_DATA); //数据长度 u8_head[0] = 0x55; u8_head[1] = 0xAA; u8_head[2] = CFG_DATA_VERSION_H; u8_head[3] = CFG_DATA_VERSION_L; u8_head[4] = (U8_T)(u16_len >> 8); u8_head[5] = (U8_T)u16_len; s32_flash_dataflash_erase_sector(u32_addr); //清空扇区 mSleep(10); GetCurrentTime(&s_ocpp_flash_cfg_data.time); //获取当前时间 u16_crc = u16_crc_checksum((U8_T *)(&(s_ocpp_flash_cfg_data)), u16_len); u8_head[6] = (U8_T)(u16_crc >> 8); u8_head[7] = (U8_T)u16_crc; for (j=0; j<3; j++) //如果写失败,则重试3次 { if ((s32_flash_dataflash_write(u32_addr, u8_head, 8) != 0) || (s32_flash_dataflash_write(u32_addr+8, (U8_T *)(&(s_ocpp_flash_cfg_data)), u16_len) != 0)) { continue; } else { break; } } } S32_T s32_flash_read_ocpp_cfg_data(void) { U8_T u8_head[8],err; U16_T u16_len, i, j, k; U32_T u32_addr = DATAFLASH_OCPP_CFG_DATA_ADDR; u16_len = sizeof(S_OCPP_FLASH_CFG_DATA); for (i=0; i<3; i++) { if ((s32_flash_dataflash_read(u32_addr, u8_head, 8) == 0) && (s32_flash_dataflash_read(u32_addr+8, (U8_T *)(&(s_ocpp_flash_cfg_data)), u16_len) == 0)) { if ((u8_head[0] == 0x55) && (u8_head[1] == 0xAA) &&(u8_head[2] == CFG_DATA_VERSION_H) //版本相同 && (u8_head[3] == CFG_DATA_VERSION_L) && (u16_len == ((u8_head[4]<<8) | u8_head[5])) //长度相同 && (((u8_head[6]<<8) | u8_head[7]) == u16_crc_checksum((U8_T *)(&(s_ocpp_flash_cfg_data)), u16_len))) //CRC校验正确 { break; } } } if (i >= 3) //三份配置数据都没有读取成功,则退出 { return -1; } return 0; } void v_flash_ocpp_data_restore() { s_ocpp_flash_cfg_data.s_ocpp_charge_data.card_ver = 0; s_ocpp_flash_cfg_data.s_ocpp_charge_data.s8_ChangeAvailability[0] = 0; s_ocpp_flash_cfg_data.s_ocpp_charge_data.s8_ChangeAvailability[1] = 0; strncpy(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor,"iECharge", sizeof(s_ocpp_flash_cfg_data.s_ocpp_charge_data.chargePointVendor)-1); // ------------------- 必选boolean类型(U8_T) ------------------- private_config_data->u8_AuthorizeRemoteTxRequests = 0; // 只读 远程启动交易是否需要预授权 private_config_data->u8_LocalAuthorizeOffline = 1; // ! 离线时是否允许本地授权启动交易 private_config_data->u8_LocalPreAuthorize = 0; // !在线时是否无需等待中央系统授权即可本地启动交易 private_config_data->u8_StopTransactionOnEVSideDisconnect = 1; // - EV端断开时是否自动停止交易 private_config_data->u8_StopTransactionOnInvalidId = 1; // ! √ 收到无效授权状态时是否停止当前交易 private_config_data->u8_UnlockConnectorOnEVSideDisconnect = 0; // - EV端断开时是否解锁充电点侧连接器 private_config_data->u8_LocalAuthListEnabled = 1; // ! 是否启用本地授权列表 // ------------------- 必选integer类型(U16_T) ------------------- private_config_data->u16_ClockAlignedDataInterval = 0; // - 时钟对齐数据间隔(秒) private_config_data->u16_ConnectionTimeOut = 0; // - 准备状态超时自动取消交易时间(秒) private_config_data->u16_GetConfigurationMaxKeys = GetConfiguration_NUM;// 只读 单个GetConfiguration请求最大键数量 private_config_data->u16_HeartbeatInterval = 30; // ! 心跳间隔(秒) private_config_data->u16_MeterValueSampleInterval = 30; // ! 计量数据采样间隔(秒) private_config_data->u16_NumberOfConnectors = g_t_share_data.t_sys_fix_cfg.u8_gunCnt; // 只读 充电点物理连接器数量 private_config_data->u16_ResetRetries = 0; // - 充电点复位失败后重试次数 private_config_data->u16_TransactionMessageAttempts = 0; // - 交易消息提交失败后重试次数 private_config_data->u16_TransactionMessageRetryInterval = 20; // - 交易消息重试间隔(秒) private_config_data->u16_LocalAuthListMaxLength = CARD_MAX_COUNT; // 只读 本地授权列表最大存储条目数 private_config_data->u16_SendLocalListMaxLength = 10; //只读 单个SendLocalList请求最大发送条目数 private_config_data->u16_ChargeProfileMaxStackLevel = 0; // - 充电配置最大堆叠层级 private_config_data->u16_ChargingScheduleMaxPeriods = 0; // - 单个充电计划最大时段数 private_config_data->u16_MaxChargingProfilesInstalled = 0; // - 同时可安装的充电配置最大数量 // ------------------- 必选CSL类型 ------------------------------- //OCPP_CONNECTOR_PHASE enum_ConnectorPhaseRotation[3]; //各枪电表的连接相序 0整桩 1枪A 2枪B private_config_data->enum_ConnectorPhaseRotation[0] = ENUM_NotApplicable; // 不适用(单相交流/直流充电桩,非三相场景) private_config_data->enum_ConnectorPhaseRotation[1] = ENUM_NotApplicable; private_config_data->enum_ConnectorPhaseRotation[2] = ENUM_NotApplicable; /*合并 MeterValuesAlignedData、 MeterValuesSampledData、 StopTxnAlignedData、 StopTxnSampledData MeterValues测量项在以上数据单元是否需要 bit 0 :MeterValuesAlignedData是否需要 时钟定点上送 bit 1 :MeterValuesSampledData是否需要 周期上送 bit 2 :StopTxnAlignedData是否需要 时钟定点上送 bit 3 :StopTxnSampledData是否需要 周期上送 */ // U8_T u8_MeterValuesMeasurandNeed[ENUM_measurand_Num]; // ! private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyActiveExportRegister ] = 0; // 有功电能输出累计值(Wh)- 设备向电网输出的总有功电能累计 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyActiveImportRegister ] = E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData; // 有功电能输入累计值(Wh)- 电网向设备输入的总有功电能累计 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyReactiveExportRegister ] = 0; // 无功电能输出累计值(VARh)- 设备向电网输出的总无功电能累计 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyReactiveImportRegister ] = 0; // 无功电能输入累计值(VARh)- 电网向设备输入的总无功电能累计 // ------------------- 能量时段值(Interval)- 文档7.31时段能量类 ------------------- private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyActiveExportInterval ] = 0; // 有功电能输出时段值(Wh)- 单个时钟对齐时段内输出的有功电能 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyActiveImportInterval ] = 0; // 有功电能输入时段值(Wh)- 单个时钟对齐时段内输入的有功电能 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyReactiveExportInterval ] = 0; // 无功电能输出时段值(VARh)- 单个时钟对齐时段内输出的无功电能 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyReactiveImportInterval ] = 0; // 无功电能输入时段值(VARh)- 单个时钟对齐时段内输入的无功电能 // ------------------- 功率类 - 文档7.31功率计量类 ------------------- private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerActiveExport ] = 0; // 有功功率输出(W)- 设备向电网输出的实时有功功率 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerActiveImport ] = E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData; // 有功功率输入(W)- 电网向设备输入的实时有功功率 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerOffered ] = 0; // 提供的功率(W)- 充电桩可向EV提供的最大可用有功功率 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerReactiveExport ] = 0; // 无功功率输出(VAR)- 设备向电网输出的实时无功功率 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerReactiveImport ] = 0; // 无功功率输入(VAR)- 电网向设备输入的实时无功功率 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerFactor ] = 0; // 功率因数(无单位,0~1)- 实时有功功率与视在功率的比值 // ------------------- 电流类 - 文档7.31电流计量类 ------------------- private_config_data->u8_MeterValuesMeasurandNeed[ENUM_CurrentImport ] = E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData; // 输入电流(A)- 电网向设备输入的实时电流 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_CurrentExport ] = 0; // 输出电流(A)- 设备向电网输出的实时电流 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_CurrentOffered ] = 0; // 提供的电流(A)- 充电桩可向EV提供的最大可用电流 // ------------------- 电气参数类 - 文档7.31基础电气参数 ------------------- private_config_data->u8_MeterValuesMeasurandNeed[ENUM_Voltage ] = E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData; // 电压(V)- 充电桩输出端的实时线电压 private_config_data->u8_MeterValuesMeasurandNeed[ENUM_Frequency ] = 0; // 电网频率(Hz)- 接入电网的实时频率(50/60Hz) // ------------------- 物理/状态量类 - 文档7.31非电气计量项 ------------------- private_config_data->u8_MeterValuesMeasurandNeed[ENUM_Temperature ] = 0; // 温度(℃)- 充电桩/EV电池的实时温度(文档标注为℃/℉,默认℃) private_config_data->u8_MeterValuesMeasurandNeed[ENUM_SoC ] = E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData | E_CFG_MVMN_StopTxnAlignedData | E_CFG_MVMN_StopTxnSampledData; // 电池剩余电量(%)- EV电池的State of Charge,0~100% private_config_data->u8_MeterValuesMeasurandNeed[ENUM_RPM ] = 0; // 转速(转/分钟)- 冷却风扇/泵等设备的实时转速 /*支持的功能配置文件列表 bit 0 :Core(核心) 是否支持 bit 1 :FirmwareManagement(固件管理) 是否支持 bit 2 :LocalAuthListManagement(本地授权列表管理) 是否支持 bit 3 :Reservation(预约) 是否支持 bit 4 :SmartCharging(智能充电) 是否支持 bit 5 :RemoteTrigger(远程触发) 是否支持 */ private_config_data->u8_SupportedFeatureProfiles = 0; // - 只读 默认获取时写死 /*充电调度支持的物理量列表 bit 0 :'Current'(电流) 是否支持 bit 1 :'Power'(功率) 是否支持 */ private_config_data->ChargingScheduleAllowedChargingRateUnit = 0; // - // ------------------- 可选boolean类型(U8_T:0=false,非0=true) ------------------- private_config_data->u8_AllowOfflineTxForUnknownId = 0; //! 是否允许未知ID用户离线启动交易 -离线时直接启动不鉴权 private_config_data->u8_AuthorizationCacheEnabled = 0; //- 是否启用本地授权缓存 (一次充电成功自动在授权缓存保存ID) private_config_data->u8_ReserveConnectorZeroSupported = 0; //- 是否支持对0号连接器进行预约 private_config_data->u8_ConnectorSwitch3to1PhaseSupported = 0; //- 是否支持交易期间三相切单相充电 // ------------------- 可选integer类型(U16_T,单位见注释) ------------------- private_config_data->u16_BlinkRepeat = 0; //- 充电点指示灯闪烁次数 private_config_data->u16_ConnectorPhaseRotationMaxLength = 0; //- 相位旋转配置最大条目数(补充:可选核心项) private_config_data->u16_LightIntensity = 0; //- 充电点灯光亮度(百分比) private_config_data->u16_MaxEnergyOnInvalidId = 0; //- 无效ID用户最大允许充电能量(Wh) private_config_data->u16_MeterValuesAlignedDataMaxLength = 0; //- 时钟对齐计量项列表最大长度(可选) private_config_data->u16_MeterValuesSampledDataMaxLength = MeterValuesRequest_SV_NUM; //! 采样计量项列表最大长度(可选) private_config_data->u16_MinimumStatusDuration = 0; //- 状态稳定后发送通知的最短持续时间(秒) private_config_data->u16_StopTxnAlignedDataMaxLength = MeterValuesRequest_SV_NUM; //- 交易停止时对齐计量项最大长度(可选) private_config_data->u16_StopTxnSampledDataMaxLength = MeterValuesRequest_SV_NUM; //- 交易停止时采样计量项最大长度(可选) private_config_data->u16_SupportedFeatureProfilesMaxLength = 0; //- 支持功能配置文件列表最大长度(可选) private_config_data->u16_WebSocketPingInterval = 0; //- WebSocket Ping间隔(秒,0表示禁用) //------------------私有配置------------------------ strncpy(&private_config_data->QRCodeConnector1[0] ,&g_t_share_data.t_sys_var_cfg.QRDisplay[0][0], NUM_64); //√ strncpy(&private_config_data->QRCodeConnector2[0] ,&g_t_share_data.t_sys_var_cfg.QRDisplay[1][0], NUM_64); //√ v_flash_save_ocpp_cfg_data(); //保存参数到flash } static void v_ocpp_fix_legacy_meter_values_default(void) { U8_T sampled_energy = (private_config_data->u8_MeterValuesMeasurandNeed[ENUM_EnergyActiveImportRegister] & E_CFG_MVMN_MeterValuesSampledData) ? 1 : 0; U8_T sampled_power = (private_config_data->u8_MeterValuesMeasurandNeed[ENUM_PowerActiveImport] & E_CFG_MVMN_MeterValuesSampledData) ? 1 : 0; U8_T sampled_current = (private_config_data->u8_MeterValuesMeasurandNeed[ENUM_CurrentImport] & E_CFG_MVMN_MeterValuesSampledData) ? 1 : 0; U8_T sampled_voltage = (private_config_data->u8_MeterValuesMeasurandNeed[ENUM_Voltage] & E_CFG_MVMN_MeterValuesSampledData) ? 1 : 0; U8_T sampled_soc = (private_config_data->u8_MeterValuesMeasurandNeed[ENUM_SoC] & E_CFG_MVMN_MeterValuesSampledData) ? 1 : 0; // 兼容历史固件仅默认上送3项的情况:自动补齐Voltage和SoC if(sampled_energy && sampled_power && sampled_current && !sampled_voltage && !sampled_soc) { private_config_data->u8_MeterValuesMeasurandNeed[ENUM_Voltage] |= (E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData); private_config_data->u8_MeterValuesMeasurandNeed[ENUM_SoC] |= (E_CFG_MVMN_MeterValuesAlignedData | E_CFG_MVMN_MeterValuesSampledData); v_flash_save_ocpp_cfg_data(); OCPP_CONFIG_PRINTF_LOG("Fix legacy MeterValues default: add Voltage,SoC\n"); } } /**************************************************** *函数名称: v_ocpp_init_config_data() *功能说明: 程序运行前 配置参数初始化 *参数说明: * 输入参数: * 输出参数: ****************************************************/ void v_ocpp_init_config_data() { memset(&s_ocpp_flash_cfg_data,0,sizeof(S_OCPP_FLASH_CFG_DATA)); private_config_data = &s_ocpp_flash_cfg_data.s_ocpp_config_data; //指针数据初始化 必选配置参数 //读可变配置参数 //v_flash_ocpp_data_restore();//默认使用初始化参数 if (s32_flash_read_ocpp_cfg_data() == -1) { v_flash_ocpp_data_restore(); printf("ocpp flash fail,read new\n"); } else { v_ocpp_fix_legacy_meter_values_default(); } } #endif