Files
pamhagen-sysctrl/PamhagenSysCtrl/Helpers/PamhagenPlant.cs
T
2026-07-07 13:56:57 +02:00

172 lines
7.2 KiB
C#

using System.Windows;
namespace PamhagenSysCtrl.Helpers {
public class PamhagenPlant : IDisposable {
protected PamhagenPlc Plc;
protected bool IsRunning = true;
protected Thread? BackgroundThread;
public event EventHandler<EventArgs>? Update;
protected bool ActuatorsChanged = false;
protected PamhagenPlc.ActuatorStates Actuators;
protected PamhagenPlc.SensorStates Sensors;
protected bool GetDS(int n) => Sensors.GetDS(n >= 1 && n <= 60 ? n : throw new ArgumentException("Invalid value for n: 1 <= #DS <= 60"));
protected bool GetV(int n) => Actuators.GetV(n >= 1 && n <= 60 ? n : throw new ArgumentException("Invalid value for n: 1 <= #V <= 60"));
public bool IsValveClosed(int n) => GetDS(n);
public bool IsValveOpen(int n) => !IsValveClosed(n);
public bool WantValveClosed(int n) => GetV(n);
public bool WantValveOpen(int n) => !WantValveClosed(n);
public bool IsA1Selected => Sensors.TroughSelector == 1;
public bool IsA2Selected => Sensors.TroughSelector == 2;
public FillState FillLevelA1 => Sensors.FillingLevels.A1;
public FillState FillLevelA2 => Sensors.FillingLevels.A2;
public FillState FillLevelPress1 => Sensors.FillingLevels.Press1;
public FillState FillLevelPress2 => Sensors.FillingLevels.Press2;
public FillState FillLevelT1 => Sensors.FillingLevelTanks[0];
public FillState FillLevelT2 => Sensors.FillingLevelTanks[1];
public FillState FillLevelT3 => Sensors.FillingLevelTanks[2];
public FillState FillLevelT4 => Sensors.FillingLevelTanks[3];
public FillState FillLevelT5 => Sensors.FillingLevelTanks[4];
public FillState FillLevelT6 => Sensors.FillingLevelTanks[5];
public FillState FillLevelT7 => Sensors.FillingLevelTanks[6];
public FillState FillLevelT8 => Sensors.FillingLevelTanks[7];
public FillState FillLevelT9 => Sensors.FillingLevelTanks[8];
public double GradationOe => Sensors.GradationOe;
public MotorState PresseQuerSchnecke => Sensors.PresseQuerSchnecke;
public bool WantA1Selected => Actuators.TroughSelector;
public bool WantA2Selected => !Actuators.TroughSelector;
public bool IsTroughAugerActive => Actuators.TroughAuger;
public bool IsReblerActive => Actuators.Rebler;
public bool IsStirrerA1Active => Actuators.StirrerA1;
public bool IsStirrerA2Active => Actuators.StirrerA2;
public bool IsBeltActive => Actuators.Belt;
public bool IsAuger1Active => Actuators.Auger1;
public bool IsAuger2Active => Actuators.Auger2;
public bool IsGradationPumpActive => Actuators.GradationPump;
public PamhagenPlant(string portName) {
Plc = new(portName);
}
protected virtual void RaiseUpdateEvent(EventArgs evt) {
App.MainDispatcher.BeginInvoke(() => Update?.Invoke(this, evt));
}
public async Task StartThread() {
await Plc.TestConnection();
Actuators = await Plc.ReadOutputs();
BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop));
BackgroundThread.Start();
}
public void Dispose() {
IsRunning = false;
BackgroundThread?.Interrupt();
BackgroundThread?.Join();
Plc.Dispose();
GC.SuppressFinalize(this);
}
protected async void BackgroundLoop(object? parameters) {
while (IsRunning) {
try {
if (ActuatorsChanged) {
await Plc.WriteOutputs(Actuators);
ActuatorsChanged = false;
}
Sensors = await Plc.ReadInputs();
RaiseUpdateEvent(EventArgs.Empty);
} catch (ThreadInterruptedException) {
// ignore
} catch (Exception exc) {
var str = "Bei der SPS ist ein Fehler aufgetreten:\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
try {
await Plc.WriteOutputs(new());
} catch (Exception exc) {
var str = "Beim Schließen der Verbindung zur SPS ist ein Fehler aufgetreten:\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void CommitChanges() {
ActuatorsChanged = true;
}
public MotorState MP1 {
get => Actuators.MP1;
set => Actuators.MP1 = (value != MotorState.Halt && value != MotorState.Forward && value != MotorState.Backward) ? throw new ArgumentException("Invalid state for MP1") : value;
}
public MotorState MP2 {
get => Actuators.MP2;
set => Actuators.MP2 = (value != MotorState.Halt && value != MotorState.Forward && value != MotorState.Backward) ? throw new ArgumentException("Invalid state for MP2") : value;
}
public MotorState P12 {
get => Actuators.P12;
set => Actuators.P12 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P12") : value;
}
public MotorState P3 {
get => Actuators.P3;
set => Actuators.P3 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P3") : value;
}
public MotorState P4 {
get => Actuators.P4;
set => Actuators.P4 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P4") : value;
}
public MotorState P5 {
get => Actuators.P5;
set => Actuators.P5 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P5") : value;
}
public MotorState P6 {
get => Actuators.P6;
set => Actuators.P6 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P6") : value;
}
public void OpenV(int n) => SetV(n, false);
public void CloseV(int n) => SetV(n, true);
public void SetV(int n, bool val) {
if (n < 1 || n > 60) throw new ArgumentException("Invalid value for n: 1 <= #V <= 60");
Actuators.SetV(n, val);
}
public void SelectA1() {
Actuators.TroughSelector = true;
//if (IsReblerActive) Actuators.StirrerA1 = true;
}
public void SelectA2() {
Actuators.TroughSelector = false;
//if (IsReblerActive) Actuators.StirrerA2 = true;
}
public void StartRebler() {
Actuators.Rebler = true;
}
public void StopRebler() {
Actuators.Rebler = false;
}
}
}