281 lines
8.5 KiB
C#
281 lines
8.5 KiB
C#
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Windows.Threading;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using ConeCalorimeter.Services;
|
|
|
|
namespace ConeCalorimeter.ViewModels;
|
|
|
|
public sealed class ConeRadiationSettingsViewModel : PageViewModel
|
|
{
|
|
private const ushort CurrentTemperatureRegister = 26;
|
|
private const ushort TargetTemperatureRegister = 400;
|
|
private const ushort CurrentHeatFluxRegister = 32;
|
|
private const ushort SlopeRegister = 420;
|
|
private const ushort InterceptRegister = 422;
|
|
private const ushort AlarmCoil = 91;
|
|
private const ushort CirculatingWaterCoil = 49;
|
|
private const string CirculatingWaterAction = "循环水";
|
|
|
|
private readonly Action _closeAction;
|
|
private readonly Action _helpAction;
|
|
private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService;
|
|
private readonly DispatcherTimer _refreshTimer;
|
|
private string _currentTemperatureText = "";
|
|
private string _currentHeatFluxText = "";
|
|
private string _targetTemperatureText = "";
|
|
private string _heatTransferText = "";
|
|
private string _slopeText = "";
|
|
private string _interceptText = "";
|
|
private string _lastAction = "待机";
|
|
private bool _alarmActive;
|
|
private bool _circulatingWaterActive;
|
|
private bool _isEditingConeParameters;
|
|
|
|
public ConeRadiationSettingsViewModel(
|
|
Action closeAction,
|
|
Action helpAction,
|
|
ITcpDeviceConnectionService tcpDeviceConnectionService) : base("辐射锥设置")
|
|
{
|
|
_closeAction = closeAction;
|
|
_helpAction = helpAction;
|
|
_tcpDeviceConnectionService = tcpDeviceConnectionService;
|
|
CloseCommand = new RelayCommand(_closeAction);
|
|
HelpCommand = new RelayCommand(_helpAction);
|
|
ActionCommand = new RelayCommand<string>(ExecuteAction);
|
|
SaveParametersCommand = new RelayCommand(SaveParameters);
|
|
|
|
RefreshDeviceValues();
|
|
_refreshTimer = new DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
};
|
|
_refreshTimer.Tick += (_, _) => RefreshDeviceValues();
|
|
_refreshTimer.Start();
|
|
}
|
|
|
|
public IRelayCommand CloseCommand { get; }
|
|
|
|
public IRelayCommand HelpCommand { get; }
|
|
|
|
public IRelayCommand<string> ActionCommand { get; }
|
|
|
|
public IRelayCommand SaveParametersCommand { get; }
|
|
|
|
public string CurrentTemperatureText
|
|
{
|
|
get => _currentTemperatureText;
|
|
private set => SetProperty(ref _currentTemperatureText, value);
|
|
}
|
|
|
|
public string CurrentHeatFluxText
|
|
{
|
|
get => _currentHeatFluxText;
|
|
private set => SetProperty(ref _currentHeatFluxText, value);
|
|
}
|
|
|
|
public string TargetTemperatureText
|
|
{
|
|
get => _targetTemperatureText;
|
|
set => SetProperty(ref _targetTemperatureText, value);
|
|
}
|
|
|
|
public string HeatTransferText
|
|
{
|
|
get => _heatTransferText;
|
|
set => SetProperty(ref _heatTransferText, value);
|
|
}
|
|
|
|
public string SlopeText
|
|
{
|
|
get => _slopeText;
|
|
set => SetProperty(ref _slopeText, value);
|
|
}
|
|
|
|
public string InterceptText
|
|
{
|
|
get => _interceptText;
|
|
set => SetProperty(ref _interceptText, value);
|
|
}
|
|
|
|
public string LastAction
|
|
{
|
|
get => _lastAction;
|
|
private set => SetProperty(ref _lastAction, value);
|
|
}
|
|
|
|
public bool AlarmActive
|
|
{
|
|
get => _alarmActive;
|
|
private set => SetProperty(ref _alarmActive, value);
|
|
}
|
|
|
|
public bool CirculatingWaterActive
|
|
{
|
|
get => _circulatingWaterActive;
|
|
private set
|
|
{
|
|
if (SetProperty(ref _circulatingWaterActive, value))
|
|
{
|
|
OnPropertyChanged(nameof(CirculatingWaterButtonText));
|
|
}
|
|
}
|
|
}
|
|
|
|
public string CirculatingWaterButtonText => CirculatingWaterActive ? "循环水:开启" : "循环水:关闭";
|
|
|
|
public void BeginConeParameterEdit()
|
|
{
|
|
_isEditingConeParameters = true;
|
|
}
|
|
|
|
public void EndConeParameterEdit()
|
|
{
|
|
_isEditingConeParameters = false;
|
|
}
|
|
|
|
private void ExecuteAction(string? action)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(action))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LastAction = action;
|
|
|
|
if (action == CirculatingWaterAction)
|
|
{
|
|
ToggleCirculatingWater();
|
|
return;
|
|
}
|
|
|
|
if (action == "开始升温")
|
|
{
|
|
WriteTargetTemperature();
|
|
WriteActionCoil(action);
|
|
return;
|
|
}
|
|
|
|
WriteActionCoil(action);
|
|
}
|
|
|
|
private void RefreshDeviceValues()
|
|
{
|
|
CurrentTemperatureText = ReadFloatText(CurrentTemperatureRegister);
|
|
CurrentHeatFluxText = ReadFloatText(CurrentHeatFluxRegister);
|
|
if (!_isEditingConeParameters)
|
|
{
|
|
SlopeText = ReadFloatText(SlopeRegister);
|
|
InterceptText = ReadFloatText(InterceptRegister);
|
|
}
|
|
|
|
AlarmActive = _tcpDeviceConnectionService.TryReadCoil(AlarmCoil, out var alarmActive) && alarmActive;
|
|
if (_tcpDeviceConnectionService.TryReadCoil(CirculatingWaterCoil, out var circulatingWaterActive))
|
|
{
|
|
CirculatingWaterActive = circulatingWaterActive;
|
|
}
|
|
}
|
|
|
|
private string ReadFloatText(ushort registerAddress)
|
|
{
|
|
return _tcpDeviceConnectionService.TryReadFloat(registerAddress, out var value)
|
|
? value.ToString("0.00", CultureInfo.InvariantCulture)
|
|
: string.Empty;
|
|
}
|
|
|
|
private void WriteTargetTemperature()
|
|
{
|
|
if (!short.TryParse(TargetTemperatureText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
|
|
{
|
|
Debug.WriteLine($"Invalid cone radiation target temperature: {TargetTemperatureText}");
|
|
return;
|
|
}
|
|
|
|
if (!_tcpDeviceConnectionService.TryWriteInt16(TargetTemperatureRegister, value))
|
|
{
|
|
LastAction = "设置辐射温度失败";
|
|
Debug.WriteLine("Cone radiation target temperature write failed.");
|
|
}
|
|
}
|
|
|
|
private void SaveParameters()
|
|
{
|
|
if (!float.TryParse(SlopeText, NumberStyles.Float, CultureInfo.InvariantCulture, out var slope))
|
|
{
|
|
LastAction = "斜率输入无效";
|
|
Debug.WriteLine($"Invalid cone radiation slope: {SlopeText}");
|
|
return;
|
|
}
|
|
|
|
if (!float.TryParse(InterceptText, NumberStyles.Float, CultureInfo.InvariantCulture, out var intercept))
|
|
{
|
|
LastAction = "截距输入无效";
|
|
Debug.WriteLine($"Invalid cone radiation intercept: {InterceptText}");
|
|
return;
|
|
}
|
|
|
|
var slopeWritten = _tcpDeviceConnectionService.TryWriteFloat(SlopeRegister, slope);
|
|
var interceptWritten = _tcpDeviceConnectionService.TryWriteFloat(InterceptRegister, intercept);
|
|
|
|
if (slopeWritten && interceptWritten)
|
|
{
|
|
LastAction = "参数保存成功";
|
|
return;
|
|
}
|
|
|
|
LastAction = "参数保存失败";
|
|
Debug.WriteLine($"Cone radiation parameters write failed. Slope: {slopeWritten}, intercept: {interceptWritten}.");
|
|
}
|
|
|
|
private void ToggleCirculatingWater()
|
|
{
|
|
if (!_tcpDeviceConnectionService.TryReadCoil(CirculatingWaterCoil, out var isActive))
|
|
{
|
|
LastAction = "循环水状态读取失败";
|
|
Debug.WriteLine("Cone radiation circulating water state read failed.");
|
|
return;
|
|
}
|
|
|
|
var nextValue = !isActive;
|
|
if (_tcpDeviceConnectionService.TryWriteCoil(CirculatingWaterCoil, nextValue))
|
|
{
|
|
CirculatingWaterActive = nextValue;
|
|
LastAction = $"循环水{(nextValue ? "开启" : "关闭")}";
|
|
return;
|
|
}
|
|
|
|
LastAction = $"循环水{(nextValue ? "开启" : "关闭")}失败";
|
|
Debug.WriteLine("Cone radiation circulating water write failed.");
|
|
}
|
|
|
|
private void WriteActionCoil(string action)
|
|
{
|
|
if (!TryGetActionCoil(action, out var coilAddress))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!_tcpDeviceConnectionService.TryWriteCoil(coilAddress, true))
|
|
{
|
|
LastAction = $"{action}失败";
|
|
Debug.WriteLine($"Cone radiation action '{action}' write failed.");
|
|
}
|
|
}
|
|
|
|
private static bool TryGetActionCoil(string action, out ushort coilAddress)
|
|
{
|
|
switch (action)
|
|
{
|
|
case "开始升温":
|
|
coilAddress = 100;
|
|
return true;
|
|
case "停止升温":
|
|
coilAddress = 101;
|
|
return true;
|
|
default:
|
|
coilAddress = 0;
|
|
return false;
|
|
}
|
|
}
|
|
}
|