This commit is contained in:
GukSang.Jin
2026-05-18 09:47:22 +08:00
parent 3db2f360b1
commit 175d0983d4
8 changed files with 197 additions and 13 deletions

View File

@@ -26,6 +26,8 @@ namespace TabletTester2025.ViewModels
private DispatcherTimer _disintegrationTimer;
private bool _isLoadingDissolution1Time;
private bool _isLoadingDissolution2Time;
private bool _isLoadingDissolution1SampleInterval;
private bool _isLoadingDissolution2SampleInterval;
private bool _isLoadingDisintegrationTime;
private bool _isLoadingDisintegrationSpeed;
@@ -41,6 +43,7 @@ namespace TabletTester2025.ViewModels
private bool _dissolution2SampleRequestActive;
private bool _isDissolution1SamplePromptOpen;
private bool _isDissolution2SamplePromptOpen;
private bool _discardDisintegrationResult;
private string _dissolutionResultChannel = "";
private double _dissolutionResultRate30Min;
private double _dissolutionResultRSquared;
@@ -110,6 +113,8 @@ namespace TabletTester2025.ViewModels
[ObservableProperty] private double _dissolutionTargetRpm = 50;
[ObservableProperty] private int _dissolution1TimeMin = 30;
[ObservableProperty] private int _dissolution2TimeMin = 30;
[ObservableProperty] private double _dissolution1SampleIntervalMin = 5;
[ObservableProperty] private double _dissolution2SampleIntervalMin = 5;
[ObservableProperty] private double _dissolutionElapsedTime;
[ObservableProperty] private double _dissolutionCountdown;
[ObservableProperty] private double _dissolutionRSquared;
@@ -123,14 +128,17 @@ namespace TabletTester2025.ViewModels
public IAsyncRelayCommand PrintDissolutionCommand { get; }
public IAsyncRelayCommand StartDissolution1Command { get; }
public IAsyncRelayCommand StopDissolution1Command { get; }
public IAsyncRelayCommand ResetDissolution1Command { get; }
public IAsyncRelayCommand StartDissolution2Command { get; }
public IAsyncRelayCommand StopDissolution2Command { get; }
public IAsyncRelayCommand ResetDissolution2Command { get; }
// 崩解新增
[ObservableProperty] private double _disintegrationTargetFreq = 31;
[ObservableProperty] private double _disintegrationSpeedRpm = 31;
[ObservableProperty] private double _disintegrationTimeMin = 15;
public IAsyncRelayCommand StopDisintegrationCommand { get; }
public IAsyncRelayCommand ResetDisintegrationCommand { get; }
public IAsyncRelayCommand PrintDisintegrationCommand { get; }
public PlotModel DissolutionPlotModel { get; }
@@ -254,13 +262,16 @@ namespace TabletTester2025.ViewModels
DissolutionDownCommand = new AsyncRelayCommand(async () => await _plc.WriteCoilAsync(0x23, true));
StartDissolution1Command = new AsyncRelayCommand(StartDissolution1Async);
StopDissolution1Command = new AsyncRelayCommand(StopDissolution1Async);
ResetDissolution1Command = new AsyncRelayCommand(ResetDissolution1Async);
StartDissolution2Command = new AsyncRelayCommand(StartDissolution2Async);
StopDissolution2Command = new AsyncRelayCommand(StopDissolution2Async);
ResetDissolution2Command = new AsyncRelayCommand(ResetDissolution2Async);
StopDissolutionCommand = new AsyncRelayCommand(StopDissolution1Async);
PrintDissolutionCommand = new AsyncRelayCommand(async () => await PrintReport("溶出度"));
// 崩解命令
StopDisintegrationCommand = new AsyncRelayCommand(StopDisintegrationAsync);
ResetDisintegrationCommand = new AsyncRelayCommand(ResetDisintegrationAsync);
PrintDisintegrationCommand = new AsyncRelayCommand(async () => await PrintReport("崩解"));
_ = LoadDisintegrationTimeAsync();
@@ -559,6 +570,23 @@ namespace TabletTester2025.ViewModels
_ = WriteDissolutionTimeAsync(_plcConfig.Dissolution2Time, value);
}
partial void OnDissolution1SampleIntervalMinChanged(double value)
{
if (_isLoadingDissolution1SampleInterval || _plcConfig.Dissolution1SampleInterval == 0 || value <= 0)
return;
_ = WriteDissolutionFloatAsync(_plcConfig.Dissolution1SampleInterval, value);
DissolutionSampleInterval = ToCompatibleSampleInterval(value);
}
partial void OnDissolution2SampleIntervalMinChanged(double value)
{
if (_isLoadingDissolution2SampleInterval || _plcConfig.Dissolution2SampleInterval == 0 || value <= 0)
return;
_ = WriteDissolutionFloatAsync(_plcConfig.Dissolution2SampleInterval, value);
}
private async Task LoadDissolutionTimesAsync()
{
if (_plcConfig.Dissolution1Time != 0)
@@ -592,6 +620,8 @@ namespace TabletTester2025.ViewModels
_isLoadingDissolution2Time = false;
}
}
await LoadDissolutionSampleIntervalsAsync();
}
private async Task WriteDissolutionTimeAsync(ushort registerAddress, int value)
@@ -606,6 +636,64 @@ namespace TabletTester2025.ViewModels
catch { }
}
private async Task LoadDissolutionSampleIntervalsAsync()
{
if (_plcConfig.Dissolution1SampleInterval != 0)
{
try
{
_isLoadingDissolution1SampleInterval = true;
float value = await _plc.ReadFloatAsync(_plcConfig.Dissolution1SampleInterval);
if (float.IsFinite(value) && value > 0)
{
Dissolution1SampleIntervalMin = value;
DissolutionSampleInterval = ToCompatibleSampleInterval(value);
}
}
catch { }
finally
{
_isLoadingDissolution1SampleInterval = false;
}
}
if (_plcConfig.Dissolution2SampleInterval != 0)
{
try
{
_isLoadingDissolution2SampleInterval = true;
float value = await _plc.ReadFloatAsync(_plcConfig.Dissolution2SampleInterval);
if (float.IsFinite(value) && value > 0)
Dissolution2SampleIntervalMin = value;
}
catch { }
finally
{
_isLoadingDissolution2SampleInterval = false;
}
}
}
private async Task WriteDissolutionFloatAsync(ushort registerAddress, double value)
{
if (registerAddress == 0 || value <= 0 || !double.IsFinite(value))
return;
try
{
await _plc.WriteFloatAsync(registerAddress, (float)value);
}
catch { }
}
private static int ToCompatibleSampleInterval(double value)
{
if (!double.IsFinite(value) || value <= 0)
return 0;
return (int)Math.Min(int.MaxValue, Math.Round(value, MidpointRounding.AwayFromZero));
}
partial void OnDisintegrationTimeMinChanged(double value)
{
if (_isLoadingDisintegrationTime || _plcConfig.DisintegrationTime == 0 || value <= 0)
@@ -885,9 +973,12 @@ namespace TabletTester2025.ViewModels
int maxSec = DisintegrationTimeMin > 0
? (int)Math.Ceiling(DisintegrationTimeMin * 60)
: App.CurrentPharmaParams.DisintegrationMaxSeconds;
DisintegrationPass = (RemainingTubes == 0 && DisintegrationSeconds <= maxSec);
DisintegrationPass = !_discardDisintegrationResult && RemainingTubes == 0 && DisintegrationSeconds <= maxSec;
await SaveBatchResult();
if (!_discardDisintegrationResult)
await SaveBatchResult();
_discardDisintegrationResult = false;
}
}
@@ -904,6 +995,29 @@ namespace TabletTester2025.ViewModels
}
}
private async Task ResetDisintegrationAsync()
{
bool wasRunning = CurrentTest == TestType.Disintegration && Phase == TestPhase.Running;
_discardDisintegrationResult = wasRunning;
try
{
await PulseCoilAsync(_plcConfig.DisintegrationResetCoil);
}
finally
{
_disintegrationTimer?.Stop();
TubesCompleted = new bool[6];
RemainingTubes = 6;
DisintegrationSeconds = 0;
DisintegrationPass = false;
Phase = TestPhase.Idle;
if (!wasRunning)
_discardDisintegrationResult = false;
}
}
private async Task StartDissolution1Async()
{
CurrentTest = TestType.Dissolution;
@@ -915,6 +1029,7 @@ namespace TabletTester2025.ViewModels
_isDissolution1Running = true;
DissolutionPlotModel.Title = "溶出曲线";
await WriteDissolutionTimeAsync(_plcConfig.Dissolution1Time, Dissolution1TimeMin);
await WriteDissolutionFloatAsync(_plcConfig.Dissolution1SampleInterval, Dissolution1SampleIntervalMin);
await PulseCoilAsync(_plcConfig.Dissolution1StartCoil);
}
@@ -934,6 +1049,22 @@ namespace TabletTester2025.ViewModels
}
}
private async Task ResetDissolution1Async()
{
try
{
await PulseCoilAsync(_plcConfig.Dissolution1ResetCoil);
}
finally
{
_isDissolution1Running = false;
ResetDissolutionChannel(1);
ResetDissolutionSampleState(1);
Phase = _isDissolution2Running ? TestPhase.Running : TestPhase.Idle;
UpdateDissolutionClock();
}
}
private async Task StartDissolution2Async()
{
if (_plcConfig.Dissolution2Percent == 0)
@@ -952,6 +1083,7 @@ namespace TabletTester2025.ViewModels
_isDissolution2Running = true;
DissolutionPlotModel.Title = "溶出曲线";
await WriteDissolutionTimeAsync(_plcConfig.Dissolution2Time, Dissolution2TimeMin);
await WriteDissolutionFloatAsync(_plcConfig.Dissolution2SampleInterval, Dissolution2SampleIntervalMin);
await PulseCoilAsync(_plcConfig.Dissolution2StartCoil);
}
@@ -971,6 +1103,22 @@ namespace TabletTester2025.ViewModels
}
}
private async Task ResetDissolution2Async()
{
try
{
await PulseCoilAsync(_plcConfig.Dissolution2ResetCoil);
}
finally
{
_isDissolution2Running = false;
ResetDissolutionChannel(2);
ResetDissolutionSampleState(2);
Phase = _isDissolution1Running ? TestPhase.Running : TestPhase.Idle;
UpdateDissolutionClock();
}
}
private void ResetDissolutionChannel(int channel)
{
if (channel == 1)
@@ -1096,7 +1244,11 @@ namespace TabletTester2025.ViewModels
DissolutionRate30Min = dissolutionRate30Min,
DissolutionTargetRpm = DissolutionTargetRpm,
DissolutionRSquared = rsquared,
DissolutionSampleInterval = DissolutionSampleInterval,
DissolutionSampleInterval = CurrentTest == TestType.Dissolution && _dissolutionResultChannel == "溶出2"
? ToCompatibleSampleInterval(Dissolution2SampleIntervalMin)
: ToCompatibleSampleInterval(Dissolution1SampleIntervalMin),
Dissolution1SampleInterval = Dissolution1SampleIntervalMin,
Dissolution2SampleInterval = Dissolution2SampleIntervalMin,
DissolutionUpDownFreq = DissolutionUpDownFreq,
HardnessPass = HardnessPass,
FriabilityPass = FriabilityPass,