This commit is contained in:
GukSang.Jin
2026-05-22 15:33:31 +08:00
parent e2ee1b2a2d
commit b009fabfdb

View File

@@ -13,12 +13,17 @@ public sealed class SmokeDensitySettingsViewModel : PageViewModel
private const ushort AbsorbanceRegister = 120;
private const double AbsorbanceMinimum = 0;
private const double AbsorbanceMaximum = 100;
private const double AbsorbanceStableTolerance = 0.25;
private const int AbsorbanceStableReadCount = 2;
private readonly Action _closeAction;
private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService;
private readonly DispatcherTimer _refreshTimer;
private readonly HashSet<ushort> _loggedFloatDiagnostics = [];
private readonly HashSet<ushort> _loggedInvalidFloatDiagnostics = [];
private double? _stableAbsorbance;
private double? _pendingAbsorbance;
private int _pendingAbsorbanceReadCount;
private string _absorbanceText = "";
private string _lastCalibration = "待校准";
@@ -90,34 +95,85 @@ public sealed class SmokeDensitySettingsViewModel : PageViewModel
private void RefreshDeviceValues()
{
AbsorbanceText = ReadRangedFloatText(
if (!TryReadRangedFloatValue(
"Absorbance",
AbsorbanceRegister,
AbsorbanceMinimum,
AbsorbanceMaximum,
"0.00");
out var value))
{
if (!_stableAbsorbance.HasValue)
{
AbsorbanceText = string.Empty;
}
return;
}
if (TryUpdateStableAbsorbance(value, out var stableValue))
{
AbsorbanceText = stableValue.ToString("0.00", CultureInfo.InvariantCulture);
}
}
private string ReadRangedFloatText(
private bool TryReadRangedFloatValue(
string label,
ushort registerAddress,
double minimum,
double maximum,
string format)
out double value)
{
value = double.NaN;
if (!_tcpDeviceConnectionService.TryReadFloatValues(registerAddress, out var result))
{
return string.Empty;
return false;
}
if (!ModbusFloatSelector.TrySelectRangedFloat(result, minimum, maximum, out var byteOrder, out var value, out var matchCount))
if (!ModbusFloatSelector.TrySelectRangedFloat(result, minimum, maximum, out var byteOrder, out var selectedValue, out var matchCount))
{
LogFloatDiagnostic(label, registerAddress, result, null, matchCount);
return string.Empty;
return false;
}
LogFloatDiagnostic(label, registerAddress, result, byteOrder, matchCount);
return NormalizeDisplayValue(value).ToString(format, CultureInfo.InvariantCulture);
value = NormalizeDisplayValue(selectedValue);
return true;
}
private bool TryUpdateStableAbsorbance(double value, out double stableValue)
{
stableValue = _stableAbsorbance ?? value;
if (_stableAbsorbance.HasValue
&& Math.Abs(value - _stableAbsorbance.Value) <= AbsorbanceStableTolerance)
{
_pendingAbsorbance = null;
_pendingAbsorbanceReadCount = 0;
stableValue = _stableAbsorbance.Value;
return true;
}
if (!_pendingAbsorbance.HasValue
|| Math.Abs(value - _pendingAbsorbance.Value) > AbsorbanceStableTolerance)
{
_pendingAbsorbance = value;
_pendingAbsorbanceReadCount = 1;
return false;
}
_pendingAbsorbanceReadCount++;
if (_pendingAbsorbanceReadCount < AbsorbanceStableReadCount)
{
return false;
}
_stableAbsorbance = value;
_pendingAbsorbance = null;
_pendingAbsorbanceReadCount = 0;
stableValue = value;
return true;
}
private void LogFloatDiagnostic(