2026-03-19 20:40:54 +08:00
|
|
|
|
using MembranePoreTester.Communication;
|
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.ComponentModel; // 用于 PropertyChanged
|
2026-03-26 19:43:52 +08:00
|
|
|
|
using System.Net;
|
2026-03-19 20:40:54 +08:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Input;
|
2026-04-09 10:49:28 +08:00
|
|
|
|
using System.Windows.Threading;
|
2026-03-26 19:43:52 +08:00
|
|
|
|
using static OfficeOpenXml.ExcelErrorValue;
|
2026-03-02 18:50:30 +08:00
|
|
|
|
|
|
|
|
|
|
namespace MembranePoreTester.ViewModels
|
|
|
|
|
|
{
|
|
|
|
|
|
public class MainViewModel : ViewModelBase
|
|
|
|
|
|
{
|
|
|
|
|
|
public ObservableCollection<StationItem> Stations { get; } = new();
|
2026-04-09 10:49:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 报警信息集合(用于显示多条)
|
|
|
|
|
|
private ObservableCollection<string> _alarmMessages;
|
|
|
|
|
|
public ObservableCollection<string> AlarmMessages
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _alarmMessages;
|
|
|
|
|
|
set => SetProperty(ref _alarmMessages, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _hasAlarm;
|
|
|
|
|
|
public bool HasAlarm
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _hasAlarm;
|
|
|
|
|
|
set => SetProperty(ref _hasAlarm, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _alarmText;
|
|
|
|
|
|
public string AlarmText
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _alarmText;
|
|
|
|
|
|
set => SetProperty(ref _alarmText, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private DispatcherTimer _alarmTimer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
public class PressureModeItem
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Text { get; set; }
|
|
|
|
|
|
public int Value { get; set; }
|
|
|
|
|
|
|
2026-03-02 18:50:30 +08:00
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
public override string ToString()
|
|
|
|
|
|
{
|
|
|
|
|
|
return Text; // 直接返回要显示的文本
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-19 20:40:54 +08:00
|
|
|
|
public class StationItem : ViewModelBase
|
|
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
private PressureModeItem _selectedPressureMode;
|
|
|
|
|
|
private List<PressureModeItem> _pressureModeList;
|
|
|
|
|
|
|
|
|
|
|
|
public List<PressureModeItem> PressureModeList => _pressureModeList ??= new List<PressureModeItem>
|
|
|
|
|
|
{
|
|
|
|
|
|
new PressureModeItem { Text = "低压", Value = 1 },
|
|
|
|
|
|
new PressureModeItem { Text = "高压", Value = 0 }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public PressureModeItem SelectedPressureMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _selectedPressureMode;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SetProperty(ref _selectedPressureMode, value))
|
|
|
|
|
|
{
|
|
|
|
|
|
Task.Run(async () => await WritePressureModeAsync(value?.Text ?? "低压"));
|
2026-04-16 13:09:01 +08:00
|
|
|
|
|
|
|
|
|
|
// 切换模式后调整加压上限
|
|
|
|
|
|
AdjustPressureLimitForMode();
|
2026-03-26 21:37:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
|
|
|
|
|
|
private PressureModeItem _selectedInTakeMode;
|
|
|
|
|
|
private List<PressureModeItem> _inTakeModeList;
|
|
|
|
|
|
|
|
|
|
|
|
public List<PressureModeItem> InTakeModeList => _inTakeModeList ??= new List<PressureModeItem>
|
|
|
|
|
|
{
|
|
|
|
|
|
new PressureModeItem { Text = "底部进气", Value = 0 },
|
2026-04-14 17:30:52 +08:00
|
|
|
|
//new PressureModeItem { Text = "顶部进气", Value = 1 }
|
2026-04-09 21:43:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public PressureModeItem SelecteInTakeMode
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _selectedInTakeMode;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SetProperty(ref _selectedInTakeMode, value))
|
|
|
|
|
|
{
|
|
|
|
|
|
Task.Run(async () => await WriteInTakeModeAsync(value?.Text ?? "底部进气"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
private readonly IPlcService _plcService;
|
|
|
|
|
|
private readonly PlcConfiguration _plcConfig;
|
|
|
|
|
|
private bool _isPressing;
|
|
|
|
|
|
private string _pressButtonText = "加压";
|
|
|
|
|
|
private string _highLowPressure = "低压";
|
|
|
|
|
|
private bool _enableStatus; // M21 状态
|
|
|
|
|
|
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
public BubblePointViewModel BubblePointVM { get; set; }
|
|
|
|
|
|
public PoreDistributionViewModel PoreDistributionVM { get; set; }
|
|
|
|
|
|
public int StationId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string HighLowPressure
|
|
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
get => _selectedPressureMode?.Text ?? "低压";
|
2026-03-19 20:40:54 +08:00
|
|
|
|
set
|
|
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
var mode = PressureModeList.FirstOrDefault(m => m.Text == value);
|
|
|
|
|
|
if (mode != null)
|
2026-03-19 20:40:54 +08:00
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
SelectedPressureMode = mode;
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
public string UpAndDown
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _selectedInTakeMode?.Text ?? "底部";
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
var mode = InTakeModeList.FirstOrDefault(m => m.Text == value);
|
|
|
|
|
|
if (mode != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
SelecteInTakeMode = mode;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
public string PressButtonText
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _pressButtonText;
|
|
|
|
|
|
set => SetProperty(ref _pressButtonText, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 18:06:10 +08:00
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
public bool EnableStatus
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _enableStatus;
|
2026-03-26 21:37:34 +08:00
|
|
|
|
private set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SetProperty(ref _enableStatus, value))
|
|
|
|
|
|
{
|
2026-04-02 18:06:10 +08:00
|
|
|
|
// 当设备停止运行时,停止孔分布自动采集
|
|
|
|
|
|
if (!value)
|
|
|
|
|
|
{
|
|
|
|
|
|
PoreDistributionVM?.StopCollecting();
|
|
|
|
|
|
}
|
2026-03-26 21:37:34 +08:00
|
|
|
|
OnPropertyChanged(nameof(EnableStatusText));
|
|
|
|
|
|
OnPropertyChanged(nameof(EnableStatusColor));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
2026-04-02 18:06:10 +08:00
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
// 使能状态显示文本
|
|
|
|
|
|
public string EnableStatusText => EnableStatus ? "运行中" : "未启动";
|
|
|
|
|
|
|
|
|
|
|
|
// 使能状态显示颜色(绿色表示运行中,灰色表示未启动)
|
2026-03-26 21:37:34 +08:00
|
|
|
|
// 使能状态显示颜色(更亮的颜色)
|
|
|
|
|
|
public string EnableStatusColor => EnableStatus ? "#00FF00" : "#FF3333";
|
2026-03-19 20:40:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 定时器,用于轮询 M21 状态
|
|
|
|
|
|
private System.Windows.Threading.DispatcherTimer _timer;
|
|
|
|
|
|
|
|
|
|
|
|
public ICommand PressCommand { get; }
|
|
|
|
|
|
//public ICommand BurstCommand { get; }
|
|
|
|
|
|
public ICommand StartCommand { get; }
|
|
|
|
|
|
public ICommand StopCommand { get; }
|
|
|
|
|
|
public ICommand EnableCommand { get; } // 备用,但可以使用复选框直接绑定
|
|
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-02 10:13:01 +08:00
|
|
|
|
|
|
|
|
|
|
private double _pressureUpperLimit;
|
|
|
|
|
|
private double _pressureRate;
|
2026-04-02 18:06:10 +08:00
|
|
|
|
// 防止从PLC读取时触发校验弹窗
|
|
|
|
|
|
private bool _suppressPressureValidation = false;
|
2026-04-02 10:13:01 +08:00
|
|
|
|
|
|
|
|
|
|
public double PressureUpperLimit
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _pressureUpperLimit;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
2026-04-02 18:06:10 +08:00
|
|
|
|
// 如果不是从PLC读取(即用户交互或程序主动设置),先校验再设置
|
|
|
|
|
|
if (!_suppressPressureValidation && HighLowPressure.Contains("低压") && value > 200)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("低压模式,加压上限不能超过200!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-04-15 12:27:58 +08:00
|
|
|
|
if (!_suppressPressureValidation && HighLowPressure.Contains("高压") && value > 1000)
|
2026-04-14 21:40:09 +08:00
|
|
|
|
{
|
2026-04-15 12:27:58 +08:00
|
|
|
|
MessageBox.Show("高压模式,加压上限不能超过1000!");
|
2026-04-14 21:40:09 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-04-02 18:06:10 +08:00
|
|
|
|
|
|
|
|
|
|
bool changed = SetProperty(ref _pressureUpperLimit, value);
|
|
|
|
|
|
// 仅在非抑制模式下将改变写回PLC,避免把PLC读回的值再次写入造成循环
|
|
|
|
|
|
if (changed && !_suppressPressureValidation)
|
2026-04-02 10:13:01 +08:00
|
|
|
|
{
|
2026-04-09 21:43:30 +08:00
|
|
|
|
ushort address = StationId == 1 ? _plcConfig.PressureUpperLimit
|
|
|
|
|
|
: StationId == 2 ? _plcConfig.PressureUpperLimit2
|
|
|
|
|
|
: _plcConfig.PressureUpperLimit3;
|
|
|
|
|
|
_ = _plcService.WriteMultipleRegistersAsync(address, (float)value);
|
2026-04-02 10:13:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public double PressureRate
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _pressureRate;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SetProperty(ref _pressureRate, value))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 值改变时写入PLC
|
2026-04-09 21:43:30 +08:00
|
|
|
|
_ = _plcService.WriteMultipleRegistersAsync(StationId == 1 ? _plcConfig.PressureRate : StationId == 2 ? _plcConfig.PressureRate2 : _plcConfig.PressureRate3, (float)value);
|
2026-04-02 10:13:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加读取这两个参数的方法
|
|
|
|
|
|
private async Task ReadPressureParametersAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-04-09 21:43:30 +08:00
|
|
|
|
// 根据工位选择加压上限的PLC地址
|
|
|
|
|
|
ushort upperLimitAddress = StationId == 1 ? _plcConfig.PressureUpperLimit
|
|
|
|
|
|
: StationId == 2 ? _plcConfig.PressureUpperLimit2
|
|
|
|
|
|
: _plcConfig.PressureUpperLimit3;
|
|
|
|
|
|
|
|
|
|
|
|
float upperLimit = await _plcService.ReadFloatAsync(upperLimitAddress);
|
|
|
|
|
|
float rate = await _plcService.ReadFloatAsync(StationId == 1 ? _plcConfig.PressureRate : StationId == 2 ? _plcConfig.PressureRate2 : _plcConfig.PressureRate3);
|
2026-04-02 10:13:01 +08:00
|
|
|
|
|
2026-04-02 14:34:29 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-02 10:13:01 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
2026-04-02 18:06:10 +08:00
|
|
|
|
// 在将PLC读取的值赋回到属性时,抑制用户校验提示和避免回写PLC
|
|
|
|
|
|
_suppressPressureValidation = true;
|
2026-04-02 10:13:01 +08:00
|
|
|
|
PressureUpperLimit = upperLimit;
|
|
|
|
|
|
PressureRate = rate;
|
2026-04-02 18:06:10 +08:00
|
|
|
|
_suppressPressureValidation = false;
|
2026-04-02 10:13:01 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"读取压力参数失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
public StationItem()
|
|
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
if (IsInDesignMode())
|
|
|
|
|
|
{
|
|
|
|
|
|
return; // 设计时跳过PLC初始化
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
_plcService = App.PlcService;
|
|
|
|
|
|
_plcConfig = App.PlcConfig;
|
|
|
|
|
|
|
|
|
|
|
|
PressCommand = new RelayCommand(async () => await TogglePressAsync());
|
2026-03-27 21:35:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 在 StationItem 构造函数中
|
|
|
|
|
|
StartCommand = new RelayCommand(async () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 启动PLC
|
2026-04-09 21:43:30 +08:00
|
|
|
|
await WriteCoilAsync(StationId == 1 ? _plcConfig.StartCoil : StationId == 2 ? _plcConfig.StartCoil2 : _plcConfig.StartCoil3, true);
|
2026-03-27 21:35:32 +08:00
|
|
|
|
|
|
|
|
|
|
// 启动孔分布自动采集
|
|
|
|
|
|
PoreDistributionVM.StartCollecting();
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
StopCommand = new RelayCommand(async () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 停止自动采集
|
|
|
|
|
|
PoreDistributionVM.StopCollecting();
|
|
|
|
|
|
// 停止PLC
|
2026-04-09 21:43:30 +08:00
|
|
|
|
await WriteCoilAsync(StationId == 1 ? _plcConfig.StopCoil : StationId == 2 ? _plcConfig.StopCoil2 : _plcConfig.StopCoil3, true);
|
2026-03-27 21:35:32 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
// 启动定时器,每秒读取一次 M21 状态
|
|
|
|
|
|
_timer = new System.Windows.Threading.DispatcherTimer();
|
|
|
|
|
|
_timer.Interval = TimeSpan.FromSeconds(1);
|
2026-04-02 14:34:29 +08:00
|
|
|
|
_timer.Tick += async (s, e) =>
|
2026-04-02 10:13:01 +08:00
|
|
|
|
{
|
|
|
|
|
|
await ReadEnableStatusAsync();
|
|
|
|
|
|
await ReadPressureParametersAsync(); // 新增:读取压力参数
|
|
|
|
|
|
};
|
2026-03-19 20:40:54 +08:00
|
|
|
|
_timer.Start();
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 延迟2秒后读取,确保连接稳定
|
|
|
|
|
|
Task.Delay(2000).ContinueWith(async _ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
await ReadPressureModeAsync();
|
2026-04-02 10:13:01 +08:00
|
|
|
|
await ReadPressureParametersAsync(); // 新增:读取压力参数
|
2026-04-09 21:43:30 +08:00
|
|
|
|
await ReadInTakeModeAsync();
|
2026-04-02 10:13:01 +08:00
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
}, TaskScheduler.Default);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
private async Task ReadPressureModeAsync()
|
|
|
|
|
|
{
|
2026-03-28 16:48:41 +08:00
|
|
|
|
await SafeExecuteAsync($"ReadPressureModeAsync{StationId}", async () =>
|
2026-03-26 21:37:34 +08:00
|
|
|
|
{
|
2026-03-28 16:48:41 +08:00
|
|
|
|
try
|
2026-03-26 21:37:34 +08:00
|
|
|
|
{
|
2026-04-10 09:22:10 +08:00
|
|
|
|
ushort[] values = await _plcService.ReadHoldingRegistersAsync(StationId == 1 ? _plcConfig.PressureModeRegister : StationId == 2 ? _plcConfig.PressureModeRegister2 : _plcConfig.PressureModeRegister3, 1);
|
2026-03-28 16:48:41 +08:00
|
|
|
|
ushort val = values[0];
|
|
|
|
|
|
string newValue = val == 0 ? "高压" : "低压";
|
|
|
|
|
|
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更新选中项
|
|
|
|
|
|
HighLowPressure = newValue;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"读取压力模式失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
private async Task ReadInTakeModeAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
await SafeExecuteAsync($"ReadInTakeModeAsync{StationId}", async () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort address = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (StationId == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ushort[] values = await _plcService.ReadHoldingRegistersAsync(address, 1);
|
|
|
|
|
|
ushort val = values[0];
|
|
|
|
|
|
string newValue = val == 0 ? "底部进气" : "顶部进气";
|
|
|
|
|
|
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更新选中项
|
|
|
|
|
|
UpAndDown = newValue;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"读取出口模式失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
private async Task TogglePressAsync()
|
|
|
|
|
|
{
|
2026-03-26 21:37:34 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-04-07 21:10:37 +08:00
|
|
|
|
ushort coilAddress = _plcConfig.PressCoil; // 根据工位选择不同的线圈地址
|
|
|
|
|
|
switch (StationId)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
coilAddress = _plcConfig.PressCoil;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
coilAddress = _plcConfig.PressCoil2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
coilAddress = _plcConfig.PressCoil3;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
// 先读取PLC当前的加压状态
|
2026-04-07 21:10:37 +08:00
|
|
|
|
bool currentStatus = await _plcService.ReadCoilAsync(coilAddress);
|
2026-03-19 20:40:54 +08:00
|
|
|
|
|
2026-03-26 21:37:34 +08:00
|
|
|
|
// 切换状态
|
|
|
|
|
|
_isPressing = !currentStatus;
|
|
|
|
|
|
|
|
|
|
|
|
// 写入新状态到PLC
|
2026-04-07 21:10:37 +08:00
|
|
|
|
await WriteCoilAsync(coilAddress, _isPressing);
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新按钮文字
|
|
|
|
|
|
PressButtonText = _isPressing ? "停止加压" : "加压";
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"读取加压状态失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-28 16:48:41 +08:00
|
|
|
|
// 在 StationItem 类中添加字段
|
|
|
|
|
|
private bool _lastEnableReadFailed = false;
|
|
|
|
|
|
private DateTime _lastEnableErrorTime = DateTime.MinValue;
|
2026-03-19 20:40:54 +08:00
|
|
|
|
private async Task ReadEnableStatusAsync()
|
|
|
|
|
|
{
|
2026-03-28 16:48:41 +08:00
|
|
|
|
await SafeExecuteAsync($"ReadEnableStatus_Station{StationId}", async () =>
|
2026-03-19 20:40:54 +08:00
|
|
|
|
{
|
2026-03-28 16:48:41 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-04-09 21:43:30 +08:00
|
|
|
|
bool status = await _plcService.ReadCoilAsync(StationId == 1 ? _plcConfig.EnableCoil : StationId == 2 ? _plcConfig.EnableCoil2 : _plcConfig.EnableCoil3); // 读取 M21
|
2026-03-28 16:48:41 +08:00
|
|
|
|
EnableStatus = status;
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
bool pressStatus = await _plcService.ReadCoilAsync(StationId == 1 ? _plcConfig.PressCoil : StationId == 2 ? _plcConfig.PressCoil2 : _plcConfig.PressCoil3);//这里也要更新加压的按钮状态
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
2026-03-28 16:48:41 +08:00
|
|
|
|
_isPressing = pressStatus;
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
2026-03-28 16:48:41 +08:00
|
|
|
|
// 在UI线程更新按钮文字
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
PressButtonText = pressStatus ? "停止加压" : "加压";
|
|
|
|
|
|
});
|
2026-03-26 21:37:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-28 16:48:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 读取出错时保持原状态或显示错误
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"读取使能状态失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task WriteCoilAsync(ushort coil, bool value)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await _plcService.WriteCoilAsync(coil, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"写线圈失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task WritePressureModeAsync(string mode)
|
|
|
|
|
|
{
|
2026-03-26 19:43:52 +08:00
|
|
|
|
if (IsDisposed) return;
|
|
|
|
|
|
|
|
|
|
|
|
ushort val = mode.ToString().Contains("高压") ? (ushort)0 : (ushort)1;
|
2026-03-19 20:40:54 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-04-10 09:22:10 +08:00
|
|
|
|
if (StationId == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _plcService.WriteSingleRegisterAsync(_plcConfig.PressureModeRegister, val);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _plcService.WriteSingleRegisterAsync(_plcConfig.PressureModeRegister2, val);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _plcService.WriteSingleRegisterAsync(_plcConfig.PressureModeRegister3, val);
|
|
|
|
|
|
}
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"写压力模式失败: {ex.Message}");
|
|
|
|
|
|
}
|
2026-03-26 19:43:52 +08:00
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
2026-03-24 19:33:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
private async Task WriteInTakeModeAsync(string mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsDisposed) return;
|
|
|
|
|
|
|
|
|
|
|
|
ushort val = mode.ToString().Contains("底部") ? (ushort)0 : (ushort)1;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort address = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (StationId == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown2;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (StationId == 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
address = _plcConfig.UpAndDown3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await _plcService.WriteSingleRegisterAsync(address, val);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"写出口模式失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-27 21:35:32 +08:00
|
|
|
|
private bool _isPoreDistributionActive;
|
|
|
|
|
|
public bool IsPoreDistributionActive
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _isPoreDistributionActive;
|
|
|
|
|
|
set => SetProperty(ref _isPoreDistributionActive, value);
|
|
|
|
|
|
}
|
2026-03-24 19:33:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-16 13:09:01 +08:00
|
|
|
|
// 在 StationItem 类中添加以下方法
|
|
|
|
|
|
private void AdjustPressureLimitForMode()
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isLowPressure = (SelectedPressureMode?.Text == "低压");
|
|
|
|
|
|
double currentLimit = _pressureUpperLimit;
|
|
|
|
|
|
double newLimit = currentLimit;
|
|
|
|
|
|
|
|
|
|
|
|
if (isLowPressure && currentLimit > 200)
|
|
|
|
|
|
newLimit = 200;
|
|
|
|
|
|
else if (!isLowPressure && currentLimit > 1000)
|
|
|
|
|
|
newLimit = 1000;
|
|
|
|
|
|
else
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 直接修改字段,避免触发 setter 中的校验和重复写 PLC
|
|
|
|
|
|
_pressureUpperLimit = newLimit;
|
|
|
|
|
|
OnPropertyChanged(nameof(PressureUpperLimit));
|
|
|
|
|
|
|
|
|
|
|
|
// 写回 PLC
|
|
|
|
|
|
ushort address = StationId == 1 ? _plcConfig.PressureUpperLimit
|
|
|
|
|
|
: StationId == 2 ? _plcConfig.PressureUpperLimit2
|
|
|
|
|
|
: _plcConfig.PressureUpperLimit3;
|
|
|
|
|
|
_ = _plcService.WriteMultipleRegistersAsync(address, (float)newLimit);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-19 20:40:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-24 19:33:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-02 18:50:30 +08:00
|
|
|
|
public MainViewModel()
|
|
|
|
|
|
{
|
2026-03-28 16:48:41 +08:00
|
|
|
|
for (int i = 1; i <= 3; i++)
|
2026-03-02 18:50:30 +08:00
|
|
|
|
{
|
2026-03-19 20:40:54 +08:00
|
|
|
|
var station = new StationItem
|
2026-03-02 18:50:30 +08:00
|
|
|
|
{
|
|
|
|
|
|
Name = $"工位 {i}",
|
2026-04-09 21:43:30 +08:00
|
|
|
|
BubblePointVM = new BubblePointViewModel(),
|
|
|
|
|
|
PoreDistributionVM = new PoreDistributionViewModel(),
|
2026-03-19 20:40:54 +08:00
|
|
|
|
StationId = i
|
|
|
|
|
|
};
|
2026-04-09 21:43:30 +08:00
|
|
|
|
// 在构造完成后显式传入 StationId 以初始化 VM
|
|
|
|
|
|
station.BubblePointVM.Initialize(i);
|
|
|
|
|
|
station.PoreDistributionVM.Initialize(i);
|
2026-03-19 20:40:54 +08:00
|
|
|
|
Stations.Add(station);
|
2026-03-02 18:50:30 +08:00
|
|
|
|
}
|
2026-04-09 10:49:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AlarmMessages = new ObservableCollection<string>();
|
|
|
|
|
|
|
|
|
|
|
|
_alarmTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
|
|
|
|
|
_alarmTimer.Tick += async (s, e) => await RefreshAlarms();
|
|
|
|
|
|
_alarmTimer.Start();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async Task RefreshAlarms()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var plc = App.PlcService;
|
|
|
|
|
|
var config = App.PlcConfig;
|
|
|
|
|
|
|
|
|
|
|
|
// 读取4个报警线圈状态
|
|
|
|
|
|
bool smallFlowAlarm = await plc.ReadCoilAsync(config.SmallFlowAlarm);
|
|
|
|
|
|
bool bigFlowAlarm = await plc.ReadCoilAsync(config.BigFlowAlarm);
|
|
|
|
|
|
bool highPressAlarm = await plc.ReadCoilAsync(config.HighPressAlarm);
|
|
|
|
|
|
bool lowPressAlarm = await plc.ReadCoilAsync(config.LowPressAlarm);
|
|
|
|
|
|
|
2026-04-09 21:43:30 +08:00
|
|
|
|
|
|
|
|
|
|
bool Midnight1 = await plc.ReadCoilAsync(config.Midnight1);
|
|
|
|
|
|
bool Midnight2 = await plc.ReadCoilAsync(config.Midnight2);
|
|
|
|
|
|
bool Midnight3 = await plc.ReadCoilAsync(config.Midnight3);
|
|
|
|
|
|
|
2026-04-09 10:49:28 +08:00
|
|
|
|
// 收集当前报警信息
|
|
|
|
|
|
var newAlarms = new List<string>();
|
|
|
|
|
|
if (smallFlowAlarm) newAlarms.Add("小流量计报警");
|
|
|
|
|
|
if (bigFlowAlarm) newAlarms.Add("大流量报警");
|
|
|
|
|
|
if (highPressAlarm) newAlarms.Add("高压超限");
|
|
|
|
|
|
if (lowPressAlarm) newAlarms.Add("低压超限");
|
|
|
|
|
|
|
2026-04-10 18:54:06 +08:00
|
|
|
|
if (Midnight1) newAlarms.Add("1工位漏液");
|
|
|
|
|
|
if (Midnight2) newAlarms.Add("2工位漏液");
|
|
|
|
|
|
if (Midnight3) newAlarms.Add("3工位漏液");
|
2026-04-09 21:43:30 +08:00
|
|
|
|
|
2026-04-09 10:49:28 +08:00
|
|
|
|
// 更新UI(避免频繁刷新集合导致界面闪烁,直接替换内容)
|
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
AlarmMessages.Clear();
|
|
|
|
|
|
foreach (var msg in newAlarms)
|
|
|
|
|
|
AlarmMessages.Add(msg);
|
|
|
|
|
|
|
|
|
|
|
|
HasAlarm = newAlarms.Any();
|
|
|
|
|
|
AlarmText = HasAlarm ? string.Join(";", newAlarms) : "";
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.Diagnostics.Debug.WriteLine($"读取报警状态失败: {ex.Message}");
|
|
|
|
|
|
}
|
2026-03-02 18:50:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|