Files
pamhagen-sysctrl/PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs
T
2026-10-13 17:26:35 +02:00

269 lines
10 KiB
C#

using System.IO.Ports;
namespace PamhagenSysCtrl.Helpers.Plc {
public class PamhagenPlc : IDisposable {
private bool _manualControlMode = false;
private bool _overridePathClearnaces = false;
private bool _overrideDryRunClearances = false;
public bool ManualControlMode { get => _manualControlMode; set { _manualControlMode = value; UpdateInterlocks(); } }
public bool OverridePathClearances { get => _overridePathClearnaces; set { _overridePathClearnaces = value; UpdateInterlocks(); } }
public bool OverrideDryRunClearances { get => _overrideDryRunClearances; set { _overrideDryRunClearances = value; UpdateInterlocks(); } }
protected LegacyPamhagenPlc Plc;
public PamhagenState State { get; private set; }
public string? ComPort => Plc?.ComPort;
public T1.Status? LastStatus => Plc?.LastStatus;
public T1Error? LastError => Plc?.LastError;
protected LegacyPamhagenPlc.ActuatorStates Actuators;
protected LegacyPamhagenPlc.ActuatorStates LastActuators;
protected LegacyPamhagenPlc.SensorStates Sensors = new(default, default, default, default, default, default, default, [
FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown
], default);
public PamhagenPlc(string comPort, Parity parity = Parity.Odd) {
Plc = new(comPort, parity);
}
public void Dispose() {
GC.SuppressFinalize(this);
Plc.Dispose();
}
public async Task Initialize() {
await Plc.TestConnection();
Actuators = await Plc.ReadOutputs();
LastActuators = Actuators;
Sensors = await Plc.ReadInputs();
State = new(Sensors, () => Actuators, OverridePathClearances, OverrideDryRunClearances);
}
public async Task Shutdown() {
await Plc.WriteOutputs(new() { Valves = Actuators.Valves });
}
public async Task Update() {
UpdateInterlocks();
if (Actuators != LastActuators) {
LastActuators = Actuators;
await Plc.WriteOutputs(LastActuators);
}
Sensors = await Plc.ReadInputs();
State = new(Sensors, () => Actuators, OverridePathClearances, OverrideDryRunClearances);
UpdateInterlocks();
}
protected void UpdateInterlocks() {
if (!ManualControlMode) {
if (State.PressCrossAuger_IsActive && !State.Auger2_IsActive) StartAuger2();
if (State.Rebler_IsActive && !State.Auger1_IsActive) StartAuger1();
if (State.Auger1_IsActive && !State.Auger2_IsActive) StartAuger2();
if (State.Auger2_IsActive && !State.Auger3_IsActive) StartAuger3();
if (State.TroughAuger_IsActive && !State.TroughAuger_HasClearance)
StopTroughAuger();
if (!State.PressCrossAuger_IsActive && !State.Auger1_IsActive) {
StopAuger2();
StopAuger3();
}
}
if (State.MP1_IsActive && !State.MP1_HasClearance) StopMP1();
if (State.MP2_IsActive && !State.MP2_HasClearance) StopMP2();
if (!ManualControlMode) {
if (State.MP1_State == MotorState.Forward && State.MW1_FillLevel >= FillState.Half && !State.MW1_Stirrer_IsActive) {
StartStirrerMW1();
} else if (State.MW2_Stirrer_IsActive && (!State.MP1_IsActive || State.MW1_FillLevel < FillState.Half)) {
StopStirrerMW1();
}
if (State.MP2_State == MotorState.Forward && State.MW2_FillLevel >= FillState.Half && !State.MW2_Stirrer_IsActive) {
StartStirrerMW2();
} else if (State.MW2_Stirrer_IsActive && (!State.MP2_IsActive || State.MW2_FillLevel < FillState.Half)) {
StopStirrerMW2();
}
}
if (State.P12_IsActive && !State.P12_HasClearance) DisableP12();
if (State.P3_IsActive && !State.P3_HasClearance) DisableP3();
if (State.P4_IsActive && !State.P4_HasClearance) DisableP4();
if (State.P5_IsActive && !State.P5_HasClearance) DisableP5();
if (State.P6_IsActive && !State.P6_HasClearance) DisableP6();
}
public void OpenV(int n) => SetV(n, true);
public void CloseV(int n) => SetV(n, false);
protected void SetV(int n, bool val) {
if (n < 1 || n > 57) throw new ArgumentException("Invalid value for n: 1 <= #V <= 57");
Actuators.SetV(n, val);
}
public void SelectMW1() {
Actuators.SetV(58, true);
}
public void SelectMW2() {
Actuators.SetV(58, false);
}
public void StartTroughAuger() {
if (!ManualControlMode && !State.TroughAuger_HasClearance)
throw new NoClearanceException("Schnecke Auffangwanne hat keine Freigabe");
Actuators.TroughAuger = true;
}
public void StopTroughAuger() {
Actuators.TroughAuger = false;
}
public void StartRebler() {
Actuators.Rebler = true;
if (!ManualControlMode) StartAuger1();
}
public void StopRebler() {
if (!ManualControlMode) StopTroughAuger();
Actuators.Rebler = false;
}
public void StartStirrerMW1() {
Actuators.StirrerMW1 = true;
}
public void StopStirrerMW1() {
Actuators.StirrerMW1 = false;
}
public void StartStirrerMW2() {
Actuators.StirrerMW2 = true;
}
public void StopStirrerMW2() {
Actuators.StirrerMW2 = false;
}
public void StartAuger1() {
Actuators.Auger1 = true;
if (!ManualControlMode) StartAuger2();
}
public void StopAuger1() {
if (!ManualControlMode && State.Rebler_IsActive) throw new NoClearanceException("Rebler aktiv");
Actuators.Auger1 = false;
}
public void StartAuger2() {
Actuators.Auger2 = true;
if (!ManualControlMode) StartAuger3();
}
public void StopAuger2() {
if (!ManualControlMode && State.PressCrossAuger_IsActive) throw new NoClearanceException("Presse-Querschnecke aktiv");
if (!ManualControlMode && State.Auger1_IsActive) throw new NoClearanceException("Förderschnecke 1 aktiv");
Actuators.Auger2 = false;
}
public void StartAuger3() {
Actuators.Auger3 = true;
}
public void StopAuger3() {
if (!ManualControlMode && State.Auger2_IsActive) throw new NoClearanceException("Förderschnecke 2 aktiv");
Actuators.Auger3 = false;
}
public void StartGradationPump() {
Actuators.GradationPump = true;
}
public void StopGradationPump() {
Actuators.GradationPump = false;
}
public void StartMP1Forward() {
if (!State.MP1_HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
if (Actuators.MP1 == MotorState.Backward) throw new NoClearanceException("MP1 läuft bereits (zurück)");
Actuators.MP1 = MotorState.Forward;
if (State.MW1_FillLevel >= FillState.Half) StartStirrerMW1();
}
public void StartMP1Backward() {
if (!State.MP1_HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
if (Actuators.MP1 == MotorState.Forward) throw new NoClearanceException("MP1 läuft bereits (vor)");
Actuators.MP1 = MotorState.Backward;
}
public void StopMP1() {
Actuators.MP1 = MotorState.Halt;
if (!ManualControlMode) StopStirrerMW1();
}
public void StartMP2Forward() {
if (!State.MP2_HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
if (Actuators.MP2 == MotorState.Backward) throw new NoClearanceException("MP2 läuft bereits (zurück)");
Actuators.MP2 = MotorState.Forward;
if (State.MW2_FillLevel >= FillState.Half) StartStirrerMW2();
}
public void StartMP2Backward() {
if (!State.MP2_HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
if (Actuators.MP2 == MotorState.Forward) throw new NoClearanceException("MP2 läuft bereits (vor)");
Actuators.MP2 = MotorState.Backward;
}
public void StopMP2() {
Actuators.MP2 = MotorState.Halt;
if (!ManualControlMode) StopStirrerMW1();
}
public void EnableP12() {
if (!State.P12_HasClearance) throw new NoClearanceException("P1/2 hat keine Freigabe");
Actuators.P12 = MotorState.Forward;
}
public void DisableP12() {
Actuators.P12 = MotorState.Halt;
}
public void EnableP3() {
if (!State.P3_HasClearance) throw new NoClearanceException("P3 hat keine Freigabe");
Actuators.P3 = MotorState.Forward;
}
public void DisableP3() {
Actuators.P3 = MotorState.Halt;
}
public void EnableP4() {
if (!State.P4_HasClearance) throw new NoClearanceException("P4 hat keine Freigabe");
Actuators.P4 = MotorState.Forward;
}
public void DisableP4() {
Actuators.P4 = MotorState.Halt;
}
public void EnableP5() {
if (!State.P5_HasClearance) throw new NoClearanceException("P5 hat keine Freigabe");
Actuators.P5 = MotorState.Forward;
}
public void DisableP5() {
Actuators.P5 = MotorState.Halt;
}
public void EnableP6() {
if (!State.P6_HasClearance) throw new NoClearanceException("P6 hat keine Freigabe");
Actuators.P6 = MotorState.Forward;
}
public void DisableP6() {
Actuators.P6 = MotorState.Halt;
}
}
}