# 欧姆龙 PLC PCB 条码文件判定系统项目计划 ## 1. 项目目标 开发一个 Windows WinForms 上位机程序,实现: 1. 通过 FINS/TCP 与欧姆龙 PLC 通信。 2. 等待 PLC 发出 PCB 到位信号。 3. 同时触发两把 TCP Server 扫描枪。 4. 两把扫描枪分别扫描 PCB 正面和反面,任意一把返回有效条码即可。 5. 根据条码检查本地目录中的 `<条码>.txt` 文件。 6. 将检查结果返回 PLC。 7. 通过 WinForms 界面显示 PLC、扫描枪、文件检查和当前任务状态。 8. 对通信超时、断线、重复触发和异常情况进行处理并记录日志。 ## 2. 当前需求基线 ### PLC 通信 | 项目 | 配置 | |---|---| | 协议 | Omron FINS/TCP | | PLC IP | `192.168.2.100` | | 端口 | `9600` | | UnitAddress | `0` | | SourceNodeAddress | `0` | | EndianFormat | `ABCD` | | PLC 区域 | D 区 | ### PLC 点位 | 名称 | 地址 | 类型 | 初步用途 | |---|---:|---|---| | PcbArrived | D101 | Bool | PCB 到位信号 | | PlcReset | D102 | Bool | PLC 复位本轮流程 | | PlcAckRelease | D103 | Bool | PLC 确认放行结果 | | PcBusy | D51 | Bool | 上位机忙碌状态 | | ReleasePermit | D52 | Bool | 是否允许放行 | | ResultCode | D401 | Word | 扫描和文件检查结果 | 初版按 D 区字值 `0/1` 处理 Bool: ```text 0 = False 1 = True ``` 如果 PLC 实际使用 `D101.00` 这类 bit 位,需要在开发前调整 FINS 读写实现。 ### 扫描枪 | 项目 | 扫描枪 1 | 扫描枪 2 | |---|---|---| | IP | `192.168.2.13` | `192.168.2.14` | | 端口 | `2001` | `2001` | | 设备角色 | PCB 正面 | PCB 反面 | | 通信模式 | TCP Server | TCP Server | | 上位机角色 | TCP Client | TCP Client | | 触发指令 | `T` | `T` | | 返回结束符 | 无 | 无 | | 超时时间 | 2000 ms | 2000 ms | ### 文件检查 ```text 根目录:D:\test 文件规则:D:\test\<条码>.txt ``` 例如条码为: ```text PCB202608040001 ``` 检查文件: ```text D:\test\PCB202608040001.txt ``` ## 3. 业务流程 ```mermaid flowchart TD A["等待 D101 到位信号"] --> B{"D101 是否为 True"} B -- 否 --> A B -- 是 --> C["生成任务号并锁存本轮触发"] C --> D["写入 D51 = 1,进入扫描中"] D --> E["并行连接两把扫描枪并发送 T"] E --> F{"是否收到有效条码"} F -- 是 --> G["记录第一条有效条码"] F -- 否且未超时 --> E F -- 超时 --> H["写入扫描超时结果"] G --> I["检查 D:\\test\\条码.txt"] I --> J{"文件是否存在"} J -- 是 --> K["D401 写入通过结果,D52 = 1"] J -- 否 --> L["D401 写入不通过结果,D52 = 0"] K --> M["等待 PLC 确认或复位"] L --> M H --> M M --> N{"D102 PlcReset 是否为 True"} N -- 否 --> M N -- 是 --> O["清除 D51、D52 和本轮结果"] O --> P["等待 D101 恢复 False"] P --> A ``` ## 4. 详细握手策略 ### 等待到位 - 程序持续读取 `D101`。 - `D101=True` 时只创建一次任务。 - 在本轮任务结束前,即使 `D101` 一直保持 True,也不能重复触发扫描。 - 程序重启时,如果发现 `D101` 已经为 True,默认不立即重复处理,等待 PLC 先复位到 False。 ### 扫描阶段 - 设置 `D51=1`。 - 两把扫描枪并行发送 `T`。 - 任意一把返回非空条码后结束等待。 - 另一把扫描枪的迟到结果记录为本轮无效数据,不参与下一轮。 - 两把扫描枪都无返回时,2000 ms 后判定扫描超时。 ### 文件判断阶段 - 对条码进行去除空白、长度检查和非法文件名字符检查。 - 禁止条码产生 `..`、路径分隔符或越过 `D:\test` 的路径。 - 使用精确路径检查 `<根目录>\<条码>.txt`。 - 文件存在即判定为允许放行。 - 文件不存在即判定为不允许放行。 ### 结果保持阶段 - `D401` 结果写入后保持。 - 文件存在时 `D52=1`。 - 文件不存在或扫描失败时 `D52=0`。 - `D51` 在本轮任务期间保持为 1。 - 收到 `D102=True` 后清除本轮输出。 - `D103` 用于记录 PLC 是否确认放行结果;其是否作为必须等待的条件,需要 PLC 程序最终确认。 ## 5. 建议结果编码 结果编码必须最终与 PLC 程序确认,建议如下: | ResultCode | 含义 | |---:|---| | 0 | 空闲 | | 1 | 扫描中 | | 2 | 文件存在,允许放行 | | 3 | 文件不存在,不允许放行 | | 4 | 两把扫描枪均超时 | | 5 | 扫描枪通信异常 | | 6 | 条码为空或格式错误 | | 7 | PLC 通信异常 | | 8 | PLC 复位 | | 9 | 系统异常 | 建议 `ReleasePermit` 只表达一个含义: ```text D52 = 1:允许放行 D52 = 0:不允许放行 ``` 具体 `ResultCode` 用于区分“不存在文件”“扫描超时”“通信异常”等原因。 ## 6. 系统架构 建议采用分层结构: ```text src/ PcbCheck.Desktop/ PcbCheck.Application/ PcbCheck.Domain/ PcbCheck.Devices/ PcbCheck.Infrastructure/ tests/ PcbCheck.Tests/ PcbCheck.IntegrationTests/ docs/ architecture.md plc-protocol.md scanner-protocol.md deployment.md acceptance-checklist.md ``` ### PcbCheck.Desktop 负责: - WinForms 窗体 - 当前状态显示 - 设备连接状态显示 - 当前条码显示 - 文件检查结果显示 - 任务耗时和最近结果显示 - 错误提示 - 手动连接、断开和复位操作 界面层不能直接拼装 FINS 报文或操作 TCP 流。 ### PcbCheck.Application 负责: - PCB 检测流程编排 - PLC 到位触发处理 - 双扫描枪并行扫描 - 条码选择策略 - 文件检查调用 - PLC 结果写回 - 超时和异常状态处理 - 任务去重和复位控制 核心流程建议命名为: ```text PcbInspectionWorkflow ``` ### PcbCheck.Domain 负责: - 任务状态 - 设备状态 - 扫描结果 - 文件检查结果 - PLC 结果编码 - 业务异常类型 该层不引用 WinForms、TCP、FINS、文件系统或第三方 SDK。 ### PcbCheck.Devices 负责: - FINS/TCP PLC 客户端 - TCP 扫描枪客户端 - Fake PLC - Fake 扫描枪 - 设备连接状态和重连机制 建议接口: ```text IFinsPlcClient ITcpScannerClient IIndustrialDevice ``` ### PcbCheck.Infrastructure 负责: - 本地文件检查 - 配置加载 - 日志 - 任务记录 - 文件路径安全校验 - 系统时间和基础设施封装 ## 7. 扫描枪无结束符处理方案 扫描枪返回不带结束符,不能简单地认为一次 TCP `Receive` 就是一条完整条码,因为 TCP 可能出现: - 一条报文拆成多次接收; - 多条报文合并接收; - 返回后保持连接不断开。 因此开发前必须确认扫描枪的实际行为: ### 优先方案 扫描枪返回条码后主动关闭本次 TCP 连接。程序读取到连接关闭即认为一条数据完成。 ### 备用方案 如果扫描枪保持长连接,则使用: - 最大报文长度限制; - 接收缓冲区; - 字节间空闲超时; - 2000 ms 总超时; - 收到数据后短暂等待后判定报文结束。 该参数需要配置化,不能写死在界面代码中。 ## 8. WinForms 界面计划 ### 设备状态区 显示: - PLC:已连接、连接中、断开、故障 - 扫描枪 1:已连接、断开、超时 - 扫描枪 2:已连接、断开、超时 - 本地目录:存在、不可访问 ### 当前任务区 显示: - 当前流程状态 - 当前任务号 - PCB 到位状态 - 当前条码 - 条码来源:正面/反面 - 文件完整路径 - 文件是否存在 - ResultCode - ReleasePermit - 本轮耗时 ### 统计区 显示: - 总扫描数 - 通过数量 - 不通过数量 - 扫描超时数量 - 扫描枪通信异常数量 - PLC 通信异常数量 - 最近一次任务时间 ### 操作区 建议提供: - 连接设备 - 断开设备 - 清除报警 - 手动复位 - 打开日志目录 - 打开文件根目录 - 进入配置页面 手动写 PLC 点位的功能应限制权限,避免普通操作员误操作生产信号。 ## 9. 配置文件计划 所有通信参数和业务参数放入配置文件,不硬编码在程序中。 ```json { "Plc": { "Host": "192.168.2.100", "Port": 9600, "UnitAddress": 0, "SourceNodeAddress": 0, "EndianFormat": "ABCD", "MemoryArea": "D", "Inputs": { "PcbArrived": 101, "PlcReset": 102, "PlcAckRelease": 103 }, "Outputs": { "PcBusy": 51, "ReleasePermit": 52 }, "Registers": { "ResultCode": 401 } }, "Scanners": [ { "Name": "FrontScanner", "Host": "192.168.2.13", "Port": 2001, "Trigger": "T", "TimeoutMs": 2000, "Encoding": "ASCII" }, { "Name": "BackScanner", "Host": "192.168.2.14", "Port": 2001, "Trigger": "T", "TimeoutMs": 2000, "Encoding": "ASCII" } ], "FileCheck": { "RootPath": "D:\\test", "FileNamePattern": "{Barcode}.txt", "IgnoreCase": false }, "Workflow": { "WaitPlcReset": true, "RequireReleaseAck": false, "ClearResultAfterReset": true } } ``` `RequireReleaseAck` 在 PLC 握手确认后再决定是否启用,默认关闭。 ## 10. 日志要求 每一轮 PCB 任务生成唯一任务号,日志至少记录: - 任务号 - 开始时间和结束时间 - PLC 地址和读写结果 - 到位信号变化 - 两把扫描枪触发内容 - 两把扫描枪原始返回内容 - 选中的条码和来源设备 - 文件检查路径和结果 - ResultCode - ReleasePermit - PlcAckRelease - PlcReset - 每个步骤耗时 - 异常消息和通信错误 日志按日期滚动保存,例如: ```text logs\ 2026-08-04\ application.log communication.log task.log ``` ## 11. 异常和恢复策略 ### PLC 断线 - 状态显示为 PLC 断开。 - 停止触发扫描。 - 进入自动重连。 - 重连成功后重新读取当前状态。 - 不重复执行已经完成的任务。 ### 扫描枪断线 - 单把扫描枪断线时,仍允许另一把扫描枪继续工作。 - 两把均断线时,任务判定为通信异常。 - 支持自动重连。 - 记录具体设备名称和异常原因。 ### PLC 到位信号长时间保持 - 通过任务状态和任务锁避免重复触发。 - 本轮流程未复位前不再次发送 `T`。 - 复位后要求 `D101` 先恢复 False,再允许下一轮触发。 ### 文件目录不可访问 - 不判定为普通“文件不存在”。 - 返回独立的系统异常码。 - 界面显示目录访问错误。 - 日志记录完整路径和系统异常。 ### 程序重启 - 启动时先连接 PLC 和扫描枪。 - 如果 `D101=True`,默认等待 PLC 复位,不自动重扫。 - 如果存在上一次未完成任务,记录为中断任务,不自动伪造结果。 ## 12. 开发阶段 ### 阶段一:需求和协议确认 确认: - D 区 Bool 是字值 0/1 还是 bit; - `D103 PlcAckRelease` 的真实含义; - `D102 PlcReset` 的触发和清除时序; - `D401` 结果编码; - 扫描枪返回后是否断开 TCP; - 扫描枪编码格式; - 条码最大长度和合法字符; - 两把枪同时返回时的处理规则。 交付物: - PLC 点位表 - PLC 握手时序图 - 扫描枪报文说明 - 结果编码表 - 文件规则说明 ### 阶段二:项目骨架 实现: - WinForms 工程 - 分层项目结构 - 配置加载 - 日志系统 - 依赖注入 - 领域状态和结果模型 - 基础状态界面 ### 阶段三:FINS/TCP 通信 实现: - FINS/TCP 连接 - D 区 Bool 读取 - D 区 Bool 写入 - D401 结果写入 - 连接超时 - 读写超时 - 断线重连 - 原始通信日志 - Fake PLC 测试实现 ### 阶段四:双扫描枪通信 实现: - 两个 TCP Client - 自动连接和重连 - 同时发送 `T` - 无结束符报文接收 - 2000 ms 超时 - 首个有效结果选择 - 空结果和异常处理 - Fake 扫描枪测试实现 ### 阶段五:文件检查和流程编排 实现: - 条码清洗 - 文件名安全校验 - `D:\test\<条码>.txt` 精确检查 - PLC 信号与扫描枪流程串联 - 结果保持 - PLC 复位 - 任务去重 - 异常恢复 ### 阶段六:WinForms 状态界面 实现: - PLC 状态 - 两把扫描枪状态 - 文件目录状态 - 当前任务显示 - 结果和统计显示 - 日志查看入口 - 报警显示 - 手动复位和连接控制 ### 阶段七:测试和交付 实现: - 单元测试 - Fake 设备流程测试 - 通信异常测试 - 现场联调 - 发布包 - 配置模板 - 操作说明书 - 维护说明书 - 验收记录 ## 13. 测试计划 ### 单元测试 覆盖: - ResultCode 映射 - 文件路径拼接 - 条码非法字符校验 - 文件存在和不存在 - D101 长保持防重复 - PLC 复位流程 - 扫描超时 - 首个有效条码选择 - 两把扫描枪同时返回 - 连接断开和重连 ### 协议测试 覆盖: - FINS/TCP 建连 - D 区读取 - D 区写入 - D401 数值写入 - ABCD 字节序 - 错误响应 - 超时响应 - PLC 断电重连 ### 模拟流程测试 覆盖: 1. 正常扫描,文件存在。 2. 正常扫描,文件不存在。 3. 正面扫描成功,反面无结果。 4. 反面扫描成功,正面无结果。 5. 两把均无结果。 6. 一把断线,另一把成功。 7. 两把均断线。 8. D101 长时间保持 True。 9. 扫描过程中收到 D102。 10. PLC 结果确认。 11. 程序重启时 D101 为 True。 12. 文件目录不存在或无权限。 ### 现场测试 硬件测试必须在现场或真实设备环境中执行,模拟测试不能替代现场验收。 现场至少验证: - PLC 实际 IP 和 FINS 节点; - D 区真实点位; - 真实 Bool 表达方式; - 真实扫描枪触发报文; - 真实返回报文边界; - 两把扫描枪同时触发; - PLC 复位和放行确认; - 连续生产 30~60 个 PCB 的稳定性。 ## 14. 交付标准 满足以下条件才算完成: - Release 构建成功。 - 单元测试全部通过。 - Fake PLC 和 Fake 扫描枪流程测试通过。 - 所有设备操作均有超时和取消机制。 - UI 线程无阻塞通信。 - PLC 断线能够显示并重连。 - 扫描枪断线能够显示并恢复。 - D101 长保持不会重复扫描。 - 文件检查路径不可越界。 - 结果能够正确保持和复位。 - 日志能够定位每一轮任务。 - 配置文件不包含硬编码生产密码。 - 完成真实 PLC、扫描枪和本地目录现场验收。 ## 15. 预计开发周期 在 PLC 和扫描枪可及时提供测试的前提下: | 阶段 | 预计时间 | |---|---:| | 需求和协议确认 | 0.5~1 天 | | 项目骨架和配置 | 0.5~1 天 | | FINS/TCP 通信 | 1~2 天 | | 双扫描枪通信 | 1~2 天 | | 流程和文件判断 | 1 天 | | WinForms 界面 | 1~2 天 | | 测试和修复 | 1~2 天 | | 现场联调 | 1~2 天 | 预计开发周期为 6~10 个工作日,现场联调时间取决于 PLC 点位、扫描枪协议和设备可用情况。 ## 16. 当前开发门槛 正式编写现场通信代码前,必须最终确认: 1. D101、D102、D103、D51、D52 是否使用 D 字的 0/1。 2. 扫描枪返回后是否主动断开 TCP。 3. `D401` 的正式结果编码。 4. `D103 PlcAckRelease` 的正式握手含义。 5. 文件不存在时是否直接结束,还是继续等待另一把扫描枪。 6. PLC 程序是否要求 `D51`、`D52` 和 `D401` 保持到 `D102` 复位。 7. 真实条码编码和最大长度。 本计划采用设备接口隔离、后台异步通信、超时与重连、Fake 设备测试和真实设备验收分离的方式,便于先完成可测试的软件闭环,再进行现场通信确认。