# IES 积成平台通信移植方案(CCU601_A → CCU601E_D) 本文档基于 **`CCU601_A_20240601\app\platform`** 中积成智通(IESZT)协议实现,对照 **`CCU601E_D\app\plat_comm`** 现有联网框架(`plat_comm_task` + `bs_connect_impl` + `bs_public_impl`),给出在 E 工程中**新增 IES 平台连接**的分阶段实现方案。 --- ## 0. 备份说明 已在本机创建工程目录备份(不含 `MDK-ARM\output` 编译产物,以缩短拷贝时间): | 路径 | |------| | `d:\Desktop\NewProject\cursor\EuropeanStandard\CCU601E_D_backup_20260519` | 如需完整含编译输出的备份,可在资源管理器中自行复制整个 `CCU601E_D` 目录。 --- ## 1. 源工程(CCU601_A)IES 模块概览 ### 1.1 文件与职责 | 文件 | 行级规模(约) | 职责 | |------|----------------|------| | **`BS_ies_ctrl.h`** | 协议常量 + `S_IES_CTRL_DATA` | 帧类型码 `NT_*`、数据对象、对外 API | | **`BS_ies_ctrl.c`** | ~560 行 | 回调注册、TCP/4G 建链、登录、收包解帧、私有超时逻辑 | | **`BS_ies_interface.h/c`** | ~1800+ 行 | **组帧/解帧**:登录、心跳、费率、实时数据、账单、远程启停、对时、FTP 升级、二维码等 | | **`BS_Task.c/h`** | ~1150 行 | **平台任务总线**:周期发送、双枪调度、`bs_register_callback`、`Task_BS` 主循环 | | **`FtpUpdate.c`** | FTP 升级 | 与 `NT_UPDATE_AUTO(0x90)` 配合(A 侧旧 FTP 流程) | | **`BS_WH_GM5.c`** | 4G 模组 | A 工程 **WH-GM5** 透传/AT(**E 工程为 EC200A,不可直接搬**) | ### 1.2 协议特征(与 OCPP 差异) 积成协议为 **二进制定长头 + 变长数据域**,非 JSON/WebSocket。 ``` 帧起始 0x68 | 长度 2B | 序号 1B | 设备地址 16B ASCII | 加密 1B | 数据对象 1B | 帧类型 1B | 数据域 N | 校验 1B ``` - **协议版本**:`NT_PTL_VERSION = 37`(V3.5) - **帧类型码**:登录 `0x01/0x02`、心跳 `0x03/0x04`、充电实时 `0x11/0x13`、账单 `0x47/0x48`、远程启停 `0x44~0x46`、对时 `0x76`、计费 `0x7D/0x7E`、FTP `0x90` 等(见 `BS_ies_ctrl.h`) - **校验**:序号域至数据域末字节 **累加和**(`u8_crc_checkSum`) - **粘包**:`v_bs_unpack_handle_ieszt` 按 `0x68` 搜头、长度域算整帧长 ### 1.3 A 侧任务模型 ```mermaid flowchart TB subgraph Task_BS TCP[v_bs_tcp_connect] LOG[v_ies_logo_on / v_bs_register_req] SEND[v_bs_send_ctrl] RECV[v_ies_recv_data → unpack] PRIV[v_ies_private_crel] end subgraph callbacks IF[BS_ies_interface 组帧] end SEND -->|E_BS_CALLBACK_CMD| IF IF -->|com_read / eth_send| LINK[4G WH_GM5 / 以太网 socket] ``` - **发送**:`BS_Task.c` 中 `v_bs_send_ctrl(bs_flag)` 按周期/标志调用 `v_bs_callback(cmd, gun)`,IES 在 `v_bs_ies_register_callback()` 中注册具体组帧函数。 - **接收**:`v_ies_recv_data()` → `v_bs_unpack_handle_ieszt()` → `v_bs_rx_cmd_hanle()` 按 `u8_recvBuf[22]` 帧类型分发。 - **登录成功**:`v_bs_register_ack()` 内置 `u8_register_flag = 1`,并置 `bs_ctrl_data[].u8_log_on_flag`(与 E 的 `u8_log_on_flag` 概念一致)。 --- ## 2. 目标工程(CCU601E_D)现状 ### 2.1 已有挂钩(未实现) | 位置 | 内容 | |------|------| | **`public_define.h`** | `BS_IES_EN` 默认 **0** | | **`plat_comm_task.c`** | `MasterFuncArray` 已预留 **`"ieszt"`** 槽位及 7 个回调函数名 | | **`plat_comm_task.h`** | `#include "plat_comm/ieszt/bs_ies_ctrl.h"`、`S_BS_IES_CTRL_DATA s_ies_data` | | **目录** | **`plat_comm/ieszt/` 尚不存在**(编译开启 `BS_IES_EN` 会缺文件) | E 侧 **`MasterFuncPtl`** 比 A 多一项 **`v_bs_recv_unpack`**(OCPP 未用;IES 可将解帧放在 `v_ies_recv_data` 内,**`v_ies_recv_unpack` 可留空**)。 ### 2.2 E 侧应复用的基础设施(禁止重复造轮子) | 模块 | 用途 | |------|------| | **`plat_comm_task.c`** | `v_Plat_Comm` 主循环、FTP/联网分时、`v_set_bs_renew` | | **`bs_connect_impl.c`** | **`u8_tcp_connect`**、**`v_bs_send`**、**`u16_bs_recv`**(4G EC200A + 网口 LwIP/TLS) | | **`bs_public_impl.c`** | 枪状态、**`S_LOG_DATA`** 订单、启停 **`v_bs_charge_action_ctrl`**、未结/掉电 **`s8_plat_get_unsettled_order`** | | **`meter_calculate`** | 计量订单、EEPROM 临时单、Flash 未结索引 | | **`flowctrl`** | `u8_bs_get_flow_state`(E 已有,替代 A 的 `e_get_flow_rt_state`) | | **`v_ftp_update_action`** | OCPP/平台 FTP 升级;IES `0x90` 需映射到 **`t_ftp_update_info`** + `u8_updata_flag` | ### 2.3 A → E 关键差异对照 | 维度 | CCU601_A | CCU601E_D | |------|----------|-----------| | RTOS / 任务 | `Task_BS` + `GetCurSecond` | `v_Plat_Comm` + `get_current_seconds` | | 4G | WH-GM5、`com_read(COM_PORT_BS)` | **EC200A**、`v_ec200a_tcp_app_send/recv` | | 网口 | `eth_connect` / `CreatSocket` 直连 | **`lwip_tcp_connect`** + `v_bs_eth_close_socket` | | 订单结构 | **`CHARGE_LOG_T`** | **`S_LOG_DATA`** | | 双平台控制块 | **`bs_ctrl_data[MAX_BS_NUM]`** | **`s_bs_task_ctrl.s_bs_ctrl[]`** + 可选 **`s_ies_data`** | | 平台协议 | SDK + IES 二选一或双开 | **OCPP** + 可选 **IES**(`MAX_BS_NUM=2`) | | 日志 | `logMsg_bs` | **`Plat_Comm_LOG` / `MYLOG_MSG`** | --- ## 3. 目标架构(移植后) ```mermaid flowchart TB subgraph PlatComm PC[v_Plat_Comm] M[MasterFuncArray slot: ieszt] end subgraph ieszt CTRL[bs_ies_ctrl.c] IF[bs_ies_interface.c] SEND[v_ies_send_ctrl] end subgraph impl CONN[bs_connect_impl] PUB[bs_public_impl] end PC --> M M --> CTRL SEND --> IF IF --> CONN CTRL --> PUB CONN --> EC200A[4G EC200A] CONN --> LWIP[LwIP TCP/TLS] ``` **原则** 1. **IES 只实现「积成二进制协议」**;TCP/4G/网口/TLS **一律走 `bs_connect_impl`**。 2. **业务数据只通过 `bs_public_impl` + `meter_calculate`** 读写,不在 IES 模块内直接碰 flow 内部结构。 3. **周期发送**可移植 A 的 `E_BS_CALLBACK_CMD` 模型,但计时器挂到 **`s_bs_task_ctrl.s_bs_ctrl[ies_id]`** 或独立 **`S_BS_IES_CTRL_DATA`**,由 **`v_ies_send_ctrl`** 在已登录分支执行(与 OCPP 的 `v_ocpp_send_ctrl` 同级)。 --- ## 4. 建议目录与文件清单 在 **`CCU601E_D/app/plat_comm/ieszt/`**(运行时说明见 **`ieszt/IES积成平台功能说明.md`**,与 **`平台联网任务功能说明.md`** 联动)新建: | 文件 | 来源 | 说明 | |------|------|------| | **`bs_ies_ctrl.h`** | 自 A `BS_ies_ctrl.h` 改编 | 帧类型码、`S_BS_IES_CTRL_DATA`(合并原 `S_IES_CTRL_DATA` + 必要定时器) | | **`bs_ies_ctrl.c`** | 自 A `BS_ies_ctrl.c` 重构 | 去掉 WH_GM5/CreatSocket;改用 `u8_tcp_connect(id)`、`v_bs_send`、`u16_bs_recv` | | **`bs_ies_interface.h`** | 自 A `BS_ies_interface.h` | 组帧/解帧 API | | **`bs_ies_interface.c`** | 自 A `BS_ies_interface.c` | 大文件;发送改为 `v_bs_send`;桩号从 `u8_get_str_data(E_STR_PILE_NO)` 获取 | | **`bs_ies_send.c`**(可选) | 自 A `BS_Task.c` 抽取 | `v_ies_send_ctrl`、`v_ies_register_callback`、双枪周期逻辑,减小单文件体积 | | **`bs_ies_adapter.c/h`**(建议新建) | 新写 | **`S_LOG_DATA` ↔ 账单组帧字段**、停止原因 **E_FAULT_* → IESZT_REASON** | **不迁入 E 工程(或仅参考)** - `BS_WH_GM5.c/h` → 使用现有 **`ec200a_4g.c`** - `BS_sdk_*` → 与 IES 无关 - A 版 `FtpUpdate.c` 中与 OCPP 重复部分 → 统一 **`v_ftp_update_action`** + `ec200a_4g_ftp` / `lwip_ftp_upgrade` --- ## 5. 接口映射(MasterFuncPtl 七件套) | 回调 | 实现要点 | |------|----------| | **`v_ies_init_data(U8_T id)`** | `id` 写入 `s_ies_data.u8_bs_flag`;`v_ies_register_callback()`;清 `s_ies_data`;**不要**调用 `v_bs_4G_data_init`(由 `u8_tcp_connect` 统一处理);帧序号 `u16_msgSerialNumber=0` | | **`v_ies_tcp_connect(void)`** | 返回 **`u8_tcp_connect(s_ies_data.u8_bs_flag)`** 结果;删除 A 中 `v_WH_GM5_init`、独立 `CreatSocket` | | **`v_ies_logo_on(void)`** | 周期发 **`v_bs_register_req()`**(约 20s);**`v_bs_register_ack`** 内置置位后返回 1;登录超时 6 次 → **`v_set_bs_renew(id)`** + 仅重置 IES 私有数据(**勿全量 `v_ocpp_init_data`**) | | **`v_ies_recv_data(void)`** | `u16_bs_recv(id, buf, len)`;若 `u8_updata_flag` 且 4G FTP 活跃则可直接 return(与 A 一致) | | **`v_ies_recv_unpack(id, buf, len)`** | **建议空实现**;解帧已在 `v_ies_recv_data` 完成。若未来 UART 分包由外部注入,再迁入 `v_bs_unpack_handle_ieszt` | | **`v_ies_send_ctrl(void)`** | 移植 A **`v_bs_send_ctrl(ies_flag)`**:登录后心跳、费率、空闲/充电实时、表底、告警、账单、即插即充、离线单等 | | **`v_ies_private_logic(U8_T id)`** | 心跳无应答计数、登录态维护、**`v_cheak_state_change` 类逻辑**(改调 E 的 `v_bs_log_txFlag_*`)、离线订单 **`s8_plat_get_unsettled_order` 路径**(可选与 OCPP 互斥) | --- ## 6. 数据与业务适配层(`bs_ies_adapter`) ### 6.1 订单 / 账单(`NT_BILL_UPLOAD 0x47`) A:`v_get_log_data` / `v_gunTmpChgRcd_rd` + `CHARGE_LOG_T` → `v_bs_bill_pack`。 E 建议: ```c S_LOG_DATA log; u8_plat_get_real_order(&log, gun) 或 s8_plat_get_unsettled_order(&log, 0); v_ies_bill_pack_from_log(gun, &log); ``` - **`u8_preTradeNo`**:IES 账单字段与 A 一致处直接 `memcpy`;无平台流水号时用设备流水号或占位规则与运营确认。 - **停充原因**:`log.e_stop_reason[0]` 经 **`v_ies_map_stop_reason_to_ieszt()`** 转为 `IESZT_REASON_E`(A 已在 `BS_Task.c` 有大表,可迁到 adapter)。 ### 6.2 远程启停(`0x44` / `0x46`) A:`v_bs_rmt_start/stop` 内调 flow/UI。 E: ```c S_BS_CHAR_CTRL ctrl; memset(&ctrl, 0, sizeof(ctrl)); ctrl.u16_ctrl_res = E_NORMAL_1002; /* 或映射平台原因 */ v_bs_charge_action_ctrl(gun, E_CHAR_CTRL_STOP, &ctrl); ``` 启机需组 **`S_CHAR_LOG_START_DATA`** 后 `E_CHAR_CTRL_START`,与 OCPP RemoteStart 路径对齐,避免双协议冲突(见 §8)。 ### 6.3 对时(`NT_CLK_SYNC_REQ 0x76`) A:写 RTC。 E:**`v_bs_set_time(&Comm_Time)`**(`bs_public_impl` 已有)。 ### 6.4 计费模型(`0x05/0x06/0x7D/0x7E`) A:写费率 Flash/共享区。 E:对接 **`meter_calculate` / 费率存储**(`u32_meterlog_get_sys_data(E_METERLOG_GET_DATA_FEE_*)` 或现有配置接口),需与产品确认 IES 费率 PDU 与 E 侧 96 时段模型是否一致。 ### 6.5 实时数据(`0x11` / `0x13`) 字段来源改为: - 电压电流 SOC:`u32_bs_get_sys_data` / `u64_bs_get_sys_data` - 枪状态:`u8_bs_get_flow_state`、`E_BS_GET_SYS_DATA_GUN_STATE` - 电量:`E_BS_GET_SYS_DATA_MEMTER_ELECT` ### 6.6 FTP 升级(`NT_UPDATE_AUTO 0x90`) 解析平台下发的 FTP 参数 → 填充 **`t_ftp_update_info`** → 置对应槽位 **`u8_updata_flag=1`** → 由现有 **`v_ftp_update_action`** 执行(4G/网口分支已有)。 --- ## 7. 配置与编译集成 ### 7.1 宏与工程配置 ```c /* public_define.h */ #define BS_IES_EN (1) /* 使能积成平台 */ #define BS_OCPP_EN (1) /* 可与 OCPP 双平台:槽位 0=OCPP,1=IES,由 PLAT_EN 决定 */ ``` - Keil / CMake:将 **`plat_comm/ieszt/*.c`** 加入 **PlatComm** 分组。 - 确认 **`plat_comm_task.h`** 中 `S_BS_IES_CTRL_DATA` 与 `bs_ies_ctrl.h` 定义一致(或 typedef 别名)。 ### 7.2 系统参数(与 A 对齐项) | 配置项 | A 来源 | E 建议 | |--------|--------|--------| | 主站 IP/端口 | `u8_remote_ip` / `u16_remote_port` | 继续用 **`t_sys_fix_cfg`**;IES **不用** WebSocket URL,可用 **纯 `tcp://ip:port`** 或单独 **IES 服务器配置项**(若与 OCPP 域名不同,需在配置表增加字段,避免与 `u8_serverA_domain_name` 混用) | | 桩号 16 字节 | `u8_pile_serial_num` | `u8_get_str_data(E_STR_PILE_NO)` | | 平台使能 | `bs_type[]` 初始化 | `E_BS_GET_SYS_DATA_PLAT_EN` per 槽位 | | 联网方式 | `e_network_type` | `E_BS_GET_SYS_DATA_NET_TYPE` | ### 7.3 `MasterFuncArray` 注册示例 与现有 `plat_comm_task.c` 一致,确保 **`BS_IES_EN`** 时槽位与 **`PLAT_EN`** 配置对应,例如: - 槽位 0:OCPP(`BS_OCPP_EN`) - 槽位 1:IES(`BS_IES_EN`) 双平台同时使能时,**两路独立 `u8_TCP_connect_flag` / `u8_log_on_flag`**,互不覆盖。 --- ## 8. 双平台共存策略(OCPP + IES) | 风险 | 策略 | |------|------| | 同一枪被 OCPP RemoteStart 与 IES `0x44` 同时控制 | 产品层约定:**仅一个平台为主**;或 `PLAT_EN` 互斥。代码层在 `v_bs_rmt_start` 中判断 **`u8_bs_get_flow_state==0`** 且 OCPP 未在充。 | | 离线订单双路上送 | E 未结索引统一 **`unsettled_order_mng`**;IES 掉电单走 **`s8_plat_get_unsettled_order`** 时与 OCPP **互斥处理**(同一单不两协议各 Stop 一次)。 | | 4G UART 占用 | OCPP 与 IES **共用 `bs_connect_impl`** 时,**不能两槽位同时 `u8_netType==0` 各建一条 Socket**,除非运营确认为双连接;通常 **一机一路 4G 一个 TCP** → **双平台只选其一或网口+4G 分流**。 | | FTP 与 IES 收包 | 保持 **`plat_comm_task` FTP/联网分时**;IES **`v_ies_recv_data`** 在 FTP 周期不解析 IES 帧(与 A 相同 guard)。 | --- ## 9. 分阶段实施计划 ### 阶段 1:骨架可编译(1~2 天) - [ ] 创建 `plat_comm/ieszt/`,迁入 **`bs_ies_ctrl.h`**、精简 **`bs_ies_ctrl.c`**(`init/tcp_connect/logo_on/recv/private` 空壳 + `u8_tcp_connect`) - [ ] **`BS_IES_EN=1`** 编译通过;`v_ies_recv_unpack` 空实现 - [ ] 槽位 **`bs_enable=1`** 时能进 `v_Plat_Comm` 建链日志 ### 阶段 2:链路 + 登录心跳(2~3 天) - [ ] 迁入 **`bs_ies_interface.c`** 中:`u8_bs_pack_frm_head`、`v_bs_register_req/ack`、`v_bs_heart/ack`、`u8_crc_checkSum` - [ ] 收包粘包 **`v_bs_unpack_handle_ieszt`** - [ ] 实机验证:**Login 0x02**、**Heartbeat 0x04**、平台对时(若有) ### 阶段 3:运营关键帧(3~5 天) - [ ] **`v_bs_rtd_free` / `v_bs_rtd_chging`** + `v_ies_send_ctrl` 周期表(对齐 A:心跳 20s、充电 30s、空闲 180s 等) - [ ] **`v_bs_bill_pack`** + adapter 从 **`S_LOG_DATA`** - [ ] **`v_bs_rmt_start/stop`** → `v_bs_charge_action_ctrl` - [ ] **`v_bs_bill_upload_ack`** → `v_bs_platform_settlement_confirm` / 清 EEPROM 临时单 ### 阶段 4:增强与对齐(按需) - [ ] 计费模型 `0x7D/0x7E`、二维码 `0x08/0x0A`、故障 `0x15`、表底 `0x31` - [ ] FTP `0x90` → `t_ftp_update_info` - [ ] 掉电未结:与 **`meter_calculate` EEPROM 恢复**、**`s8_plat_get_unsettled_order`** 联调 - [ ] 双枪 `u8_bs_twoGnu_send` 逻辑迁入 ### 阶段 5:测试与文档 - [ ] 用例:4G / 网线、单枪/双枪、远程启停、断网重连、充电中离线、掉电上电补单 - [ ] 更新 **`平台联网任务功能说明.md`** 增加 IES 章节 --- ## 10. 接收发送伪代码(E 风格) ```c void v_ies_recv_data(void) { U8_T id = s_ies_data.u8_bs_flag; U8_T buf[512]; U16_T n; if (s_bs_task_ctrl.s_bs_ctrl[id].u8_updata_flag != 0U && s_bs_task_ctrl.s_bs_ctrl[id].u8_netType == 0U) { return; } n = u16_bs_recv(id, buf, sizeof(buf)); if (n > 0U) { v_bs_unpack_handle_ieszt(buf, (S16_T)n); } } static void v_ies_send_frame(U8_T *frm, U16_T len) { v_bs_send(s_ies_data.u8_bs_flag, frm, len); } ``` --- ## 11. 测试验收标准(摘要) | 编号 | 项 | 通过标准 | |------|-----|----------| | T1 | TCP | `PlatComm` 打印 `tcp connect`,平台侧可见连接 | | T2 | 登录 | 收到 `0x02`,`u8_log_on_flag=1`,桩号与配置一致 | | T3 | 心跳 | 周期 `0x03`,平台 `0x04`,断链后 `v_set_bs_renew` 可恢复 | | T4 | 充电实时 | 充电中 `0x11`、空闲 `0x13` 周期上送,数据与电表一致 | | T5 | 账单 | 停充后 `0x47`,平台 `0x48` 后本地未结清除 | | T6 | 远程停 | 平台 `0x46` 后枪停止,原因码正确 | | T7 | 掉电 | 有 txId 的订单恢复后账单 **transactionId 非 0**(与 OCPP 掉电修复一致) | --- ## 12. 关联文档 | 文档 | 路径 | |------|------| | E 联网任务总览 | `plat_comm/平台联网任务功能说明.md` | | OCPP 模块 | `plat_comm/ocpp/OCPP功能模块说明.md` | | 4G EC200A | `plat_comm/4g_module/4G模块AT指令配置功能说明.md` | | 源 IES 协议头 | `CCU601_A_20240601/app/platform/BS_ies_ctrl.h` | --- *文档版本:2026-05-19;随 `plat_comm/ieszt` 落地情况更新勾选清单。*