9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
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。
-
业务流程(高层逻辑)
- 车主在充电桩侧操作“启动充电”(扫码 / 刷卡 / 远程指令等),CCU 准备启动充电流程。
- CCU 根据配置计算 预扣款金额(例如 50 元,可配置)。
- CCU 通过 串口上的 VTK 协议 向 POS 发送“预扣款请求”消息,请求冻结该金额。
- POS 完成预扣并返回“通过 / 拒绝 / 超时”等结果:
- 通过:CCU 进入正常充电流程。
- 拒绝:CCU 不启动充电,向用户提示相应原因。
- 充电完成(正常结束 / 故障结束 / 用户中止)后,CCU 计算 最终充电金额(按电量 / 时间 / 固定服务费等计费规则)。
- CCU 再次通过 VTK 协议向 POS 发送“结算请求”,携带最终金额以及会话标识。
- POS 根据最终金额完成扣款 / 退款(与预扣差额),返回结算结果。
- CCU 记录最终结算结果到本地订单 / 日志系统,并更新 UI / 平台状态。
-
通信方式
- 物理层:串口(UART),波特率等推荐按 VTK 文档默认值:
115200 8N1,无流控。 - 链路层:可选择直接使用原始串口帧结构(1F 起始 + 长度 + 协议号 + TLV + CRC16)。
- 应用层:严格遵循 VTK base protocol(
0x96FB/0x97FB)的 TLV 编码要求。
- 物理层:串口(UART),波特率等推荐按 VTK 文档默认值:
2. VTK 协议要点(与本项目相关部分)
2.1 基本帧格式(串口模式)
参考文档第 2 章,串口下消息帧结构:
Start:1 字节,固定0x1FLength:2 字节,大端,表示“后续所有数据长度(不含 CRC16)”Protocol discriminator:2 字节,大端0x96FB:VMC → POS0x97FB: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,例如0x01Message name、0x04Amount 等)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 元
- Message name (
-
预扣款响应(POS→CCU)
- Message name (
0x01):"CDP"(同请求) - Operation number (
0x03):与请求一致 - Amount (
0x04):实际冻结金额(可与请求相同) - 结果参数:可以使用 System information 或自定义扩展的 Simple data block(
0x0D)中定义结果码,例如:0:Approved1:Declined2:Timeout
- Message name (
-
结算请求(CCU→POS)
- Message name (
0x01):"CRD"(Charge Debit / Refund) - Operation number (
0x03):与本会话相同 - Amount (
0x04):实际消费总金额(分)
- Message name (
-
结算响应(POS→CCU)
- Message name (
0x01):"CRD" - Operation number (
0x03):同请求 - Amount (
0x04):最终扣款金额 - 结果码(同上)
- Message name (
3.3 CCU 侧状态机(简化)
-
Idle
- 等待用户操作(插枪、刷卡、平台下发启动命令)。
-
PreAuthPending
- 组包 VTK
CDP预扣款请求,通过串口发给 POS。 - 等待响应(配置超时,例如 15s),期间可处理心跳 / 重发。
- 组包 VTK
-
PreAuthOk
- 收到 POS 批准预扣款,更新内部状态,允许充电流程进入 Charging。
-
Charging
- 现有充电流程不变(BMS/流控/计量)。
-
SettlePending
- 充电结束,计算
finalAmount,组包 VTKCRD结算请求,发送给 POS。 - 等待响应;失败可重试若干次或降级处理(仅记录本地订单,提示用户到平台查询)。
- 充电结束,计算
-
Settled / Failed
- Settled:记录成功订单,通知平台/界面。
- Failed:记录失败原因(网络/卡拒绝/超时),可与平台对账或人工处理。
4. 模块划分与文件结构建议
在 CCU601E_RUN/app/pos_vtk 目录下建议创建如下模块(后续实现时使用):
-
基础协议层
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, ...)等。
-
业务协议层
vtk_pos_protocol.c / vtk_pos_protocol.h- 构造/解析 预扣款请求/响应、结算请求/响应、系统信息 等应用消息:
buildPreAuthRequest(session, preAuthAmount, QByteArray &outFrame)parsePreAuthResponse(const QByteArray &frame, VtkResult &out)buildSettleRequest(...)/parseSettleResponse(...)
- 构造/解析 预扣款请求/响应、结算请求/响应、系统信息 等应用消息:
-
会话与状态机层
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对接。
- 维护每把枪的
-
串口接入层
- 若已有串口任务(如
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. 后续实施步骤建议
- 确认业务映射:与 POS 提供方确认使用的 Message name(CDP/CRD/INF 等)、结果码格式以及参数集合。
- 实现基础协议层:
vtk_frame+vtk_tlv,并通过单元测试校验:- CRC 计算正确。
- TLV 编解码对齐文档。
- 实现预扣款 / 结算消息构造与解析:
vtk_pos_protocol。 - 实现 POS 会话状态机:
pos_vtk_service,并与现有充电流程打通(只改入口/出口逻辑,尽量不动核心 BMS/MDU 代码)。 - 集成串口任务:选定 UART 口,完成收发调试(先用日志工具验证 VTK 帧格式)。
- 与实际 POS 联调:根据联调结果调整错误码处理、超时重试策略等。
7. 示例报文
以下示例仅展示 TLV 内容和串口帧结构,CRC16 按实现自动计算,示例中不逐字列出。
7.1 预扣款请求(CDP)
-
业务参数:
- Message name:
"CDP"(Tag 0x01) - Operation number:
"12345"(Tag 0x03,十进制 ASCII) - Amount:
"5000"(Tag 0x04,表示 50.00 元)
- Message name:
-
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 LLLength(2 字节,大端,= ProtocolDisc + TLV 长度)96 FBProtocol discriminator(VMC→POS)01 03 43 44 50 03 05 31 32 33 34 35 04 04 35 30 30 30TLV 数据CC CCCRC16-CCITT(由代码计算)
7.2 结算请求(CRD)
- 参数示意:
- Message name:
"CRD"(0x01) - Operation number:与预扣款相同
"12345"(0x03) - Amount:最终金额
"4200"(0x04,表示 42.00 元)
- Message name:
TLV 结构与上例相同,仅值不同。
7.3 响应报文(POS→CCU)
- 假设 POS 对预扣款返回:
- Message name:
"CDP" - Operation number:
"12345" - Amount:
"5000" - Result:Tag 0x0D,Length=1,Value=0x00(Approved)
- Message name:
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 错误等)的处理策略。