feat(*): 添加扫码枪启动探活、全局退出助手及 README

- 添加扫码枪串口启动探活,检测端口占用并更新 UI 状态
- 新增 ShutdownHelper 安全停止 Host 扩展方法
- 新增 README.md 项目说明文档
- 更新 WorkflowHostedService 启动探活逻辑
- 补充 ShutdownHelper 与 WorkflowHostedService 单元测试
- 优化 DashboardPage 与 SystemSettingsPage 界面布局
- 调整 ModbusTcpPlcService 监控镜像读取逻辑
This commit is contained in:
2026-04-19 14:29:07 +08:00
parent 8f74e07c66
commit d70b94e904
26 changed files with 1564 additions and 827 deletions

174
README.md Normal file
View File

@@ -0,0 +1,174 @@
# AxiOmron.PcbCheck
基于 `.NET 8 + WPF + MVVM Toolkit + Generic Host/DI + NLog` 的 PCB 目检上位机示例工程,包含 PLC 通信、扫码枪触发、SFTP 文件校验、安灯报警和运行态监控。
## 项目结构
```text
Axi_Omron/
src/
AxiOmron.PcbCheck/
tests/
AxiOmron.PcbCheck.Tests/
docs/
AxiOmron.PcbCheck.slnx
```
主程序位于 [src/AxiOmron.PcbCheck](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck),测试位于 [tests/AxiOmron.PcbCheck.Tests](d:/Dev/Codes/MFD_Solution/Axi_Omron/tests/AxiOmron.PcbCheck.Tests)。
## 技术栈
- `.NET 8` / `WPF`
- `CommunityToolkit.Mvvm`
- `Microsoft.Extensions.Hosting`
- `NLog`
- `IoTClient` Modbus TCP
- `SSH.NET`
- `HandyControl`
## 配置说明
主配置文件位于 [src/AxiOmron.PcbCheck/appConfig.json](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/appConfig.json)。
当前 PLC 相关默认配置示例:
- `Plc.Host`: `127.0.0.1`
- `Plc.Port`: `502`
- `Plc.UnitId`: `1`
- `Plc.PollIntervalMs`: `200`
- `Plc.ReleasePulseMs`: `500`
- `Plc.ReleaseAckTimeoutMs`: `2000`
点位映射示例:
- 输入点位
- `PcbArrived = 0`
- `PlcReset = 1`
- `PlcAckRelease = 2`
- 输出点位
- `PcBusy = 51`
- `ReleasePermit = 52`
- 寄存器
- `ResultCode = 0`
系统设置页可修改 PLC 参数,界面入口在 [SystemSettingsPage.xaml](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Views/Pages/SystemSettingsPage.xaml#L58)。
注意:配置保存后会写入运行目录下的 `appConfig.json`,当前界面提示为“重启应用后完全生效”。
## 构建与运行
```powershell
dotnet restore .\src\AxiOmron.PcbCheck\AxiOmron.PcbCheck.csproj
dotnet build .\src\AxiOmron.PcbCheck\AxiOmron.PcbCheck.csproj -c Debug
dotnet run --project .\src\AxiOmron.PcbCheck\AxiOmron.PcbCheck.csproj -c Debug
dotnet test .\tests\AxiOmron.PcbCheck.Tests\AxiOmron.PcbCheck.Tests.csproj
```
## PLC 后台轮询调用链
### 总览
```text
App 启动
-> BuildHost 注册 WorkflowHostedService 为 HostedService
-> Host.StartAsync()
-> WorkflowHostedService.ExecuteAsync()
ExecuteAsync 主循环
-> ProbePlcOnStartupAsync() 启动先探活
-> while (...)
-> _plcService.ReadSignalsAsync() 读取 PLC 输入
-> HandleSignalSnapshot() 刷 PLC 连接状态
-> RefreshPlcMonitorSnapshotAsync() 刷监控区
-> if PlcReset = true
-> ResetAsync()
else if ShouldStartWorkflow() 命中上升沿
-> StartWorkflowInBackground()
-> RunWorkflowOnceAsync()
RunWorkflowOnceAsync 单板流程
-> InitializeBoardState()
-> ApplyProcessStateAsync(Triggered, PcBusy=true)
-> ExecuteScanFlowAsync()
-> _scannerService.TriggerScanAsync()
-> ExecuteSftpFlowAsync(barcode)
-> _sftpLookupService.CheckFileAsync()
-> ReleaseAndCompleteAsync()
-> ApplyProcessStateAsync(Releasing, ReleasePermit=true)
-> 循环 _plcService.ReadSignalsAsync() 等 PlcAckRelease
-> Delay(ReleasePulseMs)
-> ApplyProcessStateAsync(Completed, ReleasePermit=false, PcBusy=false)
-> _stateStore.AddRecord(...)
状态/UI 更新支线
-> PublishRuntimeState() / UpdateSnapshot()
-> AppStateStore.SnapshotChanged
-> MainWindowViewModel.OnSnapshotChanged()
-> DashboardPage / SystemSettingsPage 绑定刷新
```
### 关键代码入口
- 后台服务注册:
[App.xaml.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/App.xaml.cs#L125)
[App.xaml.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/App.xaml.cs#L127)
- 轮询主循环:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L70)
- PLC 输入读取:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L81)
- 轮询周期:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L110)
- 启动流程判定:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L366)
- 启动单板流程:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L388)
- 单板总流程:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L496)
- 扫码流程:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L542)
- SFTP 校验流程:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L630)
- 放行及等待 PLC 应答:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L727)
- 流程状态写回 PLC
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L942)
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L954)
### PLC 底层读写落点
- `IPlcService` 接口:
[CoreInterfaces.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Interfaces/CoreInterfaces.cs#L97)
- `ReadSignalsAsync` 实现:
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L37)
- 实际读取的输入位:
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L47)
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L48)
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L49)
- 监控区镜像读取:
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L69)
- 输出状态写入:
[ModbusTcpPlcService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/ModbusTcpPlcService.cs#L113)
### UI 刷新链
- 后台更新运行态快照:
[AppStateStore.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/AppStateStore.cs#L45)
- 主界面监听快照变化:
[MainWindowViewModel.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/ViewModels/MainWindowViewModel.cs#L532)
- 设置页监听快照变化:
[SystemSettingViewModel.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/ViewModels/SystemSettingViewModel.cs#L150)
### 常用排查入口
- `PlcReset` 触发软件复位:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L85)
- 轮询异常进入故障锁存:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L103)
- 流程异常进入故障锁存:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L432)
- 故障状态写回:
[WorkflowHostedService.cs](d:/Dev/Codes/MFD_Solution/Axi_Omron/src/AxiOmron.PcbCheck/Services/Implementations/WorkflowHostedService.cs#L823)
## 说明
本 README 主要补充程序整体说明与 PLC 后台轮询调用链便于排查“PLC 轮询在哪里启动、如何触发单板流程、状态如何回写和刷新 UI”这类问题。