# CCU–POS VTK 串口结算功能设计说明(草案) 版本:v0.1 协议参考:`vtk-protocol-en-1.23.pdf`(VTK protocol 1.23) --- ## 1. 应用场景概述 - **角色** - **VMC(Vending Machine Controller)**:本项目中的 **CCU 主控**,负责充电控制、计量和向 POS 发起扣款 / 结算请求。 - **POS 终端**:支持 VTK 协议的支付终端,完成银行卡 / 钱包扣款,并把结果回传给 CCU。 - **业务流程(高层逻辑)** 1. 车主在充电桩侧操作“启动充电”(扫码 / 刷卡 / 远程指令等),CCU 准备启动充电流程。 2. CCU 根据配置计算 **预扣款金额**(例如 50 元,可配置)。 3. CCU 通过 **串口上的 VTK 协议** 向 POS 发送“预扣款请求”消息,请求冻结该金额。 4. POS 完成预扣并返回“通过 / 拒绝 / 超时”等结果: - 通过:CCU 进入正常充电流程。 - 拒绝:CCU 不启动充电,向用户提示相应原因。 5. 充电完成(正常结束 / 故障结束 / 用户中止)后,CCU 计算 **最终充电金额**(按电量 / 时间 / 固定服务费等计费规则)。 6. CCU 再次通过 VTK 协议向 POS 发送“结算请求”,携带最终金额以及会话标识。 7. POS 根据最终金额完成扣款 / 退款(与预扣差额),返回结算结果。 8. CCU 记录最终结算结果到本地订单 / 日志系统,并更新 UI / 平台状态。 - **通信方式** - 物理层:**串口(UART)**,波特率等推荐按 VTK 文档默认值:`115200 8N1,无流控`。 - 链路层:可选择直接使用原始串口帧结构(1F 起始 + 长度 + 协议号 + TLV + CRC16)。 - 应用层:严格遵循 VTK base protocol(`0x96FB/0x97FB`)的 TLV 编码要求。 --- ## 2. VTK 协议要点(与本项目相关部分) ### 2.1 基本帧格式(串口模式) 参考文档第 2 章,串口下消息帧结构: - `Start`:1 字节,固定 `0x1F` - `Length`:2 字节,大端,表示“后续所有数据长度(不含 CRC16)” - `Protocol discriminator`:2 字节,大端 - `0x96FB`:VMC → POS - `0x97FB`:POS → VMC - `Application message`:0..65533 字节,**BER TLV**(ISO/IEC 8825-1) - `CRC16`:2 字节,大端,CRC16-CCITT(初始值 0xFFFF),从 `Start` 到 TLV 最后一字节 ### 2.2 TLV 参数 VTK base protocol 中应用消息是多个 TLV 参数的组合: - `Tag`:1~3 字节(此协议中基本为单字节 Tag,例如 `0x01` Message name、`0x04` Amount 等) - `Length`:1~3 字节 - `Value`:具体值(ASCII / Binary / UTF-8) 本项目中 **优先使用的 Tag**(参考文档 3.1): - `0x01`:Message name(ASCII 3)—— 如 `"CDP"`, `"CRD"`, `"INF"`, `"PRS"` 等。 - `0x03`:Operation number(ASCII 数字,8 位)—— 可做一次充电会话的 ID。 - `0x04`:Amount in minor currency unit(ASCII,金额的“最小货币单位”,例如分)。 - `0x11`:Local time(可选,用于时钟同步)。 - `0x12`:System information(可选,用于 POS 侧展示桩信息)。 > 后续业务实现只需先支持必要的 Tag,留出扩展空间即可。 --- ## 3. 业务消息与状态机设计(草案) ### 3.1 关键业务实体 - **ChargeSession(充电会话)** - `sessionId`:对应 VTK 的 Operation number(Tag 0x03)。 - `gunNo`:枪号(0/1/...)。 - `preAuthAmount`:预扣款金额(单位:分)。 - `finalAmount`:最终金额(单位:分)。 - `state`:`Idle / PreAuthPending / PreAuthOk / Charging / SettlePending / Settled / Failed`。 - **VTKOperation** - `messageName`(Tag 0x01):例如 `"CDP"`(预扣款)、`"CRD"`(结算)等。 - `direction`:`VMC→POS` 或 `POS→VMC`。 - `tlvList`:一个 TLV 参数列表。 ### 3.2 建议消息映射(可根据实际对接调整) - **预扣款请求**(CCU→POS) - Message name (`0x01`):`"CDP"`(或自定义,如 `"CHP"`:Charge PreAuth) - Operation number (`0x03`):本次充电会话 ID(ASCII 数字) - Amount (`0x04`):预扣款金额,单位“分”,例如 5000 表示 50.00 元 - **预扣款响应**(POS→CCU) - Message name (`0x01`):`"CDP"`(同请求) - Operation number (`0x03`):与请求一致 - Amount (`0x04`):实际冻结金额(可与请求相同) - 结果参数:可以使用 System information 或自定义扩展的 Simple data block(`0x0D`)中定义结果码,例如: - `0`:Approved - `1`:Declined - `2`:Timeout - **结算请求**(CCU→POS) - Message name (`0x01`):`"CRD"`(Charge Debit / Refund) - Operation number (`0x03`):与本会话相同 - Amount (`0x04`):实际消费总金额(分) - **结算响应**(POS→CCU) - Message name (`0x01`):`"CRD"` - Operation number (`0x03`):同请求 - Amount (`0x04`):最终扣款金额 - 结果码(同上) ### 3.3 CCU 侧状态机(简化) 1. **Idle** - 等待用户操作(插枪、刷卡、平台下发启动命令)。 2. **PreAuthPending** - 组包 VTK `CDP` 预扣款请求,通过串口发给 POS。 - 等待响应(配置超时,例如 15s),期间可处理心跳 / 重发。 3. **PreAuthOk** - 收到 POS 批准预扣款,更新内部状态,允许充电流程进入 **Charging**。 4. **Charging** - 现有充电流程不变(BMS/流控/计量)。 5. **SettlePending** - 充电结束,计算 `finalAmount`,组包 VTK `CRD` 结算请求,发送给 POS。 - 等待响应;失败可重试若干次或降级处理(仅记录本地订单,提示用户到平台查询)。 6. **Settled / Failed** - Settled:记录成功订单,通知平台/界面。 - Failed:记录失败原因(网络/卡拒绝/超时),可与平台对账或人工处理。 --- ## 4. 模块划分与文件结构建议 在 `CCU601E_RUN/app/pos_vtk` 目录下建议创建如下模块(后续实现时使用): 1. **基础协议层** - `vtk_frame.c / vtk_frame.h` - 串口帧封装 / 解封装(1F 起始、长度、协议号、CRC16)。 - CRC16-CCITT 实现(参考文档第 5 章)。 - `vtk_tlv.c / vtk_tlv.h` - TLV 编码 / 解码(Tag/Length/Value)。 - 提供便捷接口:`addAsciiParam(tag, QString)`, `getAsciiParam(tag, ...)` 等。 2. **业务协议层** - `vtk_pos_protocol.c / vtk_pos_protocol.h` - 构造/解析 **预扣款请求/响应**、**结算请求/响应**、**系统信息** 等应用消息: - `buildPreAuthRequest(session, preAuthAmount, QByteArray &outFrame)` - `parsePreAuthResponse(const QByteArray &frame, VtkResult &out)` - `buildSettleRequest(...)` / `parseSettleResponse(...)` 3. **会话与状态机层** - `pos_vtk_service.c / pos_vtk_service.h` - 维护每把枪的 `ChargeSession` 状态: - `posVtk_startPreAuth(gunNo, amount)` - `posVtk_onFrameReceived(frame)` —— 调用基础解析,然后驱动状态机 - `posVtk_notifyChargeEnd(gunNo, finalAmount)` —— 进入结算流程 - 与现有 `flowctrl_task`/`collect_task`/`meter_calculate`/`plat_comm_task` 对接。 4. **串口接入层** - 若已有串口任务(如 `uart_task`),只需在串口接收回调中把 VTK 帧交给 `vtk_frame` 层解析。 - 若没有,可在 `app_init` 或 `plat_comm_task` 下新增 POS 串口任务: - 周期读取串口缓存、拼帧、调用 `posVtk_onFrameReceived`。 --- ## 5. 与现有 CCU 模块的集成点 - **启动充电**:在当前启动充电逻辑中(flowctrl / bms / collect),增加“调用 `posVtk_startPreAuth`”步骤,并根据其结果决定是否允许进入充电状态。 - **停止充电**:在充电任务或计量模块中,当确定实际消费金额后,调用 `posVtk_notifyChargeEnd` 进入结算流程。 - **告警与 UI 提示**: - 预扣款失败:在 UI 或平台上显示“支付预授权失败,请重试或更换支付方式”。 - 结算失败:记录订单异常状态,提示用户可联系运营方处理。 --- ## 6. 后续实施步骤建议 1. **确认业务映射**:与 POS 提供方确认使用的 Message name(CDP/CRD/INF 等)、结果码格式以及参数集合。 2. **实现基础协议层**:`vtk_frame` + `vtk_tlv`,并通过单元测试校验: - CRC 计算正确。 - TLV 编解码对齐文档。 3. **实现预扣款 / 结算消息构造与解析**:`vtk_pos_protocol`。 4. **实现 POS 会话状态机**:`pos_vtk_service`,并与现有充电流程打通(只改入口/出口逻辑,尽量不动核心 BMS/MDU 代码)。 5. **集成串口任务**:选定 UART 口,完成收发调试(先用日志工具验证 VTK 帧格式)。 6. **与实际 POS 联调**:根据联调结果调整错误码处理、超时重试策略等。 --- ## 7. 示例报文 以下示例仅展示 **TLV 内容和串口帧结构**,CRC16 按实现自动计算,示例中不逐字列出。 ### 7.1 预扣款请求(CDP) - 业务参数: - Message name:`"CDP"`(Tag 0x01) - Operation number:`"12345"`(Tag 0x03,十进制 ASCII) - Amount:`"5000"`(Tag 0x04,表示 50.00 元) - TLV 区段(十六进制): - `01 03 43 44 50` - Tag=0x01,Len=0x03,Value="CDP" - `03 05 31 32 33 34 35` - Tag=0x03,Len=0x05,Value="12345" - `04 04 35 30 30 30` - Tag=0x04,Len=0x04,Value="5000" - 串口帧结构: - `1F` 起始字节 - `00 LL` Length(2 字节,大端,= ProtocolDisc + TLV 长度) - `96 FB` Protocol discriminator(VMC→POS) - `01 03 43 44 50 03 05 31 32 33 34 35 04 04 35 30 30 30` TLV 数据 - `CC CC` CRC16-CCITT(由代码计算) ### 7.2 结算请求(CRD) - 参数示意: - Message name:`"CRD"`(0x01) - Operation number:与预扣款相同 `"12345"`(0x03) - Amount:最终金额 `"4200"`(0x04,表示 42.00 元) TLV 结构与上例相同,仅值不同。 ### 7.3 响应报文(POS→CCU) - 假设 POS 对预扣款返回: - Message name:`"CDP"` - Operation number:`"12345"` - Amount:`"5000"` - Result:Tag 0x0D,Length=1,Value=0x00(Approved) TLV 区段: - `01 03 43 44 50` (CDP) - `03 05 31 32 33 34 35` (Operation number) - `04 04 35 30 30 30` (Amount) - `0D 01 00` (Simple data block,结果码=0) 串口帧中的 Protocol discriminator 为 `0x97FB`(POS→VMC)。 --- > 说明:本文件为第一版设计草案和实现说明,后续在实际联调和业务确认过程中,可根据需要继续细化: > - 完善错误码与 POS 侧状态码的映射 > - 增加更多业务消息(如 INF、PRS 等) > - 完善异常流程(网络断开、POS 重启、CRC 错误等)的处理策略。