9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
251 lines
11 KiB
Markdown
251 lines
11 KiB
Markdown
# 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 错误等)的处理策略。
|
||
|