记录日期:2026-08-26
项目仓库:/Users/liang/AndroidStudioProjects/CusumptionMachine
实施分支:simplify_menu_pay
伟邦和优卡特刷卡器原实现由每个页面或弹框直接打开物理串口并创建阻塞读取线程。业务关闭时仅调用 interrupt()、关闭串口和清空回调,设备驱动不能保证阻塞中的 InputStream.read() 立即退出。下一次业务重新打开串口后,旧线程可能继续与新线程竞争同一张卡的数据,导致刷卡器有反应但当前页面没有收到卡号。
原实现还假定串口一次 read() 必定返回一张卡的完整数据帧,未处理半包、粘包和帧头前噪声。
SingleReaderCardPortManager,统一管理单个物理刷卡串口、唯一阻塞读取线程、异常重连和最新会话路由。YoukateCardPortManager,作为优卡特 /dev/ttyS5 的进程级唯一所有者,并保留 FM17520 命令字和 CRC16-CCITT-FALSE 校验。WabonCardPortManager,作为伟邦 /dev/ttyS9 的进程级唯一所有者,并保留原有卡号格式转换规则。YoukateCardSerialPortSwiper 和 WabonCardSerialPortSwiper 改为轻量业务会话,支持 resume()、pause() 和永久 close();关闭页面只注销会话,不再关闭物理串口。LatestSessionDispatcher,刷卡结果只投递给最后注册的有效页面;旧会话关闭和主线程排队的迟到结果不会影响当前会话。CardSerialFrameDecoder,按 FE 02 + 长度字节 协议缓存并拆分数据,支持半包、一次读取多帧和帧前噪声;物理串口重连时清除旧连接残留半帧。app/src/main/java/com/cpt/cusumption/devices/serial/CardSerialFrameDecoder.javaapp/src/main/java/com/cpt/cusumption/devices/serial/SingleReaderCardPortManager.javaapp/src/main/java/com/cpt/cusumption/devices/youkate/YoukateCardPortManager.javaapp/src/main/java/com/cpt/cusumption/devices/youkate/YoukateCardSerialPortSwiper.javaapp/src/main/java/com/cpt/cusumption/devices/wabon/WabonCardPortManager.javaapp/src/main/java/com/cpt/cusumption/devices/wabon/WabonCardSerialPortSwiper.javaapp/src/test/java/com/cpt/cusumption/devices/serial/CardSerialFrameDecoderTest.javaCardSerialFrameDecoderTest,确认生产解码器缺失时测试编译失败。CardSerialFrameDecoderTest 和 LatestSessionDispatcherTest:共 8 个测试全部通过。CardSerialFrameDecoderTest 共 4 个测试,覆盖半包缓存、单次读取多帧、帧头前噪声和协议长度字节解析。LatestSessionDispatcherTest 共 4 个测试,覆盖最新会话独占、旧会话关闭不影响新会话以及迟到结果丢弃。JAVA_HOME=/Users/liang/Library/Java/JavaVirtualMachines/corretto-1.8.0_482/Contents/Home bash gradlew :app:testDebugUnitTest :app:assembleDebug:BUILD SUCCESSFUL。app/build/outputs/apk/debug/app-debug.apk。b25b3e8c6f7320732a3001d22ed21109eea420dcb07e2324a58c6cada610121a。