26 KiB
固态功率控制器动态参数测试系统 — 开发文档
版本 v1.3 | 更新:2026-07-08 14:58:50 +08:00 | 技术栈:C# + WPF + .NET 8 | 口径:以当前仓库代码为准
本文档描述当前仓库的真实结构、配置方式、核心流程和维护约定。 若文档与代码冲突,以代码实现为准,并应同步回写本文档。
0. 开发约束
对本项目进行新增、修改、排障时,默认遵守以下原则:
- 分层隔离优先:UI 只依赖 ViewModel / Service / Logic,不直接依赖具体设备驱动。
- 接口先行:SSPC、电源、负载、DAQ、安全 DIO 一律经
SSPCTester.Devices.Interfaces暴露,真假驱动由配置决定。 - 按设备粒度切换 Mock/Real:当前不再是“一个全局
MockMode管全部设备”,而是每类设备都有自己的UseMock。 - 配置分层加载:程序先读内置默认值,再读
appsettings.json,最后读%LOCALAPPDATA%\SSPCTester\settings.json。 - 测试态独占:进入测试后只展示当前项目,禁止切换其他项目,设备连接由测试态独占。
- 文档随代码更新:涉及接口、项目结构、运行方式、持久化格式变化时,要同步更新本文档。
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. 当前功能范围
主流程如下:
新建/打开项目
-> 填写项目信息 / 勾选测试项
-> 进入测试态
-> 执行基础测试 / 曲线测试 / 功率损耗 / 保护功能
-> 生成 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 复位会自动关闭报警输出、清除硬件急停锁存和软件急停状态,并刷新 UI 回到“报警急停”。
控制链路如下:
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 - Vout1.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 分层
UI (WPF / XAML / ViewModel)
-> Logic (测试流程 / 计算 / 报告 / 存储)
-> Devices.Interfaces (统一设备接口)
-> Devices.Drivers.Mock / Real (具体驱动)
依赖方向始终是 上层只依赖下层抽象。
例如 UI 只拿到 ISspc,不直接感知背后是 MockSspc 还是 SspcModbus。
4.2 当前解决方案
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 配置加载顺序
程序启动时配置来源按优先级叠加:
- 内置默认配置
SSPCTester.UI/appsettings.json%LOCALAPPDATA%\SSPCTester\settings.json
用户在设置页修改的路径、报告格式等,最终写到用户目录,不回写仓库里的 appsettings.json。
5.2 当前切换策略
当前采用 每类设备独立切换:
Devices:Sspc:UseMockDevices:PowerSupply:UseMockDevices:Load:UseMockDevices:Daq:UseMockDevices:Pci2312:UseMock
Devices:MockMode 仅保留兼容旧配置用途,不应再作为新逻辑入口。
5.3 当前 appsettings.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 公共连接接口
public interface IDeviceConnection
{
bool IsConnected { get; }
string DisplayName { get; }
Task<bool> ConnectAsync(CancellationToken ct = default);
Task DisconnectAsync();
event EventHandler<bool>? ConnectionChanged;
}
6.2 SSPC
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<bool> GetChannelStateAsync(int physicalSlot, CancellationToken ct = default);
Task<ChannelMeasurement> ReadMeasurementAsync(int physicalSlot, CancellationToken ct = default);
Task<IReadOnlyList<ChannelMeasurement>> ReadMeasurementsAsync(CancellationToken ct = default);
}
6.3 电源
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<string> QueryIdentityAsync(CancellationToken ct = default);
}
6.4 负载
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<PowerReading> ReadPowerAsync(CancellationToken ct = default);
Task<string> QueryIdentityAsync(CancellationToken ct = default);
}
6.5 DAQ
public interface IDaq : IDeviceConnection
{
Task<IReadOnlyList<DaqDeviceDescriptor>> EnumerateDevicesAsync(CancellationToken ct = default);
Task<CurveData> CaptureAsync(int[] channels, int sampleRateHz, double durationSec, CancellationToken ct = default);
Task<double[]> ReadInstantAsync(int[] channels, CancellationToken ct = default);
Task<CurveData> CaptureAroundActionAsync(
DaqActionCaptureRequest request,
Func<CancellationToken, Task> action,
CancellationToken ct = default);
event EventHandler<CurveSample>? SampleReceived;
}
CaptureAroundActionAsync() 是当前曲线测试的核心接口:
先进入预采集,再在触发点附近执行开关动作,以得到统一对齐的波形。
6.6 安全 DIO
public interface ISafetyDio : IDeviceConnection
{
Task<bool> 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 中已经落地:
public interface ITestModule
{
string Name { get; }
Task RunAsync(TestContext ctx, IProgress<TestProgress> progress, CancellationToken ct);
}
TestContext 当前持有:
ProjectISspcIPowerSupplyILoadIDaq
TestRunner 依据 Project.Selection 串行执行模块。
设备安全监控不属于 ITestModule,不会进入项目测试结果,也不会由 TestRunner 调度;它由 UI 层 SafetyMonitorService 在程序运行期持续维护。
7.2 浏览态 / 测试态
当前程序已实现两种应用状态:
- 浏览态:左侧树显示全部项目,可自由切换
- 测试态:
- 只显示当前项目
- 顶部展示“测试进行中”状态条
- 可中止测试
- 设备连接视为当前项目独占
这一逻辑由 MainViewModel.AppState 控制。
7.3 基础测试
当前基础测试实现采用 ISspc.ReadMeasurementAsync() 直接读取每路电压/电流:
TurnOnAsync(ch)
-> Delay
-> ReadMeasurementAsync(ch)
-> 记录 VoltageOn / CurrentOn
-> TurnOffAsync(ch)
-> WaitForStableOffAsync(ch)
-> 根据导通和关断稳态结果判定 Pass / Fail
说明:
- 不是旧文档中的
Daq.ReadInstant()方案 - “关断是否稳定”通过
BasicTestCriteria.WaitForStableOffAsync()判定
7.4 曲线测试
当前代码存在两套相关逻辑:
- Logic 模块批处理:
CurveTest.cs- 一次完成开通与关断两段采集
- 适用于测试模块整体执行
- UI 曲线页交互:
CurveTestViewModel- 已拆成两个独立按钮:
开启曲线测试关断曲线测试
- 开/关曲线各自保存、各自绘图、各自维护视窗范围
- 已拆成两个独立按钮:
当前页与弹窗的“起点 / 终点 / 默认”已经拆成两套独立状态:
RisingViewStartMs/RisingViewEndMsFallingViewStartMs/FallingViewEndMs
这些值会写回 CurveResultRow 并持久化。
状态规则:
- 两半都没做:
Untested - 只完成一半:
Measured - 两半都完成后:才根据 4 个指标判
Pass / Fail
7.5 功率损耗
当前正式实现采用:
UDP5080读取输入端Vin / IinIT87xx读取输出端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 日志,便于现场追踪急停动作。
启动链路:
App.ConfigureServices()
-> 注册 MockSafetyDio / Pci2312SafetyDio / ConfigurableSafetyDio
-> 注册 SafetyMonitorService
-> MainViewModel.Initialize()
-> ConnectConfiguredDevicesAsync()
-> SafetyMonitorService.Start()
运行链路:
Timer(PollIntervalMs,代码中限制 50~10000ms)
-> 自动连接 PCI2312(若启用 AutoConnect)
-> ReadInputAsync(EmergencyInputChannel)
-> 按 EmergencyInputActiveHigh 解释有效电平
-> DI 有效时锁存硬件急停并触发 HandleEmergencyAsync()
-> 硬件急停锁存后 DI 复位时触发 ClearHardwareEmergencyAsync()
急停处理具有防重入保护:_gate 和 _handlingEmergency 避免重复并发关断;_hardwareEmergencyLatched 用于区分“硬件急停曾触发后解除”和“纯软件急停等待手动重置”。每个设备的关断失败会单独记录日志,不阻断后续设备的关断尝试。
解除行为:
- 硬件急停触发后,DI 复位会自动关闭报警 DO,清除
_handlingEmergency、_softwareEmergencyActive、_hardwareEmergencyLatched,并刷新 UI 按钮回到“报警急停”。 - 纯软件急停不会因为硬件 DI 处于未触发状态而被轮询自动解除,仍需要点击“状态重置”;若此时硬件 DI 仍有效,重置会被拒绝。
主窗口顶部状态区会展示:
- 报警灯动态图标:绑定
AlarmLampActive - 急停/重置按钮:绑定
ToggleEmergencyAlarmCommand - 安全状态文本:来自
SafetyMonitorService.StatusText / DetailText - 设备面板中的
报警/急停连接状态:来自ISafetyDio.IsConnected
7.8 报告
当前报告支持:
- Word
- PDF + Word
报告特性:
- 基于项目与勾选项动态生成
- 曲线插图由
CurveImageRenderer生成 - 报告文件名不是固定
report.docx,而是动态解析后输出 - 报告页通过
WebView2预览 PDF
8. 数据存储
8.1 项目目录
每个项目一个目录,目录根路径由 Storage:ProjectsRoot 决定。
典型内容:
project.jsoncurves/- 生成出的 PDF / Word 报告
8.2 项目对象
Project 当前持久化内容包括:
- DUT 信息
- 测试站点信息
- 测试项勾选
- 报告配置
- 基础测试、曲线测试、功率损耗、保护功能结果
- 曲线阈值
- 四页测试说明文本
8.3 波形存储格式
波形不是简单的 JSON,而是:
curves/*.bin:float32 二进制采样数据curves/*.json:元数据
元数据包含:
- 采样率
- 触发点位置
- 通道角色/名称/单位
- 标定参数
8.4 旧数据兼容
CurveResultRow 中保留了旧字段:
ViewStartMsViewEndMs
新逻辑优先使用:
RisingViewStartMs / RisingViewEndMsFallingViewStartMs / FallingViewEndMs
缺失时会回退到旧字段,兼容老项目。
9. 运行与发布
9.1 本地运行
推荐命令:
PowerShell -ExecutionPolicy Bypass -File .\run.ps1
该脚本默认行为:
dotnet publishUI 到publish\win-x64- 可选执行测试
- 可选执行种子数据生成
- 直接启动
publish\win-x64\SSPCTester.UI.exe
9.2 常用参数
-Test:执行SSPCTester.Tests-Seed:执行SSPCTester.Seed-CleanSeed:清空项目目录后重新灌入种子数据-NoLaunch:只发布不启动
9.3 发布
推荐命令:
PowerShell -ExecutionPolicy Bypass -File .\publish.ps1
当前默认发布参数是:
Releasewin-x64SelfContained = trueSingleFile = 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. 风险与注意事项
- DAQ 仍是最高风险点:厂商 DLL、设备 ID、采样参数、输入量程和触发时序都依赖现场。
- Modbus 地址和端口仍需现场核实:虽然当前实现已支持 3 模块映射,但设备地址/串口号应视现场配置为准。
- 电源与负载真实驱动已接入,但控制命令支持度需按实物验证。
- PCI2312 急停报警链路依赖现场接线和 DLL 部署:DI/DO 通道号、高/低有效配置、报警灯供电、
PCI2312_64.dll位数和搜索路径都必须逐项核实。 - 软件安全链路不能替代硬件安全回路:
SafetyMonitorService通过轮询和软件命令下发关断,适合作为上位机联动保护;最终急停/互锁仍应由硬件电气回路兜底。 - 状态重置与硬件解除都必须确认急停输入已复位:当前代码在 DI 仍有效时拒绝手动重置;硬件急停锁存后只有检测到 DI 复位才会自动关闭报警灯并清除软件急停状态,避免误复位。
- 所有长流程应贯穿
CancellationToken,中止后优先保证设备回到安全状态。 - 示波器不纳入软件控制,仅作为线下校准基准。
- 任何涉及数据模型持久化格式的修改,都要考虑旧项目兼容。
12. 维护建议
- 改接口前,先同步修改
Devices.Interfaces、实现类、DI 装配和本文档。 - 改项目结构前,先检查
run.ps1、publish.ps1、Seed、测试项目是否受影响。 - 改曲线页前,注意当前已经有“主页面 + 弹窗 + 报告图”的三处视窗相关逻辑。
- 改报告前,确认
ReportViewModel、Logic/Report、WebView2预览链路同时保持可用。 - 改设备安全链路前,先确认
ISafetyDio、Pci2312SafetyDio、ConfigurableSafetyDio、SafetyMonitorService、主窗口急停按钮和设置页 PCI2312 配置同步调整。 - 若发现文档内容再次与代码偏离,应优先更新本文档,而不是继续在过时约束上开发。