修改急停联动

This commit is contained in:
zhaotielin 2026-07-09 10:47:46 +08:00
parent 76f9b8641b
commit b10b321e7d
2 changed files with 34 additions and 9 deletions

View File

@ -81,9 +81,9 @@
- 硬件连接:`PCI2312` 通过厂商 `PCI2312_64.dll` 以 P/Invoke 方式接入,使用 DI 通道读取急停状态,使用 DO 通道控制报警灯。 - 硬件连接:`PCI2312` 通过厂商 `PCI2312_64.dll` 以 P/Invoke 方式接入,使用 DI 通道读取急停状态,使用 DO 通道控制报警灯。
- 后台监控:`SafetyMonitorService.Start()` 在主窗口初始化后启动,按 `Devices:Pci2312:PollIntervalMs` 周期轮询急停输入。 - 后台监控:`SafetyMonitorService.Start()` 在主窗口初始化后启动,按 `Devices:Pci2312:PollIntervalMs` 周期轮询急停输入。
- 硬件急停:当配置的 DI 通道达到有效电平时,程序写入报警 DO并依次执行 SSPC 全通道关断、电源输出关闭、负载输入关闭。 - 硬件急停:当配置的 DI 通道达到有效电平时,程序锁存硬件急停状态,写入报警 DO并依次执行 SSPC 全通道关断、电源输出关闭、负载输入关闭。
- 软件急停:主窗口顶部“报警急停”按钮调用 `TriggerSoftwareEmergencyAsync()`,走同一套报警灯和设备关断链路。 - 软件急停:主窗口顶部“报警急停”按钮调用 `TriggerSoftwareEmergencyAsync()`,走同一套报警灯和设备关断链路;纯软件急停需要通过“状态重置”解除
- 状态重置:报警灯点亮后按钮变为“状态重置”。若硬件急停 DI 仍有效,重置会被拒绝DI 复位后才关闭报警输出并恢复监控状态 - 状态重置与硬件解除:报警灯点亮后按钮变为“状态重置”。若硬件急停 DI 仍有效,手动重置会被拒绝硬件急停曾触发后DI 复位会自动关闭报警输出、清除硬件急停锁存和软件急停状态,并刷新 UI 回到“报警急停”
控制链路如下: 控制链路如下:
@ -518,10 +518,16 @@ Timer(PollIntervalMs代码中限制 50~10000ms)
-> 自动连接 PCI2312若启用 AutoConnect -> 自动连接 PCI2312若启用 AutoConnect
-> ReadInputAsync(EmergencyInputChannel) -> ReadInputAsync(EmergencyInputChannel)
-> 按 EmergencyInputActiveHigh 解释有效电平 -> 按 EmergencyInputActiveHigh 解释有效电平
-> 触发 HandleEmergencyAsync() -> DI 有效时锁存硬件急停并触发 HandleEmergencyAsync()
-> 硬件急停锁存后 DI 复位时触发 ClearHardwareEmergencyAsync()
``` ```
急停处理具有防重入保护:`_gate` 和 `_handlingEmergency` 避免重复并发关断。每个设备的关断失败会单独记录日志,不阻断后续设备的关断尝试。 急停处理具有防重入保护:`_gate` 和 `_handlingEmergency` 避免重复并发关断;`_hardwareEmergencyLatched` 用于区分“硬件急停曾触发后解除”和“纯软件急停等待手动重置”。每个设备的关断失败会单独记录日志,不阻断后续设备的关断尝试。
解除行为:
- 硬件急停触发后DI 复位会自动关闭报警 DO清除 `_handlingEmergency`、`_softwareEmergencyActive`、`_hardwareEmergencyLatched`,并刷新 UI 按钮回到“报警急停”。
- 纯软件急停不会因为硬件 DI 处于未触发状态而被轮询自动解除,仍需要点击“状态重置”;若此时硬件 DI 仍有效,重置会被拒绝。
主窗口顶部状态区会展示: 主窗口顶部状态区会展示:
@ -669,7 +675,7 @@ PowerShell -ExecutionPolicy Bypass -File .\publish.ps1
- PDF / Word 报告生成 - PDF / Word 报告生成
- 真/假设备可按设备粒度切换 - 真/假设备可按设备粒度切换
- 实际 SSPC / 电源 / 负载 / PCIe8586 / PCI2312 驱动接入代码 - 实际 SSPC / 电源 / 负载 / PCIe8586 / PCI2312 驱动接入代码
- PCI2312 急停输入轮询、报警输出、软件急停、状态重置和设备关断联动 - PCI2312 急停输入轮询、报警输出、软件急停、硬件解除联动、状态重置和设备关断联动
### 10.2 待统一 / 待完善 ### 10.2 待统一 / 待完善
@ -687,7 +693,7 @@ PowerShell -ExecutionPolicy Bypass -File .\publish.ps1
3. **电源与负载真实驱动已接入,但控制命令支持度需按实物验证** 3. **电源与负载真实驱动已接入,但控制命令支持度需按实物验证**
4. **PCI2312 急停报警链路依赖现场接线和 DLL 部署**DI/DO 通道号、高/低有效配置、报警灯供电、`PCI2312_64.dll` 位数和搜索路径都必须逐项核实。 4. **PCI2312 急停报警链路依赖现场接线和 DLL 部署**DI/DO 通道号、高/低有效配置、报警灯供电、`PCI2312_64.dll` 位数和搜索路径都必须逐项核实。
5. **软件安全链路不能替代硬件安全回路**`SafetyMonitorService` 通过轮询和软件命令下发关断,适合作为上位机联动保护;最终急停/互锁仍应由硬件电气回路兜底。 5. **软件安全链路不能替代硬件安全回路**`SafetyMonitorService` 通过轮询和软件命令下发关断,适合作为上位机联动保护;最终急停/互锁仍应由硬件电气回路兜底。
6. **状态重置必须确认急停输入已复位**:当前代码在 DI 仍有效时拒绝关闭报警灯,避免误复位。 6. **状态重置与硬件解除都必须确认急停输入已复位**:当前代码在 DI 仍有效时拒绝手动重置;硬件急停锁存后只有检测到 DI 复位才会自动关闭报警灯并清除软件急停状态,避免误复位。
7. **所有长流程应贯穿 `CancellationToken`**,中止后优先保证设备回到安全状态。 7. **所有长流程应贯穿 `CancellationToken`**,中止后优先保证设备回到安全状态。
8. **示波器不纳入软件控制**,仅作为线下校准基准。 8. **示波器不纳入软件控制**,仅作为线下校准基准。
9. **任何涉及数据模型持久化格式的修改,都要考虑旧项目兼容** 9. **任何涉及数据模型持久化格式的修改,都要考虑旧项目兼容**

View File

@ -18,6 +18,7 @@ public sealed class SafetyMonitorService : IDisposable
private Timer? _timer; private Timer? _timer;
private bool _handlingEmergency; private bool _handlingEmergency;
private bool _softwareEmergencyActive; private bool _softwareEmergencyActive;
private bool _hardwareEmergencyLatched;
private bool _disposed; private bool _disposed;
public SafetyMonitorService( public SafetyMonitorService(
@ -55,7 +56,7 @@ public sealed class SafetyMonitorService : IDisposable
return; return;
} }
int interval = Math.Clamp(options.PollIntervalMs, 50, 10_000); int interval = Math.Clamp(options.PollIntervalMs, 50, 10000);
_timer = new Timer(OnTimer, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(interval)); _timer = new Timer(OnTimer, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(interval));
SetStatus(false, false, "设备正常", "正在监控 PCI2312 急停输入"); SetStatus(false, false, "设备正常", "正在监控 PCI2312 急停输入");
} }
@ -118,6 +119,7 @@ public sealed class SafetyMonitorService : IDisposable
await SetAlarmOutputAsync(false, ct).ConfigureAwait(false); await SetAlarmOutputAsync(false, ct).ConfigureAwait(false);
_softwareEmergencyActive = false; _softwareEmergencyActive = false;
_hardwareEmergencyLatched = false;
_handlingEmergency = false; _handlingEmergency = false;
SetStatus(false, false, "设备正常", "急停状态已重置,报警灯已关闭,正在监控 PCI2312 输入"); SetStatus(false, false, "设备正常", "急停状态已重置,报警灯已关闭,正在监控 PCI2312 输入");
return new SafetyResetResult(true, "急停状态已重置。"); return new SafetyResetResult(true, "急停状态已重置。");
@ -143,15 +145,20 @@ public sealed class SafetyMonitorService : IDisposable
bool active = await IsEmergencyInputActiveAsync(options, CancellationToken.None).ConfigureAwait(false); bool active = await IsEmergencyInputActiveAsync(options, CancellationToken.None).ConfigureAwait(false);
if (active) if (active)
{ {
_hardwareEmergencyLatched = true;
await HandleEmergencyAsync().ConfigureAwait(false); await HandleEmergencyAsync().ConfigureAwait(false);
} }
else if (_hardwareEmergencyLatched)
{
await ClearHardwareEmergencyAsync(options).ConfigureAwait(false);
}
else if (_softwareEmergencyActive) else if (_softwareEmergencyActive)
{ {
SetStatus(true, IsAlarmOutputOn, "软件急停已触发", "等待状态重置,电源和负载不会自动恢复"); SetStatus(true, IsAlarmOutputOn, "软件急停已触发", "等待状态重置,电源和负载不会自动恢复");
} }
else if (IsEmergencyActive || IsAlarmOutputOn) else if (IsEmergencyActive || IsAlarmOutputOn)
{ {
SetStatus(true, IsAlarmOutputOn, "急停已触发", $"DI{options.EmergencyInputChannel} 已复位,请点击状态重置关闭报警灯"); await ClearHardwareEmergencyAsync(options).ConfigureAwait(false);
} }
else else
{ {
@ -193,6 +200,18 @@ public sealed class SafetyMonitorService : IDisposable
} }
} }
private async Task ClearHardwareEmergencyAsync(Pci2312Options options)
{
if (IsAlarmOutputOn)
await SetAlarmOutputAsync(false, CancellationToken.None).ConfigureAwait(false);
_handlingEmergency = false;
_softwareEmergencyActive = false;
_hardwareEmergencyLatched = false;
SetStatus(false, false, "设备正常", $"DI{options.EmergencyInputChannel} 已复位,硬件急停已解除,报警灯已关闭,设备输出不会自动恢复");
_log.Add(UiLogLevel.Info, "硬件急停输入已复位,软件急停状态和报警灯已自动解除。");
}
private async Task TryShutdownSspcAsync() private async Task TryShutdownSspcAsync()
{ {
try try