Files
CCU621M/app/plat_comm/ocpp/OCPP功能模块说明.md

31 KiB
Raw Permalink Blame History

OCPP 功能模块说明(CCU601E_D

本文档描述 CCU601E_D\app\plat_comm\ocpp 目录内各文件职责、主要数据结构及与其它模块的关系,便于维护与二次开发。全文基于工程源码归纳;协议细节以 OCPP 1.6-j 为准。


1. 模块定位与编译开关

项目 说明
协议 OCPP 1.6,典型传输为 WebSocket(子协议 ocpp1.6)。
宏开关 全局 BS_OCPP_EN(通常为 Public_define.h 等处):为 0 时本目录多数代码不参与编译。
依赖 cJSONJSON 组帧/解析)、FreeRTOS 内存 pvPortMalloc / vPortFree(见 BS_ocpp_ctrl.hOCPP_MALLOC)、平台任务 plat_comm(TCP/4G、充电订单接口)、计量/F meter_calculate、Flash 配置等。

2. 目录文件一览与职责

文件名 类型 职责摘要
BS_ocpp_ctrl.h 头文件 OCPP 运行时控制结构体、定时器枚举、充电侧标志位枚举;对外 API:v_ocpp_init_datav_ocpp_tcp_connectv_ocpp_logo_onv_ocpp_recv_datav_ocpp_send_ctrlv_ocpp_private_logicrecv_mags 等。
BS_ocpp_ctrl.c 实现 核心控制器WebSocket 收发衔接、send_mag 统一发包、ocpp_send_mag_ctrl 周期/事件触发(Boot、Heartbeat、Status、MeterValues、Start/Stop、Authorize);平台下行解析(RemoteStart/Stop、ChangeConfiguration、GetConfiguration、Reset、Unlock、UpdateFirmware、SendLocalList、GetDiagnostics 等);离线/未结算订单 s8_unsettled_order_chaek;各 Action 的 CallResult 处理函数(*_res / *_unpack)。离线周期 MeterValues 的落盘与补发状态机委托 BS_ocpp_mv_offline_bridge补发单条 PDUs32_ocpp_send_meter_values_replayMeterValues_mag_offline_replay(实现位于桥接模块)。源码内用 #if 1 // … 做大段分区(见 §4.0)。
BS_ocpp_mv_offline_bridge.h 头文件 BS_OCPP_EN 内)声明 MeterValues_mag_offline_replayv_ocpp_mv_offline_bridge_private_logicv_ocpp_mv_offline_unsettled_abortu8_ocpp_mv_offline_unsettled_step;依赖 Flash 侧 ocpp_mv_offline_flash_impl.hbs_ocpp_json_data.h
BS_ocpp_mv_offline_bridge.c 实现 离线 MeterValues 桥接:TCP 未连接或已连接未登录时按周期把测量快照写入 SPI Flash 池(与 u8_get_ocpp_measurand_data 口径对齐);FRAM 映射键为 订单开始充电时间xDate2Seconds 的 32 位秒值 + 枪号;联网成功且未结单已取得平台 transactionId 后,在 StopTransaction 前按序 u8_ocpp_mv_offline_unsettled_step 补发;MeterValues_mag_offline_replayu8_MeterValuesMeasurandNeed 从快照填 SampledValuej_get_ocpp_json(OCPP_MeterValues, …)v_ocpp_mv_offline_initv_ocpp_init_data 中调用。详情见桥接文件头注释与 flash_file_mgr/ocpp_mv_offline_flash_impl.*
bs_ocpp_json_data.h 头文件 OCPP_CMD 枚举(桩→平台 / 平台→桩)、各 PDU 的 Request/Response 结构体、GetConfiguration/MeterValues 等缓冲区长度宏;供组帧与解析共用。
bs_ocpp_json_data.c 实现 字符串常量表:命令名、StatusNotification 的 errorCode/statusCode、StopTransaction.reason、RemoteStart 应答等;发送侧BootNotification_jsonStartTransaction_jsonMeterValues_jsoncJSON 组帧接收侧get_ocpp_data / ocpp_*_unpack 解析平台下行 payload通用j_get_ocpp_jsons_get_ocpp_cmd_str、枚举转字符串等。
bs_ocpp_str.h 头文件 OCPP 协议中出现的 字面量measurand、context、unit、Accepted/Blocked、以及标准 Configuration Key 名称宏 KEY_*),避免魔法字符串散落。
bs_ocpp_configuration.h 头文件 连接器相位枚举、MeterValues 测量项枚举 OCPP_MEASURAND_ID(顺序固定,与配置数组下标绑定);Flash 配置结构 S_OCPP_FLASH_CFG_DATA / OCPP_CONFIG 声明;测量项英文串表 OCPP_measurand_str 外部声明。
bs_ocpp_configuration.c 实现 s_ocpp_flash_cfg_data:默认与 Flash 持久化的 OCPP 配置(Heartbeat、MeterValues 采样项、SupportedFeatureProfiles 等);GetConfiguration / ChangeConfiguration 读写逻辑;与 spi_Flash/flash_external_data 协同落地配置;测量项字符串数组 OCPP_measurand_str 定义。
bs_websocket.h 头文件 WebSocket 帧类型(文本/PING/PONG/断开);ws_sendwebsocket_buildocpp_recv 声明;可选 OCPP_WS_HTTP_AUTHORIZATION_ENHTTP Basic)。
bs_websocket.c 实现 RFC6455 握手(含 Sec-WebSocket-Accept、可选 Basic)、帧封装/解析;与 bs_connect_impl URL/TCP 衔接;收包后递交给 recv_mags(见 BS_ocpp_ctrl.c)。

3. 核心数据结构(BS_ocpp_ctrl.h

3.1 OCPP_SEND_TIMER

周期性上报节拍:BootNotificationHeartbeat、各枪 StatusNotificationMeterValuesStopTransaction 定时、Authorize 定时等。具体周期值在运行时由配置或初始化写入 s_timerCnt[]

3.2 OCPP_CHARGE_FLAG

与充电流程协同的软件标志(落在 plat_comm_task 的枪数据中,通过 u8_charge_flag_ctrl 访问),例如:

  • OCPP_STATE_CHANGE_FLAG:连接器状态变化需上报;
  • OCPP_TRADE_UPLOAD_FLAG:订单结束待上送 StopTransaction
  • OCPP_START_RESULT_FLAG / OCPP_STOP_RESULT_FLAG:启动/停止结果触发;
  • OCPP_VIN_START_FLAG:即插即充等场景的鉴权请求节拍。

3.3 OCPP_DATA_CTRL

OCPP 私有全局状态(指针 private_ocpp_data,初始化见 v_ocpp_init_data),主要包括:

  • 登录与链路ulong_timer、超时重连等;
  • 离线/未结订单u8_unsettled_order_flags_unsettled_order_data(动态分配的 S_LOG_DATA);补单流水线 u8_unsettled_auth_phaseOCPP_UNSETTLED_AUTH_PHASE_E:先 AuthorizeStartTransaction)、u32_unsettled_last_auth_s / u32_unsettled_last_stx_sAuthorize 节流;StartTransaction 在本单鉴权通过后仅发一次,用非零时间戳标记已发,避免平台多笔 transaction);
  • 每枪控制s_ctrl_flag[]MeterValues 召测、Trigger、鉴权计数等);
  • 定时器数组s_timerCnt[OCPP_TIMERCNT_NUM]
  • 异步应答队列ack_ctrl[](平台多条指令并发时的应答上下文)。

3.4 OCPP_DATA_SAVE

待发 CALL 与应答匹配的 messageId/key 缓存(save_json_cmd / get_json_cmd),用于解析 CALLRESULT / CALLERROR 时找到对应枪号与命令类型。


4. BS_ocpp_ctrl.c 功能分层说明

4.0 源码分区(#if 1 标记)

为方便在单文件内浏览,BS_ocpp_ctrl.c 用大段 #if 1 // 注释 划分逻辑归属(编译裁剪,恒为 1):

分区注释 主要内容
//公共 随机数、待发 messageId 队列(save_json_cmd / get_json_cmd)、发送节拍累加(v_ocpp_timer_addu8_ocpp_timer_ctrl)、v_ocpp_timestamp_to_str、应答块分配/释放、parse_ftp_url 与 FTP URL 自测、时间差工具函数;供 FTP / 其它模块写 OCPP 侧“待发 Notify 状态”v_ocpp_set_diag_upload_notify_pendingv_ocpp_set_fw_notify_pendingv_ocpp_set_fw_reboot_after_installed(写入 s_bs_task_ctrl.ocpp_data,与 DiagnosticsStatusNotification_mag / FirmwareStatusNotification_magsend_mag 配合)。不再在控制器内保留已迁出的 unix 秒→ISO8601 辅助(补发时间戳在桥接文件内实现)。
//数据获取 枪/订单标志 u8_charge_flag_ctrl、桩状态、重启与交易上送标记、u8_get_ocpp_measurand_datau8_get_ocpp_transaction_dataGetConfiguration 键填充、StatusNotification 变化检测与 Faulted 判定等。
//发送 BootNotification_mag*_magcJSON body(含 MeterValues 在线路径)、GetConfiguration 应答体、DiagnosticsStatusNotification_magFirmwareStatusNotification_magsend_mags32_ocpp_send_meter_values_replay离线快照→JSON 调用桥接层 MeterValues_mag_offline_replay)、ocpp_send_mag_ctrl;部分静态函数名含 _res 实为 对外发送的 CallResult payload 组装,仍属发送段。
//接收 平台下行 CALL 解析(*_mag unpackocpp_analysis_data)、CALLRESULT 分发(*_res)、recv_mags
未结订单与充电鉴权 u8_ocpp_is_pre_trade_no_pending、未结内存释放 v_safe_free_unsettled_order_data(内含 v_ocpp_mv_offline_unsettled_abort)、u8_unsettled_pretrade_pipelines8_unsettled_order_chaek、充电中鉴权检查 v_ocpp_private_charge_authentication_cheak
//外部控制使用 v_ocpp_init_data / v_ocpp_init_data_ex(含 v_ocpp_mv_offline_init)、RX 超时与重连门槛 u8_ocpp_block_rx_timeout_relinkv_ocpp_tcp_connectv_ocpp_logo_onv_ocpp_recv_datav_ocpp_send_ctrlv_ocpp_private_logic

内层 MeterValues_mag 中另有 #if 1 //根据枚举 MeterValues 测量项…,仅区分「按配置枚举上送」与「简化固定字段」两套实现,不单独对应上表大段。

4.1 发送路径

  1. 业务或定时器置位标志 → ocpp_send_mag_ctrl() 轮询;
  2. send_mag(gunNo, cmd, ack_data, type)
    • 构造 [2, messageId, Action, payload](主动)或 [3, …](应答);
    • switch(cmd) 调用各 *_mag 生成 cJSON body(实际多在 BS_ocpp_ctrl.c 内静态函数,如 BootNotification_magStartTransaction_mag,内部再调 bs_ocpp_json_data.c 的 json 辅助);在线 MeterValuesMeterValues_mag离线 Flash 中缓存的一条快照补发s32_ocpp_send_meter_values_replay,其 body 由 MeterValues_mag_offline_replayBS_ocpp_mv_offline_bridge.c)生成,与在线共用 j_get_ocpp_jsonu8_MeterValuesMeasurandNeed
    • 文本输出经 ws_send 发到 CSMS。

type 参数:同一 Action 不同数据源时使用,例如 StartTransaction / StopTransaction / Authorize实时枪数据(0未结算内存订单 s_unsettled_order_data1

4.2 接收路径

  1. ocpp_recv()bs_websocket.c)收到文本帧 → recv_mags()
  2. 解析 JSON:区分 CALL / CALLRESULT / CALLERROR
  3. CALL:根据 Action 字符串映射 OCPP_CMDunpack 填充 OCPP_DATA_RECV_ACK,必要时 send_mag 返回 CallResult
  4. CALLRESULTget_json_cmd 匹配 messageId → 调用对应 StartTransaction_resAuthorize_res 等,更新本地订单/流水号/鉴权状态。

4.3 典型已实现的平台指令(下行)

包括但不限于:RemoteStartTransactionRemoteStopTransactionUnlockConnectorResetChangeAvailabilityChangeConfigurationGetConfigurationTriggerMessageSendLocalListGetLocalListVersionClearCacheUpdateFirmwareGetDiagnostics(工程内可能对 diagnostics 使用自定义 Action 名,以源码为准)。

4.4 离线 / 未结算订单(概要)

  • s8_unsettled_order_chaek():联网且登录后周期性调用;从 s8_plat_get_unsettled_orderbs_public_impl.c)拉取 Flash 未结列表EEPROM 掉电临时订单,挂到 s_unsettled_order_data(一次一单)。
  • 已有平台流水号u8_preTradeNo 有效:非空且非 0xFF 占位,判定见 u8_ocpp_is_pre_trade_no_pending):直接 StopTransaction(type=1) 上送结束侧订单信息(meterStop、timestamp、reason、transactionData 等),随后释放内存上下文。
  • 尚无流水号(空或 0xFF 占位):Authorize(type=1)idTag 取订单 u8_user_id)→ 仅 idTagInfo.status == AcceptedStartTransaction(type=1) 申请 transactionIdStartTransaction_res 在桩空闲且未结副本存在时把 transactionId 写入 u8_preTradeNo → 下一周期走 StopTransaction(type=1)补充:若本笔在离线阶段已通过 BS_ocpp_mv_offline_bridge 将周期 MeterValues 写入 Flash,则在 已取得平台 transactionId 后、发 StopTransaction 前,由 u8_ocpp_mv_offline_unsettled_step 按序号逐条补发(帧格式与在线 send_mag/MeterValues 一致),补完或映射无效后再结束事务。
  • 拒绝与单次 StartTransactionStartTransaction.conf 对 Blocked/Invalid 等未结补单立即 v_safe_free_unsettled_order_data(不重试 StartTransaction,避免平台侧多笔订单);Authorize 非 Accepted 同样丢弃内存。Authorize 带秒级节流(u32_unsettled_last_auth_s);鉴权通过后 StartTransaction 仅尝试发送一次(成功发出后 u32_unsettled_last_stx_s 非零 即不再发;链路 ws_send 失败 未置位时可下一周期再试一次发送)。

详细分场景(Flash / EEPROM、与平台报文顺序)见第 10~12 节。

详细边界条件见代码注释及同类需求文档。


5. bs_ocpp_json_data.c 功能分层说明

类别 内容
命令表 ocpp_cmd_str[][]OCPP_CMD 枚举对齐,用于日志与解析。
枚举串 errorCode、status、reason、UnlockConnector 状态等,供 s_get_ocpp_enum_data_str 使用。
桩 → 平台 *_json():把结构体填进 cJSON
平台 → 桩 ocpp_*_unpack():从 cJSON 填结构体,供业务判断。
入口封装 j_get_ocpp_json:按 cmd 选择对应 json 构造函数;get_ocpp_data:解析 CallResult。

6. bs_ocpp_configuration.c 功能说明

  • 维护全局 s_ocpp_flash_cfg_data(含 OCPP_CONFIG):对标 OCPP 标准配置键,如 HeartbeatInterval、MeterValuesSampledData、AuthorizeRemoteTxRequests、StopTransactionOnInvalidId 等;
  • ChangeConfiguration:校验、写入 RAM + Flash;部分键需解析 CSV(测量项列表)、相位字符串等;
  • GetConfiguration:按 key 列表返回 readonly/value;未知 key 记入 unknownKey
  • OCPP_measurand_str[]:与 OCPP_MEASURAND_ID 一一对应,供 MeterValues/StopTxn 数据项映射。

7. bs_websocket.c 功能说明

  • 完成 TLS/TCP 之上的 WebSocket 字节流处理(依工程 websocket_build 与连接模块集成方式而定);
  • 握手HTTP Upgrade → Sec-WebSocket-Accept(内置 SHA1/Base64 相关逻辑);
  • 心跳:处理 Ping/Pong,业务层亦可配合应用层 Heartbeat;
  • 数据:文本帧交给 recv_mags

8. bs_ocpp_str.h 功能说明

  • 协议常量measurand、location、unit、Sample.PeriodicTransaction.Begin/End 等;
  • 授权/配置结果AcceptedBlockedInvalid 等;
  • 配置键名KEY_HEARTBEAT_INTERVALKEY_METER_VALUES_SAMPLED_DATA 等(与 bs_ocpp_configuration 协同)。

避免与 bs_ocpp_json_data.h 中结构体字段混淆:str.h 侧重 字面量与 Key 名json_data.h 侧重 PDU 结构体与枚举


9. 与其它目录的典型调用关系(示意)

flowchart LR
    subgraph plat_comm_task
        T[v_ocpp_send_ctrl / v_ocpp_recv_data]
    end
    subgraph ocpp
        C[BS_ocpp_ctrl.c]
        M[BS_ocpp_mv_offline_bridge.c]
        J[bs_ocpp_json_data.c]
        W[bs_websocket.c]
        CFG[bs_ocpp_configuration.c]
    end
    subgraph impl
        P[bs_public_impl.c]
    end
    subgraph flash
        F[ocpp_mv_offline_flash_impl]
    end
    T --> C
    C --> M
    C --> J
    C --> W
    C --> CFG
    C --> P
    M --> F
    M --> J
  • plat_comm_task:周期性调用 v_ocpp_private_logic / v_ocpp_send_ctrl,驱动 ocpp_send_mag_ctrl;未联网或未登录分支末尾可调用 v_ocpp_mv_offline_bridge_private_logic 做离线 MV 周期采样落盘;
  • bs_public_impl:枪状态、订单 S_LOG_DATA、未结算订单 s8_plat_get_unsettled_order、结算确认等;v_ftp_update_action 在 4G 下根据 u8_log_file_upload / u8_updata_flag 调度 ec200a_4g_ftp.c 中日志或固件 FTP 状态机;
  • meter_calculate:订单写 Flash、EEPROM 临时订单、未结算索引链表(见 unsettled_order_mng)。

9.1 GetDiagnostics、4G FTP 与 PlatComm 调度(与 4g_module 衔接)

GetDiagnosticsBS_ocpp_ctrl.c 解析平台下发的 locationFTP URL、账号等),置 s_bs_task_ctrl.ocpp_data.u8_log_file_upload,并在 GetDiagnostics_res 中准备文件名、调用 v_ftp_ctrl_init() 复位 FTP 步进。须保证「先发出 CallResult / Uploading,再置 u8_updata_flag,否则与 EC200A_BLOCK_QISEND_DURING_4G_FTPu8_bs_ftp_ocpp_strict_mux 组合时可能挡掉应答(详见 4g_module/4G模块AT指令配置功能说明.md 第四节)。

4G + 非透传 时,日志上传在 ec200a_4g_ftp.c 中已改为:QFOPEN + QFSEEK + QFWRITEEC200A_FTP_UFS_RW_CHUNK_BYTES(默认 4096 分包写模组 UFSQFWRITE 在单周期内仅短等轮询,未完成则下一 FTP 半周期 续传。plat_comm_task.c 在 FTP 活跃时对 4G 采用 相邻 PlatComm 周期「仅联网 / 仅 FTP 一步」交替,与上述分包叠加后,FTP 传输期间 OCPP 仍可周期性完成 QISEND/QIRD 与 WebSocket 业务

v_ocpp_private_logic:不得在 u8_updata_flag==0 时无条件清除 u8_log_file_upload,否则会误入固件升级分支(日志出现 [FTP-UPG] 等异常);该约束与 4g_module/4G模块AT指令配置功能说明.md 第三节一致。

配置与排障(EC200A_FTP_*EC200A_FTP_LOG_DONE_TO_QISEND_DELAY_MS 等)以 ec200a_4g_cfg.h4G模块AT指令配置功能说明.md 为准。


10. 离线未结算订单处理流程(Flash 列表)

本节描述:充电正常结束或结算链路中断后,订单已写入 Flash,且索引已进入 EEPROM「未结算列表」,待 CSMS 上线后通过 OCPP 补单:本地尚无有效 transactionId(空或 0xFF 占位)时,先 Authorize(idTag),再 StartTransaction 获取流水号并写入 u8_preTradeNo,再 StopTransaction 上送订单结束信息u8_preTradeNo 已为有效流水号,则直接 StopTransaction,不再重复鉴权与 StartTransaction。

10.1 数据从哪里来(产生侧)

环节 位置 说明
订单落盘 meter_calculate_impl.cv_meterlog_flash_save_log(1, gunNo) 订单结束时 u32_chg_order_save_record 写 Flash,得到有效 orderIndexu32_index
进入未结队列 同上 u8_add_unsettled_order(orderIndex)BSP/flash_file_mgr/unsettled_order_mng.c)把该索引写入 EEPROM 未结算管理区,表示「尚未收到平台对本单的结算确认」。
典型字段 S_LOG_DATA u8_user_id、起止电量与时间、u8_preTradeNo(从未拿到 transactionId 时可能为空;离线刷卡等场景可能为 0xFF 首字节占位,u8_ocpp_is_pre_trade_no_pending 视为须先 Authorize + StartTransaction)、u8_gunNo 等。

充电过程中周期性刷新 EEPROM 临时区的逻辑见 第 11 节;正常完整结束订单后,会 清除该枪 EEPROM 临时记录v_clear_temp_chg_record_in_eeprom),并依赖 Flash 未结列表 做后续上送。

10.2 读单出口(bs_public_impl.c

S8_T s8_plat_get_unsettled_order(S_LOG_DATA *s_log, U8_T u8_type)已处理完掉电临时单 之后,走 Flash 未结逻辑:

  1. u16_get_unsettled_order_count() 为 0 则直接返回 0(无单)。
  2. u8_type == 1 时只返回数量,不读内容。
  3. 否则 v_get_unsettled_order_indexes队首 索引 currentIndex
  4. v_read_chg_order_record(s_log, currentIndex) 从 Flash 读出完整 S_LOG_DATA
  5. u8_platform_settlement_confirm(currentIndex):按当前实现,在 判断 readResult 之前 即从未结列表中移除该索引(若 Flash 读失败,存在「索引已删、数据未读出」风险,属实现细节,维护时需留意)。

返回值:>0 表示仍有未结条数(含本条);0 无单;-1 读单失败。

10.3 OCPP 何时启动补单(BS_ocpp_ctrl.c

前置条件(v_ocpp_private_logic已联网且已登录 CSMS):

  • u8_unsettled_order_flag == 0(本开机周期尚未标记「未结检查完毕」);
  • ulong_timer - u32_timer > 10(与注释「约 30 秒」对应的节流,实际以 ulong_timer 单位为准),更新 u32_timer 后调用 s8_unsettled_order_chaek()

断网或未登录时 u8_unsettled_order_flag 被置 0,不会跑未结上送;避免无链路发 OCPP。

10.4 OCPP 状态机:s8_unsettled_order_chaek

内存载体:private_ocpp_data->s_unsettled_order_data(堆上 S_LOG_DATA,一次只处理一单)。分支判定统一使用 u8_ocpp_is_pre_trade_no_pending(u8_preTradeNo)(空串或首字节 0xFF 视为「尚无有效流水号」)。

首次取单s_unsettled_order_data == NULL):

  1. OCPP_MALLOC + memsetu8_unsettled_auth_phase = NONEu32_unsettled_last_auth_s / u32_unsettled_last_stx_s 清零
  2. s8_plat_get_unsettled_order(..., 0) 填入内容;
  3. u8_user_id 为空v_safe_free_unsettled_order_data(),返回;
  4. 尚无流水号u8_ocpp_is_pre_trade_no_pending == 1):调用 u8_unsettled_pretrade_pipeline
    • OCPP_UNSETTLED_AUTH_NONE:节流后 send_mag(gunIdx, OCPP_Authorize, NULL, 1)Authorize_mags_unsettled_order_data->u8_user_id 取 idTag;成功后 u8_unsettled_auth_phase = WAIT
    • WAIT:等待 Authorize_res;仅 Accepted 时置 OK,否则释放订单;
    • OK:本单在 u32_unsettled_last_stx_s == 0 时仅 send_mag(0, OCPP_StartTransaction, NULL, 1) 一次(成功后置非零时间戳,避免重复 StartTransaction 导致平台多笔订单);StartTransaction_mag 用未结副本组 StartTransaction.reqconnectorId = u8_gunNo+1、历史 meterStart / timestamp / idTag)。
  5. 已有流水号pending == 0):send_mag(0, OCPP_StopTransaction, NULL, 1)v_safe_free_unsettled_order_data()

同一单未释放时(内存中仍持有上一笔未结单):

  • 仍按 步骤 4 / 5 区分;u8_cnt(静态) 仅用于 已有流水号StopTransaction 重试计数;无流水号路径由 u8_unsettled_pretrade_pipeline 管理(StartTransaction 每单最多成功发出一次)。

10.5 平台应答:Authorize 与 StartTransaction

  • Authorize_resu8_unsettled_auth_phase == WAIT):仅 idTagInfo.status == Accepted 时置 OCPP_UNSETTLED_AUTH_OK,否则 v_safe_free_unsettled_order_data()。解析失败时 WAIT 回退为 NONE 以便重试鉴权。
  • StartTransaction_res:若 idTagInfo.statusBlocked / Invalid / Expired / ConcurrentTx,未结补单路径不得transactionId 写入 preTradeNo,并立即释放内存(不重试 StartTransaction)。
    桩空闲u8_get_pile_state(gunNo)==0)且 s_unsettled_order_data 非空 且非上述拒绝态:将 data.transactionId 写入 u8_preTradeNou8_unsettled_auth_phase = NONE,下一周期上送 StopTransaction

注意:StopTransaction 主动发包 gunNo 常为 0,但 PDU 内 connectorId / 计量 依赖 s_unsettled_order_data->u8_gunNoAuthorize 主动发包使用 订单枪号 gunIdx,以便 CALLRESULTack_data->gunNo 一致。

10.6 StopTransactiontype=1

StopTransaction_mag(..., type==1) 使用 s_unsettled_order_datatransactionIdidTag、结束时间、meterStopreason(内部故障码映射到 StopTransactionRequest.reason,如 Local / PowerLoss 等)。


11. 掉电(异常断电)订单处理流程(EEPROM 临时记录)

本节描述:充电过程中异常断电,来不及走完整「订单结束写 Flash + 未结索引」路径时,依赖 每枪独立 EEPROM 槽位 保存的 最后一次充电快照,上电后优先恢复并走 同一套 OCPP 补单

11.1 数据何时写入 EEPROM(充电中刷新)

调用 说明
v_meterlog_flash_save_log(0, gunNo) 订单未结束,周期性把当前 s_metering_ctrl.s_gun_log[gunNo] 写入 EEPROM v_save_temp_chg_record_to_eeprom(..., TEMP_CHG_FLAG_UNSETTLED)meter_calculate_flash_impl.c)。

每枪地址互不干扰(如枪 A / 枪 B 不同 EEPROM 基址)。

11.2 正常结束订单时对 EEPROM 的处理

v_meterlog_flash_save_log(1, gunNo)(订单结束分支):写 Flash 订单、加入未结索引链 后,执行 v_clear_temp_chg_record_in_eeprom(gunNo),避免「已正规入库」仍被当成掉电单重复上传。

11.3 上电读单优先级(s8_plat_get_unsettled_order 前半段)

gunNo = 0 .. GUN_MAX_CNT-1 依次:

  1. v_check_temp_chg_record_valid(gunNo):标志为 TEMP_CHG_FLAG_UNSETTLED 或 SETTLED 类有效值 则认为有条目;
  2. v_read_temp_chg_record_from_eeprom(gunNo, s_log, NULL) 读出 S_LOG_DATA
  3. 强制 s_log->e_stop_reason[0] = E_FAULT_13073(异常掉电),用于 StopTransaction 映射为 PowerLoss 等;
  4. v_clear_temp_chg_record_in_eeprom(gunNo):读完即清标志(下次不再重复读);
  5. return 1,表示有一笔待 OCPP 处理的未结算数据。

因此:掉电单总是先于 Flash 未结队列被取出;若 EEPROM 与 Flash 同时存在数据,优先消耗掉电副本

11.4 与 OCPP 的衔接

掉电单读出后 S_LOG_DATA 同样挂在 s_unsettled_order_data 上,后续与 第 10.410.6 节 完全一致:

  • 无有效流水号Authorize(type=1)AcceptedStartTransaction(type=1) → 应答写入 preTradeNoStopTransaction(type=1)
  • 读单时已有流水号(少见)→ 直接 StopTransaction(type=1)
  • 本实现 StopTransaction 发送后即 v_safe_free_unsettled_order_data()(与 CALLRESULT 无硬耦合)。

11.5 流程示意图(合并视角)

sequenceDiagram
    participant MC as meter_calculate
    participant EEPROM as EEPROM临时区
    participant Flash as Flash订单+未结索引
    participant IMPL as s8_plat_get_unsettled_order
    participant OCPP as s8_unsettled_order_chaek

    Note over MC,EEPROM: 充电中周期
    MC->>EEPROM: v_save_temp_chg_record(UNSETTLED)

    Note over MC,Flash: 正常结束
    MC->>Flash: 写订单 + u8_add_unsettled_order
    MC->>EEPROM: clear 临时记录

    Note over EEPROM,OCPP: 上电/联网后
    EEPROM-->>IMPL: 若有有效临时记录优先读出并 clear
    Flash-->>IMPL: 否则读未结队列首条
    IMPL->>OCPP: 填充 s_unsettled_order_data
    OCPP->>OCPP: 无txId→Auth(1)→StartTx(1)→写preTradeNo→StopTx(1)

12. 两类订单的差异小结与维护注意

对比项 Flash 离线未结订单 EEPROM 掉电临时订单
典型成因 已写完订单但 CSMS 未确认结算 / StopTransaction 未成功 充电中断电,仅有最后一次周期快照
持久化位置 Flash 订单文件 + EEPROM 未结索引列表 EEPROM 按枪临时块
读取顺序 在掉电分支 之后 优先for 循环枪号顺序)
停止原因 S_LOG_DATA 内原有故障码 映射 读出后强制 E_FAULT_13073(映射 PowerLoss
OCPP 后续 相同:Authorize(1) → StartTx(1) → 填 preTradeNo → StopTx(1)(有流水号则仅 StopTx(1) 相同

实现层面已知耦合点(便于排查问题):

  1. 未结补单StopTransaction / StartTransaction 常用 send_mag(0, …)PDU 内 connectorId / 计量 依赖 s_unsettled_order_data->u8_gunNoAuthorize(type=1) 使用 send_mag(gunIdx, …)(订单枪号),以便 CALLRESULTack_data->gunNo 一致。需确认 sampled 数据是否混枪。
  2. Flash 读单后立即 u8_platform_settlement_confirm:若 Flash 读失败,可能导致索引已删。
  3. StartTransaction_res 未结算分支已对 Blocked/Invalid 等 拒绝 preTradeNo 写入;AuthorizeAccepted 会丢弃内存上下文。
  4. StopTransaction 成功后立即 free,与 StopTransaction_res 无联动;若需严格「应答后再删单」,需架构层增强。

13. 维护建议

  1. 新增 OCPP Action:在 OCPP_CMDocpp_cmd_strsend_mag switch接收分发json 组帧/解析 五处同步扩展。
  2. 新增 Configuration Key:在 bs_ocpp_str.hOCPP_CONFIG 结构体、Get/Change 分支中一并添加,并处理 Flash 默认值与长度。
  3. 测量项顺序OCPP_MEASURAND_ID 顺序不可随意插入,否则配置位图与 OCPP_measurand_str 错位。
  4. GetDiagnostics / 4G 日志 FTP:与 plat_comm / 4g_module 强相关;CallResult 与 u8_updata_flag 顺序u8_log_file_upload 勿误清PlatComm 联网与 FTP 半周期交替QFWRITE/QFREAD 分包 等见 第 9.1 节app/plat_comm/4g_module/4G模块AT指令配置功能说明.md
  5. 补单链路变更:同步核对 第 1012 节bs_public_impl.c / meter_calculate_impl.c / unsettled_order_mng 的一致性。
  6. 离线 MeterValues:改动落盘键(StartChargeTime / 枪号)、FRAM 映射、快照字段或与在线 measurand 口径时,需同时核对 BS_ocpp_mv_offline_bridge.cocpp_mv_offline_flash_impl.*u8_get_ocpp_measurand_data;释放未结单内存前须 v_ocpp_mv_offline_unsettled_abort(见 v_safe_free_unsettled_order_data)。

文档版本:2026-05 起补充 离线 MV 桥接BS_ocpp_ctrl.c 分区说明;与当前 CCU601E_D app/plat_comm/ocpp 目录一致,若后续增减文件请同步更新第二节表格。