# 固态功率控制器动态参数测试系统 — 开发文档 > 版本 v1.3 | 更新:**2026-07-08 14:58:50 +08:00** | 技术栈:**C# + WPF + .NET 8** | 口径:**以当前仓库代码为准** > > 本文档描述当前仓库的真实结构、配置方式、核心流程和维护约定。 > 若文档与代码冲突,以代码实现为准,并应同步回写本文档。 --- ## 0. 开发约束 对本项目进行新增、修改、排障时,默认遵守以下原则: 1. **分层隔离优先**:UI 只依赖 ViewModel / Service / Logic,不直接依赖具体设备驱动。 2. **接口先行**:SSPC、电源、负载、DAQ、安全 DIO 一律经 `SSPCTester.Devices.Interfaces` 暴露,真假驱动由配置决定。 3. **按设备粒度切换 Mock/Real**:当前不再是“一个全局 `MockMode` 管全部设备”,而是每类设备都有自己的 `UseMock`。 4. **配置分层加载**:程序先读内置默认值,再读 `appsettings.json`,最后读 `%LOCALAPPDATA%\SSPCTester\settings.json`。 5. **测试态独占**:进入测试后只展示当前项目,禁止切换其他项目,设备连接由测试态独占。 6. **文档随代码更新**:涉及接口、项目结构、运行方式、持久化格式变化时,要同步更新本文档。 --- ## 1. 项目背景 ### 1.1 被测对象 固态功率控制器(SSPC)用于智能配电场景。本项目按 **24 路** 输出通道建模,通过软件控制每路导通/关断,并测量: - 基础通断状态 - 开启/关断曲线与时间参数 - 功率损耗与效率 - 保护功能测试结果 ### 1.2 当前测试台硬件 | 部件 | 型号 | 作用 | 当前代码状态 | |---|---|---|---| | 工控机 | Windows x64 | 运行 WPF 主程序 | 已支持 | | 被测件 SSPC | 24 路 | 控制 24 路导通/关断 | 已有 `SspcModbus` | | 程控电源 | UDP5080-100 | 输入端电压/电流读取、输出开关控制 | 已有真实驱动 | | 可编程负载 | IT8733P / IT8702P | 输出端电压/电流/功率读取、输入开关控制 | 已有真实驱动 | | 高速采集卡 | PCIe8586 | 曲线波形采集 | 已有 `Pcie8586Daq` | | 安全 DIO 卡 | PCI2312 | 急停输入读取、报警灯输出控制 | 已有 `Pci2312SafetyDio` | | 示波器 | Tektronix MDO3024 | 线下校准基准 | 不纳入软件控制 | ### 1.3 当前实现事实 - SSPC 24 路通过 **3 个 Modbus 模块 × 每模块 8 路** 映射。 - 采集卡实现已经统一为 **PCIe8586**,不再使用旧文档中的 `PCIe9318` 命名。 - 真假设备切换已经演进为 **每类设备独立 `UseMock`**。 - 主程序启动后会按配置自动连接 SSPC、电源、负载、DAQ、PCI2312。 - 新增设备安全监控链路:后台轮询 PCI2312 急停输入,触发后接通报警输出,并向 SSPC、电源、负载发送安全关断指令。 - 根目录脚本 `run.ps1` / `publish.ps1` 已是当前标准运行入口。 --- ## 2. 当前功能范围 主流程如下: ```text 新建/打开项目 -> 填写项目信息 / 勾选测试项 -> 进入测试态 -> 执行基础测试 / 曲线测试 / 功率损耗 / 保护功能 -> 生成 PDF / Word 报告 ``` ### 2.1 四大模块 | 模块 | 当前实现 | 状态 | |---|---|---| | 基础测试 | 24 路逐路开/关、读电压电流、判定稳态关断 | 已实现 | | 开启与关断曲线 | 支持开通/关断波形采集、指标计算、独立曲线视窗、波形落盘 | 已实现 | | 功率损耗 | 使用 UDP5080 读输入端,IT87xx 读输出端功率/电压/电流 | 已实现 | | 保护功能 | 固定保护项、自动获取/人工观测数据记录、人工判别结果 | 已实现 | ### 2.2 设备安全与急停报警 当前代码新增了独立于“保护功能测试页”的**运行时设备安全链路**: - 硬件连接:`PCI2312` 通过厂商 `PCI2312_64.dll` 以 P/Invoke 方式接入,使用 DI 通道读取急停状态,使用 DO 通道控制报警灯。 - 后台监控:`SafetyMonitorService.Start()` 在主窗口初始化后启动,按 `Devices:Pci2312:PollIntervalMs` 周期轮询急停输入。 - 硬件急停:当配置的 DI 通道达到有效电平时,程序写入报警 DO,并依次执行 SSPC 全通道关断、电源输出关闭、负载输入关闭。 - 软件急停:主窗口顶部“报警急停”按钮调用 `TriggerSoftwareEmergencyAsync()`,走同一套报警灯和设备关断链路。 - 状态重置:报警灯点亮后按钮变为“状态重置”。若硬件急停 DI 仍有效,重置会被拒绝;DI 复位后才关闭报警输出并恢复监控状态。 控制链路如下: ```text PCI2312 DI 急停输入 / UI 软件急停按钮 -> SafetyMonitorService -> PCI2312 DO 报警灯输出 -> ISspc.TurnOffAsync(1..24) -> IPowerSupply.OutputAsync(false) // UDP5080 :OUTput OFF -> ILoad.InputAsync(false) // IT8702P INP OFF -> UI 状态、日志和报警灯图标同步刷新 ``` 注意:这是软件侧联动安全链路,用于快速下发关断和报警指令;现场仍应保留硬件级急停/互锁作为最终安全边界。 ### 2.3 指标口径 当前计算与判定主要围绕以下指标: - `1.1` 开启时间:到达输入电压 90% 的时间 - `1.2` 关闭时间:下降到输入电压 10% 的时间 - `1.5` 上升/下降时间:10%~90% 或 90%~10% 时间 - `1.9` 电压降:`Vin - Vout` - `1.10 / 1.13` 功率损耗、效率 - `1.14+` 保护功能相关触发条件、实测/观测值与人工判别结果 阈值定义和最终判断以 `Project.CurveThresholds` 与各页结果模型为准。 --- ## 3. 技术栈 | 用途 | 当前选型 | 说明 | |---|---|---| | UI | WPF + .NET 8 | `net8.0-windows`,x64 | | MVVM | `CommunityToolkit.Mvvm` | `ObservableObject` / `RelayCommand` | | 配置 | `Microsoft.Extensions.Configuration` | JSON + 用户设置覆盖 | | DI / Host | `Microsoft.Extensions.Hosting` | 启动时装配所有服务 | | Modbus | `NModbus` | SSPC 串口控制 | | 串口 | `System.IO.Ports` | SSPC/部分设备底层通信 | | TCP Socket | `System.Net.Sockets.TcpClient` | UDP5080 / IT87xx SCPI-RAW 通信 | | 原生驱动 | P/Invoke + 厂商 DLL | PCIe8586 / PCI2312 接入 | | 波形绘制 | `ScottPlot` / `ScottPlot.WPF` | 曲线页与报告插图 | | 报告 | `QuestPDF` + `DocumentFormat.OpenXml` | PDF 与 Word 双实现 | | Web 预览 | `Microsoft.Web.WebView2` | 报告页 PDF 预览 | | 日志 | Serilog | Debug + 文件输出 | --- ## 4. 解决方案结构 ### 4.1 分层 ```text UI (WPF / XAML / ViewModel) -> Logic (测试流程 / 计算 / 报告 / 存储) -> Devices.Interfaces (统一设备接口) -> Devices.Drivers.Mock / Real (具体驱动) ``` 依赖方向始终是 **上层只依赖下层抽象**。 例如 UI 只拿到 `ISspc`,不直接感知背后是 `MockSspc` 还是 `SspcModbus`。 ### 4.2 当前解决方案 ```text SSPCTester.sln ├── SSPCTester.UI/ # WPF 主程序(启动项) │ ├── Views/ # 页面与窗口 │ ├── ViewModels/ # MVVM 视图模型 │ ├── Controls/ # 自定义控件(含曲线控件) │ ├── Resources/ # Tokens / Controls / Icons │ ├── Converters/ # 状态与颜色转换 │ └── Services/ # 用户设置、应用配置等 ├── SSPCTester.Logic/ # 业务层 │ ├── Testing/ # 测试模块与运行器 │ ├── Calculation/ # 曲线/功率计算纯函数 │ ├── Report/ # PDF/Word 报告实现 │ ├── Storage/ # 项目与波形持久化 │ └── Models/ # 项目、结果、阈值、枚举 ├── SSPCTester.Devices/ # 设备抽象与驱动 │ ├── Interfaces/ # ISspc / IPowerSupply / ILoad / IDaq / ISafetyDio │ ├── Drivers/Mock/ # Mock 驱动 │ ├── Drivers/Real/ # 真设备驱动 │ ├── Drivers/ConfigurableDevices.cs # 按设备切换 Mock/Real │ ├── Protocol/ # 协议辅助 │ └── Config/ # 设备配置模型 ├── SSPCTester.Tests/ # xUnit 测试 ├── SSPCTester.Seed/ # 示例项目/种子数据生成 └── Docs/PCIe8586驱动接入资料/src/Pcie8586.Driver/ # 采集卡独立驱动类库,被 Devices/Tests 引用 ``` ### 4.3 关键脚本 - `run.ps1`:发布 UI、可选执行单测、可选灌入种子数据、最后启动发布产物 - `publish.ps1`:单独发布 WPF 程序 - `SSPCTester.Seed/WriteQualifiedProjects.ps1`:生成演示项目 --- ## 5. 配置与驱动切换 ### 5.1 配置加载顺序 程序启动时配置来源按优先级叠加: 1. 内置默认配置 2. `SSPCTester.UI/appsettings.json` 3. `%LOCALAPPDATA%\SSPCTester\settings.json` 用户在设置页修改的路径、报告格式等,最终写到用户目录,不回写仓库里的 `appsettings.json`。 ### 5.2 当前切换策略 当前采用 **每类设备独立切换**: - `Devices:Sspc:UseMock` - `Devices:PowerSupply:UseMock` - `Devices:Load:UseMock` - `Devices:Daq:UseMock` - `Devices:Pci2312:UseMock` `Devices:MockMode` 仅保留兼容旧配置用途,不应再作为新逻辑入口。 ### 5.3 当前 `appsettings.json` 节选 ```json { "Devices": { "MockMode": false, "Sspc": { "UseMock": false, "AutoConnect": true, "PortName": "COM1", "BaudRate": 9600, "ModuleAddresses": [1, 2, 3] }, "PowerSupply": { "UseMock": false, "AutoConnect": true, "Host": "192.168.6.5", "Port": 5025 }, "Load": { "UseMock": false, "AutoConnect": true, "Host": "192.168.200.100", "Port": 30000 }, "Daq": { "UseMock": false, "AutoConnect": true, "LogicalDeviceId": 0, "ChannelCount": 1, "InputRange": "PlusMinus5V", "ClockDivider": 1000, "PreTriggerMs": 3, "PostTriggerMs": 100, "Channels": [ { "PhysicalChannel": 0, "Role": "OutputVoltage", "Name": "输出电压", "Scale": 1.0, "Offset": 0.0, "IsCalibrated": true }, { "PhysicalChannel": 1, "Role": "Unconfigured", "Name": "CH1", "Scale": 1.0, "Offset": 0.0, "IsCalibrated": false } ] }, "Pci2312": { "Enabled": true, "UseMock": false, "AutoConnect": true, "DeviceId": 0, "EmergencyInputChannel": 0, "EmergencyInputActiveHigh": true, "AlarmOutputChannel": 0, "AlarmOutputActiveHigh": true, "PollIntervalMs": 100 } }, "Storage": { "ProjectsRoot": "%LOCALAPPDATA%\\SSPCTester\\Projects" }, "Report": { "SavePath": "%LOCALAPPDATA%\\SSPCTester\\Reports", "Format": "Pdf" } } ``` --- ## 6. 设备接口 所有设备接口均为异步接口,默认支持 `CancellationToken`。 ### 6.1 公共连接接口 ```csharp public interface IDeviceConnection { bool IsConnected { get; } string DisplayName { get; } Task ConnectAsync(CancellationToken ct = default); Task DisconnectAsync(); event EventHandler? ConnectionChanged; } ``` ### 6.2 SSPC ```csharp public interface ISspc : IDeviceConnection { int ChannelCount { get; } Task TurnOnAsync(int physicalSlot, CancellationToken ct = default); Task TurnOffAsync(int physicalSlot, CancellationToken ct = default); Task FlashAsync(int physicalSlot, int milliseconds, CancellationToken ct = default); Task GetChannelStateAsync(int physicalSlot, CancellationToken ct = default); Task ReadMeasurementAsync(int physicalSlot, CancellationToken ct = default); Task> ReadMeasurementsAsync(CancellationToken ct = default); } ``` ### 6.3 电源 ```csharp public interface IPowerSupply : IDeviceConnection { Task SetVoltageAsync(double volts, CancellationToken ct = default); Task SetCurrentLimitAsync(double amps, CancellationToken ct = default); Task OutputAsync(bool on, CancellationToken ct = default); Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default); Task QueryIdentityAsync(CancellationToken ct = default); } ``` ### 6.4 负载 ```csharp public readonly record struct PowerReading(double Volts, double Amps, double Watts); public interface ILoad : IDeviceConnection { Task SetModeAsync(LoadMode mode, CancellationToken ct = default); Task SetValueAsync(double value, CancellationToken ct = default); Task InputAsync(bool on, CancellationToken ct = default); Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default); Task ReadPowerAsync(CancellationToken ct = default); Task QueryIdentityAsync(CancellationToken ct = default); } ``` ### 6.5 DAQ ```csharp public interface IDaq : IDeviceConnection { Task> EnumerateDevicesAsync(CancellationToken ct = default); Task CaptureAsync(int[] channels, int sampleRateHz, double durationSec, CancellationToken ct = default); Task ReadInstantAsync(int[] channels, CancellationToken ct = default); Task CaptureAroundActionAsync( DaqActionCaptureRequest request, Func action, CancellationToken ct = default); event EventHandler? SampleReceived; } ``` `CaptureAroundActionAsync()` 是当前曲线测试的核心接口: 先进入预采集,再在触发点附近执行开关动作,以得到统一对齐的波形。 ### 6.6 安全 DIO ```csharp public interface ISafetyDio : IDeviceConnection { Task ReadInputAsync(int channel, CancellationToken ct = default); Task WriteOutputAsync(int channel, bool on, CancellationToken ct = default); } ``` 当前真实实现为 `Pci2312SafetyDio`: - `ConnectAsync()` 调用 `PCI2312_CreateDevice(DeviceId)` 创建设备句柄。 - `ReadInputAsync(channel)` 调用 `PCI2312_GetDeviceDI()` 读取 0~15 路 DI。 - `WriteOutputAsync(channel, on)` 维护 16 路 DO 状态数组,并调用 `PCI2312_SetDeviceDO()` 一次性写出。 - `DisconnectAsync()` 调用 `PCI2312_ReleaseDevice()` 释放句柄。 `ConfigurableSafetyDio` 按 `Devices:Pci2312:UseMock` 在 `MockSafetyDio` 与 `Pci2312SafetyDio` 间切换。PCI2312 是否参与自动连接由 `Devices:Pci2312:Enabled` 和 `Devices:Pci2312:AutoConnect` 共同决定。 --- ## 7. 核心业务逻辑 ### 7.1 测试模块统一入口 `Logic/Testing` 中已经落地: ```csharp public interface ITestModule { string Name { get; } Task RunAsync(TestContext ctx, IProgress progress, CancellationToken ct); } ``` `TestContext` 当前持有: - `Project` - `ISspc` - `IPowerSupply` - `ILoad` - `IDaq` `TestRunner` 依据 `Project.Selection` 串行执行模块。 设备安全监控不属于 `ITestModule`,不会进入项目测试结果,也不会由 `TestRunner` 调度;它由 UI 层 `SafetyMonitorService` 在程序运行期持续维护。 ### 7.2 浏览态 / 测试态 当前程序已实现两种应用状态: - **浏览态**:左侧树显示全部项目,可自由切换 - **测试态**: - 只显示当前项目 - 顶部展示“测试进行中”状态条 - 可中止测试 - 设备连接视为当前项目独占 这一逻辑由 `MainViewModel.AppState` 控制。 ### 7.3 基础测试 当前基础测试实现采用 `ISspc.ReadMeasurementAsync()` 直接读取每路电压/电流: ```text TurnOnAsync(ch) -> Delay -> ReadMeasurementAsync(ch) -> 记录 VoltageOn / CurrentOn -> TurnOffAsync(ch) -> WaitForStableOffAsync(ch) -> 根据导通和关断稳态结果判定 Pass / Fail ``` 说明: - 不是旧文档中的 `Daq.ReadInstant()` 方案 - “关断是否稳定”通过 `BasicTestCriteria.WaitForStableOffAsync()` 判定 ### 7.4 曲线测试 当前代码存在两套相关逻辑: 1. **Logic 模块批处理**:`CurveTest.cs` - 一次完成开通与关断两段采集 - 适用于测试模块整体执行 2. **UI 曲线页交互**:`CurveTestViewModel` - 已拆成两个独立按钮: - `开启曲线测试` - `关断曲线测试` - 开/关曲线各自保存、各自绘图、各自维护视窗范围 当前页与弹窗的“起点 / 终点 / 默认”已经拆成两套独立状态: - `RisingViewStartMs` / `RisingViewEndMs` - `FallingViewStartMs` / `FallingViewEndMs` 这些值会写回 `CurveResultRow` 并持久化。 状态规则: - 两半都没做:`Untested` - 只完成一半:`Measured` - 两半都完成后:才根据 4 个指标判 `Pass / Fail` ### 7.5 功率损耗 当前正式实现采用: - `UDP5080` 读取输入端 `Vin / Iin` - `IT87xx` 读取输出端 `Vout / Iout / Pout` 这是当前在用方案。 仓库中仍保留旧的 `PowerTestLegacy`(DAQ 思路),但未作为正式模块注册。 ### 7.6 保护功能 当前保护功能页和逻辑层已经按固定保护项落地,结果由 `ProtectRow` 持久化。`ProtectTestPlan` 负责初始化和刷新固定测试项: - `跳闸`:触发条件默认 `1.5×额定电流` - `短路`:触发条件默认 `输出短路` - `过温`:触发条件默认 `≥85℃` - `过压`:触发条件默认 `≥32V` - `欠压`:触发条件默认 `≤22V` - `限流`:触发条件默认 `≥1.2A` 保护功能数据分为两类: - **自动获取**:对 `跳闸`、`过压`、`欠压`、`限流` 等可由电源读数支撑的项目,页面提供“测”按钮,调用 `IPowerSupply.ReadAsync()` 获取当前电压/电流并写入 `MeasuredValue`。 - **人工观测**:对 `短路`、`过温` 等需要现场动作、仪表或人员观察的项目,由操作人员在 `MeasuredValue`、`Trigger` 等字段中填写观测记录。 判定口径: - 最终判别标准为**人工判别**,不由程序自动计算合格/不合格。 - `JudgeMode` 默认值为 `人工判别`。 - `Status` 由操作人员在表格中选择 `合格` / `不合格` / `未判定`。 - `ProtectTest.RunAsync()` 只负责刷新测量值和进度状态;若某项已经被人工判定为 `Pass` 或 `Fail`,运行批量测试时会保留该人工判定结果。 ### 7.7 设备安全监控 `SafetyMonitorService` 是当前急停/报警链路的中心,依赖: - `ISafetyDio`:读取急停 DI、写报警灯 DO。 - `ISspc`:触发急停后逐路执行 `TurnOffAsync(1..24)`。 - `IPowerSupply`:触发急停后执行 `OutputAsync(false)`,真实 UDP5080 命令为 `:OUTput OFF`。 - `ILoad`:触发急停后执行 `InputAsync(false)`,真实 IT8702P 命令为 `INP OFF`。 - `UiLogSink`:写入 UI 日志,便于现场追踪急停动作。 启动链路: ```text App.ConfigureServices() -> 注册 MockSafetyDio / Pci2312SafetyDio / ConfigurableSafetyDio -> 注册 SafetyMonitorService -> MainViewModel.Initialize() -> ConnectConfiguredDevicesAsync() -> SafetyMonitorService.Start() ``` 运行链路: ```text Timer(PollIntervalMs,代码中限制 50~10000ms) -> 自动连接 PCI2312(若启用 AutoConnect) -> ReadInputAsync(EmergencyInputChannel) -> 按 EmergencyInputActiveHigh 解释有效电平 -> 触发 HandleEmergencyAsync() ``` 急停处理具有防重入保护:`_gate` 和 `_handlingEmergency` 避免重复并发关断。每个设备的关断失败会单独记录日志,不阻断后续设备的关断尝试。 主窗口顶部状态区会展示: - 报警灯动态图标:绑定 `AlarmLampActive` - 急停/重置按钮:绑定 `ToggleEmergencyAlarmCommand` - 安全状态文本:来自 `SafetyMonitorService.StatusText / DetailText` - 设备面板中的 `报警/急停` 连接状态:来自 `ISafetyDio.IsConnected` ### 7.8 报告 当前报告支持: - PDF - Word - PDF + Word 报告特性: - 基于项目与勾选项动态生成 - 曲线插图由 `CurveImageRenderer` 生成 - 报告文件名不是固定 `report.docx`,而是动态解析后输出 - 报告页通过 `WebView2` 预览 PDF --- ## 8. 数据存储 ### 8.1 项目目录 每个项目一个目录,目录根路径由 `Storage:ProjectsRoot` 决定。 典型内容: - `project.json` - `curves/` - 生成出的 PDF / Word 报告 ### 8.2 项目对象 `Project` 当前持久化内容包括: - DUT 信息 - 测试站点信息 - 测试项勾选 - 报告配置 - 基础测试、曲线测试、功率损耗、保护功能结果 - 曲线阈值 - 四页测试说明文本 ### 8.3 波形存储格式 波形不是简单的 JSON,而是: - `curves/*.bin`:float32 二进制采样数据 - `curves/*.json`:元数据 元数据包含: - 采样率 - 触发点位置 - 通道角色/名称/单位 - 标定参数 ### 8.4 旧数据兼容 `CurveResultRow` 中保留了旧字段: - `ViewStartMs` - `ViewEndMs` 新逻辑优先使用: - `RisingViewStartMs / RisingViewEndMs` - `FallingViewStartMs / FallingViewEndMs` 缺失时会回退到旧字段,兼容老项目。 --- ## 9. 运行与发布 ### 9.1 本地运行 推荐命令: ```powershell PowerShell -ExecutionPolicy Bypass -File .\run.ps1 ``` 该脚本默认行为: 1. `dotnet publish` UI 到 `publish\win-x64` 2. 可选执行测试 3. 可选执行种子数据生成 4. 直接启动 `publish\win-x64\SSPCTester.UI.exe` ### 9.2 常用参数 - `-Test`:执行 `SSPCTester.Tests` - `-Seed`:执行 `SSPCTester.Seed` - `-CleanSeed`:清空项目目录后重新灌入种子数据 - `-NoLaunch`:只发布不启动 ### 9.3 发布 推荐命令: ```powershell PowerShell -ExecutionPolicy Bypass -File .\publish.ps1 ``` 当前默认发布参数是: - `Release` - `win-x64` - `SelfContained = true` - `SingleFile = false` 说明: - 当前脚本明确没有走 WPF 单文件发布默认方案 - 发布时会检查 `ACTS1000_64.dll` 是否存在 - PCI2312 真设备模式还需要 `PCI2312_64.dll` 可由进程加载;当前发布脚本未做该 DLL 的存在性检查 ### 9.4 运行环境 源码构建至少需要: - Windows x64 - .NET 8 SDK x64 - WebView2 Runtime - 真卡模式下的 PCIe8586 / PCI2312 厂商驱动与 x64 DLL 若只运行现成发布版,则至少需要满足发布产物依赖和本机驱动/DLL 条件。 --- ## 10. 当前状态与后续工作 ### 10.1 已完成 - WPF 主程序骨架、主题资源、页面导航 - 浏览态 / 测试态切换 - 项目新建、加载、保存 - 基础测试、曲线测试、功率损耗、保护功能页和结果记录 - PDF / Word 报告生成 - 真/假设备可按设备粒度切换 - 实际 SSPC / 电源 / 负载 / PCIe8586 / PCI2312 驱动接入代码 - PCI2312 急停输入轮询、报警输出、软件急停、状态重置和设备关断联动 ### 10.2 待统一 / 待完善 - 功率损耗旧版 `PowerTestLegacy` 仍在仓库,后续应明确去留 - 曲线弹窗窗口已实现,但当前主页面尚未提供入口按钮 - 报告生成对新旧曲线视窗字段的使用口径后续建议统一 - PCI2312 真设备链路需要在现场确认 DI/DO 接线、电平有效性、报警灯供电方式和 DLL 随发布产物部署方式 --- ## 11. 风险与注意事项 1. **DAQ 仍是最高风险点**:厂商 DLL、设备 ID、采样参数、输入量程和触发时序都依赖现场。 2. **Modbus 地址和端口仍需现场核实**:虽然当前实现已支持 3 模块映射,但设备地址/串口号应视现场配置为准。 3. **电源与负载真实驱动已接入,但控制命令支持度需按实物验证**。 4. **PCI2312 急停报警链路依赖现场接线和 DLL 部署**:DI/DO 通道号、高/低有效配置、报警灯供电、`PCI2312_64.dll` 位数和搜索路径都必须逐项核实。 5. **软件安全链路不能替代硬件安全回路**:`SafetyMonitorService` 通过轮询和软件命令下发关断,适合作为上位机联动保护;最终急停/互锁仍应由硬件电气回路兜底。 6. **状态重置必须确认急停输入已复位**:当前代码在 DI 仍有效时拒绝关闭报警灯,避免误复位。 7. **所有长流程应贯穿 `CancellationToken`**,中止后优先保证设备回到安全状态。 8. **示波器不纳入软件控制**,仅作为线下校准基准。 9. **任何涉及数据模型持久化格式的修改,都要考虑旧项目兼容**。 --- ## 12. 维护建议 1. 改接口前,先同步修改 `Devices.Interfaces`、实现类、DI 装配和本文档。 2. 改项目结构前,先检查 `run.ps1`、`publish.ps1`、`Seed`、测试项目是否受影响。 3. 改曲线页前,注意当前已经有“主页面 + 弹窗 + 报告图”的三处视窗相关逻辑。 4. 改报告前,确认 `ReportViewModel`、`Logic/Report`、`WebView2` 预览链路同时保持可用。 5. 改设备安全链路前,先确认 `ISafetyDio`、`Pci2312SafetyDio`、`ConfigurableSafetyDio`、`SafetyMonitorService`、主窗口急停按钮和设置页 PCI2312 配置同步调整。 6. 若发现文档内容再次与代码偏离,应优先更新本文档,而不是继续在过时约束上开发。