/Users/liang/.codex/worktrees/d33c/ZhctTrayBindingMachine目标 F700-HW 设备在执行 PSAM 通道 SELECT 3F00 时使用 32 字节 HID 报告。首段响应后需要发送 0x50 续包请求,但设备的后续响应把 offset 再次返回为 0,原协议实现要求绝对 offset 严格递增,因此在扣款 APDU 发出前抛出 PROTOCOL_ERROR。
现场前后读卡数据一致:主钱包余额和操作计数均未变化,日志也明确记录 cardDebitSent=false。原业务层仅以“是否进入消费调用”判断结果,因而把确定的扣款前失败误归类为 DEBIT_UNKNOWN。
第二次真机复测确认第一版兼容已经命中:首段 25 字节后接受了 offset=0 的 2 字节续包,业务错误也正确变为 PRE_DEBIT_FAILURE。但首段已经以 9000 结束,理论 CRC 尾字节应为 A4 05,设备的 PSAM 0x50 续包实际返回通用应答 01 01,拼接后触发 CRC_ERROR。因此该 32 字节固件的 PSAM 长响应不能直接沿用普通卡通道续包语义。
第三次真机复测否定了“不返回 FCI”参数方案:32 字节 PSAM 对 SELECT FILE 的 P2=0x0C 明确返回 6A86,日志仍为 cardDebitSent=false。最终方案恢复现场设备支持的 P2=0x00,不再修改 APDU 命令参数。
PRE_DEBIT_FAILURE 错误类型。协议层仅在扣款命令尚未发出时,将 PSAM、卡片准备和通信失败包装为该类型;扣款命令一旦进入发送阶段,仍保持 TRANSACTION_OUTCOME_UNKNOWN,防止重复扣款。PRE_DEBIT_FAILURE 判定为确定失败,进入现有 TRANSACTION_FAILED 页面,提示“请取走卡片和餐盘后重新操作”。若已经完成任一钱包扣款,仍归类为结果未知。0x6F、命中 PSAM 通道、已进入续包,且剩余长度严格递减、数据不重复时,才接受续包 offset=0。HID_PSAM_RELATIVE_OFFSET_ACCEPTED 诊断事件。6A86 拒绝的 P2=0x0C 方案,32/64 字节 PSAM 及普通卡通道的 SELECT FILE 均恢复 P2=0x00。SELECT FILE P1/P2=0x00、首包恰好 25 字节且末尾为 9000、声明仅余 2 字节、续包为 offset=0/remaining=0/0101。由于业务不使用 SELECT 返回的 FCI,兼容层丢弃 FCI,只生成供公共 APDU 校验器验证的最小 9000 + CRC 状态响应,并记录 HID_PSAM_SELECT_STATUS_RECOVERED。非 SELECT 指令仍必须使用设备返回的完整 CRC。64 字节 HID 不进入状态归一化分支,仍使用原有绝对 offset 和完整 CRC 严格校验,SELECT P2 保持 0x00。已增加专门回归:标准 64 字节 PSAM 多段响应能够正常拼包;64 字节 PSAM 若续包错误返回 offset=0 仍会被拒绝;32 字节普通卡通道同样保持 P2=0x00 和严格 offset 校验;非 SELECT PSAM 指令即使出现相同 0101 续包也不会被归一化。
app/src/main/java/com/zhct/traybinding/onecard/reader/NewcapecProtocol.javaapp/src/main/java/com/zhct/traybinding/onecard/reader/HidFrameCodec.javaapp/src/main/java/com/zhct/traybinding/onecard/reader/ReaderError.javaapp/src/main/java/com/zhct/traybinding/consumption/voice/ConsumptionVoiceOutcomeClassifier.javaapp/src/test/java/com/zhct/traybinding/onecard/reader/ConsumptionVoiceOutcomeClassifierTest.javaapp/src/test/java/com/zhct/traybinding/onecard/reader/NewcapecProtocolPsamContinuationTest.javaapp/src/test/java/com/zhct/traybinding/onecard/reader/NewcapecProtocolSelectFileTest.java| 验证项 | 结果 |
|---|---|
| 定向测试 | 业务分类、PSAM 续包和 SELECT 隔离共 15 项测试通过 |
| 全量 JVM 单元测试 | 172 tests,0 failures,0 errors,0 skipped |
| Debug 构建 | :app:assembleDebug 成功 |
| APK | app/build/outputs/apk/debug/app-debug.apk,66,954,953 bytes |
| APK SHA-256 | bebc264a56c6118dc3b18d88c36fbcc4e1c28d2265c1e4f40e9090f844fa0aab |
| F700-HW 安装 | 2026-08-29 18:28:03;设备与本地 APK 哈希一致 |
构建仅有项目既有的 Java 8 编译器读取 Android build-tools 30 类版本提示及 deprecated 提示,没有新增编译错误。
HID_PSAM_SELECT_STATUS_RECOVERED 后继续完成后续 PSAM 指令、用户卡扣款及 PSAM 确认;若失败,仍以 cardDebitSent 里程碑决定是否允许重试。