更新20260605
This commit is contained in:
@@ -1342,6 +1342,24 @@
|
|||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ItemsControl.ItemsPanel>
|
</ItemsControl.ItemsPanel>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
<Button MinWidth="132"
|
||||||
|
Height="34"
|
||||||
|
Margin="0,0,10,10"
|
||||||
|
Padding="12,4"
|
||||||
|
Command="{Binding CalibrateProximalPressureCommand}"
|
||||||
|
Content="近端压力校准"
|
||||||
|
Background="#FFB7791F"
|
||||||
|
IsEnabled="{Binding CanModifySession}"
|
||||||
|
ToolTip="M1300" />
|
||||||
|
<Button MinWidth="132"
|
||||||
|
Height="34"
|
||||||
|
Margin="0,0,10,10"
|
||||||
|
Padding="12,4"
|
||||||
|
Command="{Binding CalibrateDistalPressureCommand}"
|
||||||
|
Content="远端压力校准"
|
||||||
|
Background="#FFB7791F"
|
||||||
|
IsEnabled="{Binding CanModifySession}"
|
||||||
|
ToolTip="M1301" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public interface IModbusTelemetryService
|
|||||||
float? ReadHoldingFloatRegister(ushort address);
|
float? ReadHoldingFloatRegister(ushort address);
|
||||||
bool WriteHoldingRegister(ushort address, ushort value);
|
bool WriteHoldingRegister(ushort address, ushort value);
|
||||||
bool WriteHoldingFloatRegister(ushort address, float value);
|
bool WriteHoldingFloatRegister(ushort address, float value);
|
||||||
|
bool WriteCoil(ushort address, bool value, string operationName);
|
||||||
// Legacy PLC coil path retained only for non-RS485 pump compatibility.
|
// Legacy PLC coil path retained only for non-RS485 pump compatibility.
|
||||||
void SetPumpRunning(string pumpKey, bool isRunning);
|
void SetPumpRunning(string pumpKey, bool isRunning);
|
||||||
void SetValveOpen(string valveKey, bool isOpen);
|
void SetValveOpen(string valveKey, bool isOpen);
|
||||||
|
|||||||
@@ -386,6 +386,45 @@ public sealed class ModbusTelemetryService : IModbusTelemetryService, IDisposabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool WriteCoil(ushort address, bool value, string operationName)
|
||||||
|
{
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
if (_master is null)
|
||||||
|
{
|
||||||
|
_lastErrorMessage = $"PLC 离线,未执行{operationName}线圈写入:M{address}";
|
||||||
|
Logger.Warning(
|
||||||
|
"PLC 离线,跳过线圈写入,Operation={Operation},Coil=M{CoilAddress},Value={Value}",
|
||||||
|
operationName,
|
||||||
|
address,
|
||||||
|
value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_master.WriteSingleCoil(_slaveId, address, value);
|
||||||
|
Logger.Information(
|
||||||
|
"PLC 线圈写入成功,Operation={Operation},Coil=M{CoilAddress},Value={Value}",
|
||||||
|
operationName,
|
||||||
|
address,
|
||||||
|
value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(
|
||||||
|
ex,
|
||||||
|
"PLC 线圈写入失败,Operation={Operation},Coil=M{CoilAddress},Value={Value}",
|
||||||
|
operationName,
|
||||||
|
address,
|
||||||
|
value);
|
||||||
|
HandleConnectionFailure($"{operationName}线圈 M{address} 写入失败:{ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetValveOpen(string valveKey, bool isOpen)
|
public void SetValveOpen(string valveKey, bool isOpen)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_syncRoot)
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
|||||||
private const string SettingsDirectoryName = "Cardiopulmonarybypasssystems";
|
private const string SettingsDirectoryName = "Cardiopulmonarybypasssystems";
|
||||||
private const string LimitSettingsFileName = "manufacturer-limits.json";
|
private const string LimitSettingsFileName = "manufacturer-limits.json";
|
||||||
private const float EngineeringFloatVerificationTolerance = 0.0001f;
|
private const float EngineeringFloatVerificationTolerance = 0.0001f;
|
||||||
|
private const ushort ProximalPressureCalibrationCoil = 1300;
|
||||||
|
private const ushort DistalPressureCalibrationCoil = 1301;
|
||||||
|
private static readonly TimeSpan PressureCalibrationPulseDuration = TimeSpan.FromMilliseconds(300);
|
||||||
private static readonly (string Name, ushort Address)[] FlowCoefficientRegisters =
|
private static readonly (string Name, ushort Address)[] FlowCoefficientRegisters =
|
||||||
[
|
[
|
||||||
("流量系数1", 1006),
|
("流量系数1", 1006),
|
||||||
@@ -62,6 +65,7 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
|||||||
private string _lastTelemetryRefreshFailureMessage = string.Empty;
|
private string _lastTelemetryRefreshFailureMessage = string.Empty;
|
||||||
private double? _proximalPressureRawKpa;
|
private double? _proximalPressureRawKpa;
|
||||||
private double? _distalPressureRawKpa;
|
private double? _distalPressureRawKpa;
|
||||||
|
private bool _pressureCalibrationPulseInProgress;
|
||||||
private static string ResolveLimitSettingsPath()
|
private static string ResolveLimitSettingsPath()
|
||||||
{
|
{
|
||||||
return Path.Combine(
|
return Path.Combine(
|
||||||
@@ -875,6 +879,71 @@ public partial class MainViewModel : ObservableObject, IDisposable
|
|||||||
_ = RefreshTelemetryAsync();
|
_ = RefreshTelemetryAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task CalibrateProximalPressure()
|
||||||
|
{
|
||||||
|
await PulsePressureCalibrationAsync("近端压力校准", ProximalPressureCalibrationCoil);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task CalibrateDistalPressure()
|
||||||
|
{
|
||||||
|
await PulsePressureCalibrationAsync("远端压力校准", DistalPressureCalibrationCoil);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PulsePressureCalibrationAsync(string calibrationName, ushort coilAddress)
|
||||||
|
{
|
||||||
|
if (!EnsureSessionEditable(calibrationName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pressureCalibrationPulseInProgress)
|
||||||
|
{
|
||||||
|
LatestAction = "压力校准指令正在执行,请稍后再操作。";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pressureCalibrationPulseInProgress = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Information(
|
||||||
|
"执行压力校准脉冲,CalibrationName={CalibrationName},Coil=M{CoilAddress},TelemetryOnline={TelemetryOnline}",
|
||||||
|
calibrationName,
|
||||||
|
coilAddress,
|
||||||
|
IsTelemetryOnline);
|
||||||
|
|
||||||
|
if (!_telemetryService.WriteCoil(coilAddress, true, calibrationName))
|
||||||
|
{
|
||||||
|
LatestAction = IsTelemetryOnline
|
||||||
|
? $"{calibrationName} 指令下发失败:{_telemetryService.LastErrorMessage}"
|
||||||
|
: $"{calibrationName} 指令未下发,PLC 当前离线。";
|
||||||
|
TraceEvents.Insert(0, NewTrace("压力校准", $"{calibrationName} / M{coilAddress}=1 下发失败"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LatestAction = $"{calibrationName} 已触发,M{coilAddress}=1。";
|
||||||
|
TraceEvents.Insert(0, NewTrace("压力校准", $"{calibrationName} / M{coilAddress}=1"));
|
||||||
|
|
||||||
|
await Task.Delay(PressureCalibrationPulseDuration);
|
||||||
|
|
||||||
|
if (!_telemetryService.WriteCoil(coilAddress, false, calibrationName))
|
||||||
|
{
|
||||||
|
LatestAction = $"{calibrationName} 释放失败,请检查 PLC 线圈 M{coilAddress}。";
|
||||||
|
TraceEvents.Insert(0, NewTrace("压力校准", $"{calibrationName} / M{coilAddress}=0 释放失败"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LatestAction = $"{calibrationName} 已完成校准脉冲。";
|
||||||
|
TraceEvents.Insert(0, NewTrace("压力校准", $"{calibrationName} / M{coilAddress}=0"));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_pressureCalibrationPulseInProgress = false;
|
||||||
|
_ = RefreshTelemetryAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void ClearTrendData()
|
private void ClearTrendData()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user