This commit is contained in:
GukSang.Jin
2026-05-20 09:45:34 +08:00
parent 8f625a7a41
commit 070463ae8e
8 changed files with 240 additions and 502 deletions

View File

@@ -35,6 +35,9 @@ namespace TabletTester2025.ViewModels
private bool _isLoadingDisintegrationSpeed;
private bool _isLoadingFriabilityRounds;
private bool _isUpdatingFriabilityWeightFromPlc;
private bool _isReadingHardnessLiveForce;
private int _hardnessGroupNo;
private int _currentHardnessGroupNo;
private readonly List<double> _dissolution1Times = new();
private readonly List<double> _dissolution1Values = new();
@@ -85,6 +88,7 @@ namespace TabletTester2025.ViewModels
private List<double> _hardnessResults = new();
public ObservableCollection<HardnessSamplePoint> HardnessSamplePoints { get; } = new();
public ObservableCollection<HardnessDisplaySamplePoint> HardnessDisplaySamplePoints { get; } = new();
// 脆碎度
[ObservableProperty] private double _weightBefore;
@@ -121,6 +125,7 @@ namespace TabletTester2025.ViewModels
public IAsyncRelayCommand HardnessUpCommand { get; }
public IAsyncRelayCommand HardnessDownCommand { get; }
public IAsyncRelayCommand HardnessResetCommand { get; }
public IAsyncRelayCommand ClearHardnessRecordsCommand { get; }
public IAsyncRelayCommand HardnessForward { get; }//前进
public IAsyncRelayCommand HardnessBack { get; }//后退
@@ -201,6 +206,7 @@ namespace TabletTester2025.ViewModels
StartHardnessCommand = new AsyncRelayCommand(RunHardnessAsync);
StartFriabilityCommand = new AsyncRelayCommand(RunFriabilityAsync);
StartDisintegrationCommand = new AsyncRelayCommand(RunDisintegrationAsync);
ClearHardnessRecordsCommand = new AsyncRelayCommand(ClearHardnessRecordsAsync);
StartDissolutionCommand = new AsyncRelayCommand(StartDissolution1Async);
@@ -230,6 +236,7 @@ namespace TabletTester2025.ViewModels
DissolutionPlotModel.Series.Add(_dissolution1Series);
DissolutionPlotModel.Series.Add(_dissolution2Series);
StartHardnessLiveForcePolling();
HardnessDownCommand = new AsyncRelayCommand(async () =>
@@ -246,15 +253,6 @@ namespace TabletTester2025.ViewModels
await _plc.WriteCoilAsync(_plcConfig.HardnessStartReset, true);
await Task.Delay(100); // 脉冲宽度可根据PLC程序调整20~100ms
await _plc.WriteCoilAsync(_plcConfig.HardnessStartReset, false);
_hardnessResults.Clear();
HardnessSamplePoints.Clear();
HardnessCurrentCount = 0;
HardnessAvg = 0;
HardnessAverageDeviation = 0;
HardnessRSD = 0;
HardnessMax = 0;
HardnessMin= 0;
HardnessShishilizhi = 0;
Phase = TestPhase.Idle;
});
@@ -1289,11 +1287,54 @@ namespace TabletTester2025.ViewModels
await _plc.WriteCoilAsync(coilAddress, false);
}
private async Task RunHardnessAsync()
private void StartHardnessLiveForcePolling()
{
_hardnessGlobalTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(500) };
_hardnessGlobalTimer.Tick += async (_, _) =>
{
if (_isReadingHardnessLiveForce || Phase == TestPhase.Running)
return;
try
{
_isReadingHardnessLiveForce = true;
await ReadHardnessLiveForceAsync();
}
catch
{
// The footer connection status already reflects PLC availability; avoid popup noise during idle polling.
}
finally
{
_isReadingHardnessLiveForce = false;
}
};
_hardnessGlobalTimer.Start();
}
private Task ClearHardnessRecordsAsync()
{
if (Phase == TestPhase.Running && CurrentTest == TestType.Hardness)
{
MessageBox.Show("硬度测试运行中,不能清空记录。");
return Task.CompletedTask;
}
ResetCurrentHardnessGroup();
HardnessDisplaySamplePoints.Clear();
_hardnessGroupNo = 0;
_currentHardnessGroupNo = 0;
return Task.CompletedTask;
}
private void StartNewHardnessGroup()
{
_currentHardnessGroupNo = ++_hardnessGroupNo;
ResetCurrentHardnessGroup();
}
private void ResetCurrentHardnessGroup()
{
if (Phase != TestPhase.Idle) return;
CurrentTest = TestType.Hardness;
Phase = TestPhase.Running;
HardnessPass = false;
_hardnessResults.Clear();
HardnessSamplePoints.Clear();
@@ -1303,6 +1344,14 @@ namespace TabletTester2025.ViewModels
HardnessRSD = 0;
HardnessMax = 0;
HardnessMin = 0;
}
private async Task RunHardnessAsync()
{
if (Phase != TestPhase.Idle) return;
CurrentTest = TestType.Hardness;
Phase = TestPhase.Running;
StartNewHardnessGroup();
try
{
@@ -1313,8 +1362,8 @@ namespace TabletTester2025.ViewModels
throw new InvalidOperationException("硬度启动线圈未配置");
if (completeCoil == 0)
throw new InvalidOperationException("硬度完成线圈未配置");
if (_plcConfig.HardnessMax == 0)
throw new InvalidOperationException("硬度最大力寄存器未配置");
if (ResolveHardnessLiveForceRegister() == 0)
throw new InvalidOperationException("硬度实时力寄存器未配置");
await _plc.WriteFloatAsync(_plcConfig.HardnessSudu, (float)HardnessSudu);
await _plc.WriteFloatAsync(_plcConfig.HardnessWeiyi, (float)HardnessWeiyi);
@@ -1327,15 +1376,8 @@ namespace TabletTester2025.ViewModels
if (completeWasActiveBeforeStart)
await WaitForCoilStateAsync(completeCoil, false, TimeSpan.FromSeconds(10), "硬度完成信号未复位");
await WaitForCoilStateAsync(completeCoil, true, TimeSpan.FromSeconds(120), "等待硬度完成信号超时");
double value = await ReadHardnessResultAsync();
_hardnessResults.Add(value);
HardnessSamplePoints.Add(new HardnessSamplePoint
{
SequenceNo = _hardnessResults.Count,
Value = value,
RecordedAt = DateTime.Now
});
double value = await WaitForHardnessSamplePeakAsync(completeCoil);
AddHardnessSample(value);
ApplyHardnessStatistics(count);
await WaitForCoilStateAsync(completeCoil, false, TimeSpan.FromSeconds(10), "硬度完成信号未回落");
}
@@ -1375,17 +1417,77 @@ namespace TabletTester2025.ViewModels
: (ushort)70;
}
private async Task<double> ReadHardnessResultAsync()
private ushort ResolveHardnessLiveForceRegister()
{
double value = await _plc.ReadFloatAsync(_plcConfig.HardnessMax);
if (!double.IsFinite(value) || value <= 0)
throw new InvalidOperationException("硬度最大力数据异常");
return _plcConfig.HardnessShishilizhi != 0
? _plcConfig.HardnessShishilizhi
: (ushort)1314;
}
private async Task<double> ReadHardnessLiveForceAsync()
{
double value = await _plc.ReadFloatAsync(ResolveHardnessLiveForceRegister());
if (!double.IsFinite(value) || value < 0)
throw new InvalidOperationException("硬度实时力数据异常");
HardnessValue = value;
HardnessShishilizhi = value;
return value;
}
private async Task<double> WaitForHardnessSamplePeakAsync(ushort completeCoil)
{
double peak = 0;
DateTime deadline = DateTime.Now.AddSeconds(120);
while (Phase == TestPhase.Running && DateTime.Now <= deadline)
{
double liveForce = await ReadHardnessLiveForceAsync();
if (liveForce > peak)
peak = liveForce;
if (await _plc.ReadCoilAsync(completeCoil))
{
double finalForce = await ReadHardnessLiveForceAsync();
if (finalForce > peak)
peak = finalForce;
if (peak <= 0)
throw new InvalidOperationException("硬度实时力数据异常");
return peak;
}
await Task.Delay(100);
}
if (Phase != TestPhase.Running)
throw new InvalidOperationException("硬度测试已停止,未保存结果");
throw new TimeoutException("等待硬度完成信号超时");
}
private void AddHardnessSample(double value)
{
_hardnessResults.Add(value);
int sequenceNo = _hardnessResults.Count;
DateTime recordedAt = DateTime.Now;
HardnessValue = value;
HardnessSamplePoints.Add(new HardnessSamplePoint
{
SequenceNo = sequenceNo,
Value = value,
RecordedAt = recordedAt
});
HardnessDisplaySamplePoints.Add(new HardnessDisplaySamplePoint
{
GroupNo = _currentHardnessGroupNo,
SequenceNo = sequenceNo,
Value = value,
RecordedAt = recordedAt
});
}
private async Task WaitForCoilStateAsync(ushort coilAddress, bool expectedState, TimeSpan timeout, string timeoutMessage)
{
DateTime deadline = DateTime.Now.Add(timeout);
@@ -1421,6 +1523,9 @@ namespace TabletTester2025.ViewModels
foreach (var sample in HardnessSamplePoints)
sample.DeviationFromAverage = Math.Abs(sample.Value - stats.Average);
foreach (var sample in HardnessDisplaySamplePoints.Where(s => s.GroupNo == _currentHardnessGroupNo))
sample.DeviationFromAverage = Math.Abs(sample.Value - stats.Average);
}
/// 脆碎度测试主逻辑(实时状态显示)