5 Commits
21 changed files with 1201 additions and 471 deletions
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
+1 -1
View File
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PamhagenSysCtrl"
StartupUri="Windows/MainWindow.xaml"
StartupUri="Windows/PlantSchemeWindow.xaml"
Exit="Application_Exit">
<Application.Resources>
</Application.Resources>
+31 -1
View File
@@ -1,4 +1,6 @@
using PamhagenSysCtrl.Helpers;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Threading;
@@ -6,14 +8,42 @@ namespace PamhagenSysCtrl {
public partial class App : Application {
public static PamhagenPlant? Plant;
public static Dispatcher MainDispatcher;
public static Dispatcher? MainDispatcher;
public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Anlagensteuerung Pamhagen");
public static readonly string ConfigPath = Path.Combine(DataPath, "config.ini");
public static readonly string InstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Anlagensteuerung Pamhagen");
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Anlagensteuerung Pamhagen");
public static Config Config { get; private set; } = new(ConfigPath);
public static Version Version { get; private set; } = new();
public App() :
base() {
Directory.CreateDirectory(TempPath);
Directory.CreateDirectory(DataPath);
MainDispatcher = Dispatcher;
var args = Environment.GetCommandLineArgs();
if (args.Length >= 2) {
Config = new(Path.GetFullPath(args[1]));
}
}
protected override async void OnStartup(StartupEventArgs evt) {
Version = new Version(typeof(App).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion.Split('+')[0] ?? "0.0.0");
try {
Plant = new(Config.PlcPort);
await Plant.StartThread();
} catch (Exception exc) {
Plant?.Dispose();
Plant = null;
var str = $"Beim Aufbauen einer Verbindung zur SPS ist ein Fehler aufgetreten:\n\n{exc.GetType().Name}: {exc.Message}";
if (exc.InnerException != null) str += $"\n\n{exc.InnerException.GetType().Name}: {exc.InnerException.Message}";
MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
base.OnStartup(evt);
}
+28
View File
@@ -0,0 +1,28 @@
using Microsoft.Extensions.Configuration;
using System.Windows;
namespace PamhagenSysCtrl.Helpers {
public class Config {
private static readonly string[] TrueValues = ["1", "true", "yes", "on"];
private readonly string FileName;
public string PlcPort = "COM1";
public Config(string filename) {
FileName = filename;
Read();
}
public void Read() {
try {
var config = new ConfigurationBuilder().AddIniFile(FileName).Build();
PlcPort = config["plc:port"] ?? "COM1";
} catch (Exception exc) {
MessageBox.Show($"Die Konfigurationsdatei konnte nicht gelesen werden:\n\n{exc.Message}", "Konfigurationsdatei lesen", MessageBoxButton.OK, MessageBoxImage.Error);
App.Current.Shutdown();
}
}
}
}
@@ -0,0 +1,4 @@
namespace PamhagenSysCtrl.Helpers {
public class NoClearanceException(string msg) : Exception(msg) {
}
}
+60 -42
View File
@@ -9,6 +9,15 @@ namespace PamhagenSysCtrl.Helpers {
public readonly Trough MW1;
public readonly Trough MW2;
public readonly Pump MP1;
public readonly Pump MP2;
public readonly Pump P12;
public readonly Pump P3;
public readonly Pump P4;
public readonly Pump P5;
public readonly Pump P6;
public readonly EncasedAuger Auger1;
public readonly EncasedAuger Auger2;
public PamhagenGraph() {
double mw2X = 180;
@@ -38,31 +47,33 @@ namespace PamhagenSysCtrl.Helpers {
var pr1X = 750;
var pr2X = 900;
var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100);
var trough = new EntryTrough("Auffangwanne", mw1X + 70, 100, () => App.Plant?.IsTroughAugerActive ?? false);
Nodes.Add(trough);
var auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200);
var auger2 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, 180);
var auger3 = new EncasedAuger("", 120, 80, 135);
var belt = new ConveyorBelt("", 90, 160);
Auger1 = new EncasedAuger("", (mw1X + mw2X) / 2 - 100, 200, () => App.Plant?.IsAuger1Active ?? false);
var auger3 = new EncasedAuger("Pressen-\nQuerschnecke", 40, 200, () => App.Plant?.IsPresseQuerSchneckeActive ?? false, 180, clickable: false);
Auger2 = new EncasedAuger("", 120, 80, () => App.Plant?.IsAuger2Active ?? false, 135);
var belt = new ConveyorBelt("", 90, 160, () => App.Plant?.IsBeltActive ?? false);
Nodes.Add(belt);
Nodes.Add(auger1);
Nodes.Add(auger2);
Nodes.Add(Auger1);
Nodes.Add(auger3);
var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200);
Nodes.Add(Auger2);
var rebler = new Rebler("Rebler", (mw1X + mw2X) / 2, 200, () => App.Plant?.IsReblerActive ?? false);
Nodes.Add(rebler);
var switcher = new Switcher("", (mw1X + mw2X) / 2, 260, () => App.Plant?.TroughSelector ?? 0, () => App.Plant == null ? 0 : App.Plant.WantMW1Selected ? 1 : 2);
Nodes.Add(switcher);
MW1 = new Trough("MW1", mw1X, mpY - 70, () => App.Plant?.FillLevelA1 ?? FillState.Unknown);
MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelA1 ?? FillState.Unknown);
var mp1 = new Pump("MP1", mw1X, mpY);
var mp2 = new Pump("MP2", mw2X, mpY);
MW1 = new Trough("MW1", mw1X, mpY - 70, () => App.Plant?.FillLevelMW1 ?? FillState.Unknown);
MW2 = new Trough("MW2", mw2X, mpY - 70, () => App.Plant?.FillLevelMW2 ?? FillState.Unknown);
MP1 = new Pump("MP1", mw1X, mpY, () => App.Plant?.IsMP1Active ?? false, () => App.Plant?.MP1HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
MP2 = new Pump("MP2", mw2X, mpY, () => App.Plant?.IsMP2Active ?? false, () => App.Plant?.MP2HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
var x1 = new PipeJoin(mw1X, mpY + 40);
var x2 = new PipeJoin(mw2X, mpY + 40);
CreateOutlet(MW1, mp1);
CreateOutlet(MW2, mp2);
CreatePipe(mp1, x1);
CreatePipe(mp2, x2);
CreateOutlet(MW1, MP1);
CreateOutlet(MW2, MP2);
CreatePipe(MP1, x1);
CreatePipe(MP2, x2);
var v1 = CreateValve(1, mw1X, mpY + 70);
var v2 = CreateValve(2, mw2X, mpY + 70);
@@ -279,17 +290,17 @@ namespace PamhagenSysCtrl.Helpers {
CreateInlet(v43, t9);
var xp12 = new PipeJoin((t1X + t2X) / 2, tanksY + 80);
var p12 = new Pump("P1/2", (t1X + t2X) / 2, tanksY + 110);
P12 = new Pump("P1/2", (t1X + t2X) / 2, tanksY + 110, () => App.Plant?.IsP12Active ?? false, () => App.Plant?.P12HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t1, xp12);
CreateOutlet(t2, xp12);
CreatePipe(xp12, p12);
CreatePipe(xp12, P12);
var p3 = new Pump("P3", t3X, tanksY + 110);
var p4 = new Pump("P4", t4X, tanksY + 110);
var p5 = new Pump("P5", t5X, tanksY + 110);
CreateOutlet(t3, p3);
CreateOutlet(t4, p4);
CreateOutlet(t5, p5);
P3 = new Pump("P3", t3X, tanksY + 110, () => App.Plant?.IsP3Active ?? false, () => App.Plant?.P3HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
P4 = new Pump("P4", t4X, tanksY + 110, () => App.Plant?.IsP4Active ?? false, () => App.Plant?.P4HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
P5 = new Pump("P5", t5X, tanksY + 110, () => App.Plant?.IsP5Active ?? false, () => App.Plant?.P5HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t3, P3);
CreateOutlet(t4, P4);
CreateOutlet(t5, P5);
var v44 = CreateValve(44, (t1X + t2X) / 2, tanksY + 150);
var v45 = CreateValve(45, t3X, tanksY + 150);
@@ -299,10 +310,10 @@ namespace PamhagenSysCtrl.Helpers {
var xv44 = new PipeJoin((t1X + t2X) / 2, tanksY + 180);
var xv45 = new PipeJoin(t3X, tanksY + 180);
var xv47 = new PipeJoin(t4X, tanksY + 180);
CreatePipe(p12, v44);
CreatePipe(p3, v45);
CreatePipe(p4, v47);
CreatePipe(p5, v48);
CreatePipe(P12, v44);
CreatePipe(P3, v45);
CreatePipe(P4, v47);
CreatePipe(P5, v48);
CreatePipe(v44, xv44);
CreatePipe(v45, xv45);
CreatePipe(v47, xv47);
@@ -316,20 +327,20 @@ namespace PamhagenSysCtrl.Helpers {
var xt6 = new PipeJoin(t6X, tanksY + 110);
var xt7 = new PipeJoin(t7X, tanksY + 110);
var xt8 = new PipeJoin(t8X, tanksY + 110);
var p6 = new Pump("P6", t6X, tanksY + 150);
P6 = new Pump("P6", t6X, tanksY + 150, () => App.Plant?.IsP6Active ?? false, () => App.Plant?.P6HasClearance ?? false, (x) => SelectedPaths.Any(p => p.Hops.Any(h => h.Node == x)));
CreateOutlet(t6, xt6);
CreateOutlet(t7, xt7);
CreateOutlet(t8, xt8);
CreateOutlet(t9, xt8);
CreatePipe(xt8, xt7);
CreatePipe(xt7, xt6);
CreatePipe(xt6, p6);
CreatePipe(xt6, P6);
var v49 = CreateValve(49, t4X, tanksY + 220);
CreatePipe(xv47, v49);
var press1 = new Press("Presse 1", pr1X, prY, 200000, () => App.Plant?.FillLevelPress1 ?? FillState.Unknown);
var press2 = new Press("Presse 2", pr2X, prY, 150000, () => App.Plant?.FillLevelPress1 ?? FillState.Unknown);
var press2 = new Press("Presse 2", pr2X, prY, 150000, () => App.Plant?.FillLevelPress2 ?? FillState.Unknown);
var v50 = CreateValve(50, pr1X - 45, prY - 100);
var v51 = CreateValve(51, pr1X - 15, prY - 100);
var v52 = CreateValve(52, pr1X + 15, prY - 100);
@@ -346,7 +357,7 @@ namespace PamhagenSysCtrl.Helpers {
CreatePipe(v6, xp1, true);
CreatePipe(v8, xp2, true);
CreatePipe(v49, xp3, true);
CreatePipe(p6, xp4, true);
CreatePipe(P6, xp4, true);
CreatePipe(xp1, v51);
CreatePipe(xp1, v55);
CreatePipe(xp2, v52);
@@ -367,7 +378,7 @@ namespace PamhagenSysCtrl.Helpers {
}
protected static Valve CreateValve(int n, double x, double y) {
return new(n, x, y, () => App.Plant?.IsValveOpen(4) ?? false, () => App.Plant?.WantValveOpen(4) ?? false);
return new(n, x, y, () => App.Plant?.IsValveOpen(n) ?? false, () => App.Plant?.WantValveOpen(n) ?? false);
}
protected static Tank CreateTank(int n, double x, double y, int capacity) {
@@ -400,14 +411,13 @@ namespace PamhagenSysCtrl.Helpers {
public void AddPath(Path path) {
_selectedPaths.Add(path);
UpdateValvesAdjacientToPath(path, true);
UpdateValvesAdjacientToPath(path, true, false);
if (App.Plant is PamhagenPlant plant) {
foreach (var (edge, _) in path.Hops) {
if (edge is Valve v) {
foreach (var (_, node) in path.Hops) {
if (node is Valve v) {
plant.OpenV(v.Nr);
}
}
plant.CommitChanges();
}
}
@@ -416,18 +426,26 @@ namespace PamhagenSysCtrl.Helpers {
UpdateValvesAdjacientToPath(path, false);
foreach (var p in _selectedPaths) UpdateValvesAdjacientToPath(p, true);
if (App.Plant is PamhagenPlant plant) {
foreach (var (edge, _) in path.Hops) {
if (edge is Valve v) {
foreach (var (_, node) in path.Hops) {
if (node is Valve v) {
plant.CloseV(v.Nr);
}
}
plant.CommitChanges();
}
}
private void UpdateValvesAdjacientToPath(Path path, bool locked) {
private void UpdateValvesAdjacientToPath(Path path, bool locked, bool? wantOpen = null) {
foreach (var (edge, node) in path.Hops) {
TraverseSubgraph(node, valveAction: (v) => v.IsLocked = locked);
TraverseSubgraph(node, valveAction: (v) => {
v.IsLocked = locked;
if (wantOpen.HasValue) {
if (wantOpen.Value) {
App.Plant?.OpenV(v.Nr);
} else {
App.Plant?.CloseV(v.Nr);
}
}
});
}
}
+294 -38
View File
@@ -13,17 +13,23 @@ namespace PamhagenSysCtrl.Helpers {
protected bool ActuatorsChanged = false;
protected PamhagenPlc.ActuatorStates Actuators;
protected PamhagenPlc.SensorStates Sensors;
protected PamhagenPlc.SensorStates Sensors = new(default, default, default, default, [
FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown
], default);
public bool IsValveOpen(int n) => !IsValveClosed(n);
public bool IsValveClosed(int n) => Sensors.GetDS(n);
public bool WantValveClosed(int n) => !WantValveOpen(n);
public bool WantValveOpen(int n) => Actuators.GetV(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 bool AreValvesOpen(params int[] ns) => ns.All(IsValveOpen) && ns.All(WantValveOpen);
public bool AreValvesClosed(params int[] ns) => ns.All(IsValveClosed) && ns.All(WantValveClosed);
public int TroughSelector => Sensors.TroughSelector;
public bool IsMWSelected => Sensors.TroughSelector == 1;
public bool IsMW2Selected => Sensors.TroughSelector == 2;
public FillState FillLevelMW1 => Sensors.FillingLevels.MW1;
public FillState FillLevelMW2 => Sensors.FillingLevels.MW2;
public FillState FillLevelPress1 => Sensors.FillingLevels.Press1;
public FillState FillLevelPress2 => Sensors.FillingLevels.Press2;
public FillState FillLevelT1 => Sensors.FillingLevelTanks[0];
@@ -38,26 +44,53 @@ namespace PamhagenSysCtrl.Helpers {
public FillState[] TankFillLevels => Sensors.FillingLevelTanks;
public double GradationOe => Sensors.GradationOe;
public MotorState PresseQuerSchnecke => Sensors.PresseQuerSchnecke;
public bool IsPresseQuerSchneckeActive => PresseQuerSchnecke == MotorState.Forward;
public bool WantA1Selected => Actuators.GetV(58);
public bool WantA2Selected => !Actuators.GetV(58);
public bool WantMW1Selected => Actuators.GetV(58);
public bool WantMW2Selected => !Actuators.GetV(58);
public bool IsTroughAugerActive => Actuators.TroughAuger;
public bool IsReblerActive => Actuators.Rebler;
public bool IsStirrerA1Active => Actuators.StirrerA1;
public bool IsStirrerA2Active => Actuators.StirrerA2;
public bool IsStirrerMW1Active => Actuators.StirrerMW1;
public bool IsStirrerMW2Active => Actuators.StirrerMW2;
public bool IsBeltActive => Actuators.Belt;
public bool IsAuger1Active => Actuators.Auger1;
public bool IsAuger2Active => Actuators.Auger2;
public bool IsWasteDisposalActive => IsBeltActive || IsAuger1Active || IsAuger2Active;
public bool IsGradationPumpActive => Actuators.GradationPump;
public bool IsMP1Active => Actuators.MP1 == MotorState.Forward || Actuators.MP1 == MotorState.Backward;
public bool IsMP2Active => Actuators.MP2 == MotorState.Forward || Actuators.MP2 == MotorState.Backward;
public bool IsP12Active => Actuators.P12 == MotorState.Forward;
public bool IsP3Active => Actuators.P3 == MotorState.Forward;
public bool IsP4Active => Actuators.P4 == MotorState.Forward;
public bool IsP5Active => Actuators.P5 == MotorState.Forward;
public bool IsP6Active => Actuators.P6 == MotorState.Forward;
public PamhagenPlant(string portName) {
Plc = new(portName);
Update += OnUpdate;
}
protected virtual void RaiseUpdateEvent(PlantEventArgs evt) {
App.MainDispatcher.BeginInvoke(() => Update?.Invoke(this, evt));
App.MainDispatcher?.BeginInvoke(() => Update?.Invoke(this, evt));
}
protected static void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant p) return;
if (p.IsPresseQuerSchneckeActive && !p.IsBeltActive) p.StartBelt();
if (p.IsReblerActive && !p.IsAuger1Active) p.StartAuger1();
if (p.IsAuger1Active && !p.IsBeltActive) p.StartBelt();
if (p.IsBeltActive && !p.IsAuger2Active) p.StartAuger2();
if (p.IsTroughAugerActive && (!p.IsReblerActive || (p.IsMWSelected && p.FillLevelMW1 == FillState.Full) || (p.IsMW2Selected && p.FillLevelMW2 == FillState.Full)))
p.StopTroughAuger();
if (p.IsMP1Active && !p.MP1HasClearance) p.StopMP1();
if (p.IsMP2Active && !p.MP2HasClearance) p.StopMP2();
if (p.IsP12Active && !p.P12HasClearance) p.StopP12();
if (p.IsP3Active && !p.P3HasClearance) p.StopP3();
if (p.IsP4Active && !p.P4HasClearance) p.StopP4();
if (p.IsP5Active && !p.P5HasClearance) p.StopP5();
if (p.IsP6Active && !p.P6HasClearance) p.StopP6();
}
public async Task StartThread() {
@@ -107,40 +140,222 @@ namespace PamhagenSysCtrl.Helpers {
}
}
public void CommitChanges() {
ActuatorsChanged = true;
}
protected bool HasWTClearanceAA =>
(AreValvesOpen(12) && AreValvesClosed(15, 16, 20)) || // bypass
(AreValvesOpen(15, 18, 16) && AreValvesClosed(11, 12, 14, 17, 19, 20)) || // WT1
(AreValvesOpen(15, 17, 20) && AreValvesClosed(11, 12, 18, 19, 21)) || // WT2
(AreValvesOpen(15, 18, 19, 20) && AreValvesClosed(11, 12, 14, 16, 17, 21)) || // WT1+WT2
false;
protected bool HasWTClearanceAB =>
(AreValvesOpen(15, 18, 14) && AreValvesClosed(11, 12, 13, 16, 17, 19, 21)) || // WT1
(AreValvesOpen(15, 17, 21) && AreValvesClosed(11, 12, 13, 18, 19, 20)) || // WT2
(AreValvesOpen(15, 18, 19, 21) && AreValvesClosed(11, 12, 13, 14, 16, 17, 20)) || // WT1+WT2
false;
protected bool HasWTClearanceBA =>
(AreValvesOpen(11, 18, 16) && AreValvesClosed(15, 12, 13, 14, 17, 19, 20)) || // WT1
(AreValvesOpen(11, 17, 20) && AreValvesClosed(15, 12, 13, 18, 19, 21)) || // WT2
(AreValvesOpen(11, 18, 19, 20) && AreValvesClosed(15, 12, 13, 14, 16, 17, 21)) || // WT1+WT2
false;
protected bool HasWTClearanceBB =>
(AreValvesOpen(13) && AreValvesClosed(11, 14, 21)) || // bypass
(AreValvesOpen(11, 18, 14) && AreValvesClosed(15, 13, 16, 17, 19, 21)) || // WT1
(AreValvesOpen(11, 17, 21) && AreValvesClosed(15, 13, 18, 19, 20)) || // WT2
(AreValvesOpen(11, 18, 19, 21) && AreValvesClosed(15, 13, 14, 16, 17, 20)) || // WT1+WT2
false;
protected bool HasT1ClearanceA => AreValvesOpen(22) && AreValvesClosed(24, 26, 28);
protected bool HasT1ClearanceB => AreValvesOpen(23) && AreValvesClosed(25, 27, 29);
protected bool HasT2ClearanceA => AreValvesOpen(24) && AreValvesClosed(22, 26, 28);
protected bool HasT2ClearanceB => AreValvesOpen(25) && AreValvesClosed(23, 27, 29);
protected bool HasT3ClearanceA => AreValvesOpen(26) && AreValvesClosed(22, 24, 28);
protected bool HasT3ClearanceB => AreValvesOpen(27) && AreValvesClosed(23, 25, 29);
protected bool HasT4ClearanceA => AreValvesOpen(28, 30) && AreValvesClosed(22, 24, 26, 32, 34);
protected bool HasT4ClearanceB => AreValvesOpen(29, 31) && AreValvesClosed(23, 25, 27, 33, 35);
protected bool HasT5ClearanceA => AreValvesOpen(28, 32) && AreValvesClosed(22, 24, 26, 30, 34);
protected bool HasT5ClearanceB => AreValvesOpen(29, 33) && AreValvesClosed(23, 25, 27, 31, 35);
protected bool HasT6ClearanceA => AreValvesOpen(28, 34, 37) && AreValvesClosed(22, 24, 26, 30, 32, 39, 41, 43);
protected bool HasT6ClearanceB => AreValvesOpen(29, 35, 36) && AreValvesClosed(23, 25, 27, 31, 33, 38, 40, 42);
protected bool HasT7ClearanceA => AreValvesOpen(28, 34, 39) && AreValvesClosed(22, 24, 26, 30, 32, 37, 41, 43);
protected bool HasT7ClearanceB => AreValvesOpen(29, 35, 38) && AreValvesClosed(23, 25, 27, 31, 33, 36, 40, 42);
protected bool HasT8ClearanceA => AreValvesOpen(28, 34, 41) && AreValvesClosed(22, 24, 26, 30, 32, 37, 39, 43);
protected bool HasT8ClearanceB => AreValvesOpen(29, 35, 40) && AreValvesClosed(23, 25, 27, 31, 33, 36, 38, 42);
protected bool HasT9ClearanceA => AreValvesOpen(28, 34, 43) && AreValvesClosed(22, 24, 26, 30, 32, 37, 39, 41);
protected bool HasT9ClearanceB => AreValvesOpen(29, 35, 42) && AreValvesClosed(23, 25, 27, 31, 33, 36, 38, 40);
protected bool HasClearanceTank1(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT1ClearanceA) || (HasWTClearanceAB && HasT1ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT1ClearanceA) || (HasWTClearanceBB && HasT1ClearanceB)));
protected bool HasClearanceTank2(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT2ClearanceA) || (HasWTClearanceAB && HasT2ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT2ClearanceA) || (HasWTClearanceBB && HasT2ClearanceB)));
protected bool HasClearanceTank3(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT3ClearanceA) || (HasWTClearanceAB && HasT3ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT3ClearanceA) || (HasWTClearanceBB && HasT3ClearanceB)));
protected bool HasClearanceTank4(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT4ClearanceA) || (HasWTClearanceAB && HasT4ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT4ClearanceA) || (HasWTClearanceBB && HasT4ClearanceB)));
protected bool HasClearanceTank5(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT5ClearanceA) || (HasWTClearanceAB && HasT5ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT5ClearanceA) || (HasWTClearanceBB && HasT5ClearanceB)));
protected bool HasClearanceTank6(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT6ClearanceA) || (HasWTClearanceAB && HasT6ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT6ClearanceA) || (HasWTClearanceBB && HasT6ClearanceB)));
protected bool HasClearanceTank7(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT7ClearanceA) || (HasWTClearanceAB && HasT7ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT7ClearanceA) || (HasWTClearanceBB && HasT7ClearanceB)));
protected bool HasClearanceTank8(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT8ClearanceA) || (HasWTClearanceAB && HasT8ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT8ClearanceA) || (HasWTClearanceBB && HasT8ClearanceB)));
protected bool HasClearanceTank9(bool a, bool b) =>
(a && ((HasWTClearanceAA && HasT9ClearanceA) || (HasWTClearanceAB && HasT9ClearanceB))) ||
(b && ((HasWTClearanceBA && HasT9ClearanceA) || (HasWTClearanceBB && HasT9ClearanceB)));
public bool MP1HasClearance => FillLevelMW1 != FillState.Empty && (
(MP1HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(MP1HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(MP1HasClearanceTanksA, MP1HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool MP1HasClearancePress1 =>
(AreValvesOpen(1, 6, 51) && AreValvesClosed(3, 4, 5, 55)) ||
(AreValvesOpen(4, 8, 52) && AreValvesClosed(1, 2, 7, 56));
protected bool MP1HasClearancePress2 =>
(AreValvesOpen(1, 6, 55) && AreValvesClosed(3, 4, 5, 51)) ||
(AreValvesOpen(4, 8, 56) && AreValvesClosed(1, 2, 7, 52));
protected bool MP1HasClearanceTanksA => AreValvesOpen(1, 5) && AreValvesClosed(3, 4, 6);
protected bool MP1HasClearanceTanksB => AreValvesOpen(4, 7, 9) && AreValvesClosed(1, 2, 8, 10);
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 bool MP2HasClearance => FillLevelMW2 != FillState.Empty && (
(MP2HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(MP2HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(MP2HasClearanceTanksA, MP2HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool MP2HasClearancePress1 =>
(AreValvesOpen(2, 8, 52) && AreValvesClosed(3, 4, 7, 56)) ||
(AreValvesOpen(3, 6, 51) && AreValvesClosed(1, 2, 5, 55));
protected bool MP2HasClearancePress2 =>
(AreValvesOpen(2, 8, 56) && AreValvesClosed(3, 4, 7, 52)) ||
(AreValvesOpen(3, 6, 55) && AreValvesClosed(2, 1, 5, 51));
protected bool MP2HasClearanceTanksA => AreValvesOpen(3, 5) && AreValvesClosed(1, 2, 6);
protected bool MP2HasClearanceTanksB => AreValvesOpen(2, 7, 9) && AreValvesClosed(3, 4, 8, 10);
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 bool P12HasClearance => (FillLevelT1 != FillState.Empty || FillLevelT2 != FillState.Empty) && (
(P12HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P12HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P12HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P12HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P12HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P12HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P12HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P12HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P12HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P12HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P12HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P12HasClearancePress1 => AreValvesOpen(44, 46, 49, 50) && AreValvesClosed(10, 45, 47, 48, 54);
protected bool P12HasClearancePress2 => AreValvesOpen(44, 46, 49, 54) && AreValvesClosed(10, 45, 47, 48, 50);
protected bool P12HasClearanceTanksB => AreValvesOpen(44, 10) && AreValvesClosed(9, 45, 46);
public MotorState P12 {
get => Actuators.P12;
set => Actuators.P12 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P12") : value;
}
public bool P3HasClearance => FillLevelT3 != FillState.Empty && (
(P3HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P3HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P3HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P3HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P3HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P3HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P3HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P3HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P3HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P3HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P3HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P3HasClearancePress1 => AreValvesOpen(45, 46, 49, 50) && AreValvesClosed(10, 44, 47, 48, 54);
protected bool P3HasClearancePress2 => AreValvesOpen(45, 46, 49, 54) && AreValvesClosed(10, 44, 47, 48, 50);
protected bool P3HasClearanceTanksB => AreValvesOpen(45, 10) && AreValvesClosed(9, 44, 46);
public MotorState P3 {
get => Actuators.P3;
set => Actuators.P3 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P3") : value;
}
public bool P4HasClearance => FillLevelT4 != FillState.Empty && (
(P4HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P4HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P4HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P4HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P4HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P4HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P4HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P4HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P4HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P4HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P4HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P4HasClearancePress1 => AreValvesOpen(47, 49, 50) && AreValvesClosed(46, 48, 54);
protected bool P4HasClearancePress2 => AreValvesOpen(47, 49, 54) && AreValvesClosed(46, 48, 50);
protected bool P4HasClearanceTanksB => AreValvesOpen(47, 46, 10) && AreValvesClosed(9, 44, 45, 48, 49);
public MotorState P4 {
get => Actuators.P4;
set => Actuators.P4 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P4") : value;
}
public bool P5HasClearance => FillLevelT5 != FillState.Empty && (
(P5HasClearancePress1 && FillLevelPress1 != FillState.Full) ||
(P5HasClearancePress2 && FillLevelPress2 != FillState.Full) ||
(HasClearanceTank1(false, P5HasClearanceTanksB) && FillLevelT1 != FillState.Full) ||
(HasClearanceTank2(false, P5HasClearanceTanksB) && FillLevelT2 != FillState.Full) ||
(HasClearanceTank3(false, P5HasClearanceTanksB) && FillLevelT3 != FillState.Full) ||
(HasClearanceTank4(false, P5HasClearanceTanksB) && FillLevelT4 != FillState.Full) ||
(HasClearanceTank5(false, P5HasClearanceTanksB) && FillLevelT5 != FillState.Full) ||
(HasClearanceTank6(false, P5HasClearanceTanksB) && FillLevelT6 != FillState.Full) ||
(HasClearanceTank7(false, P5HasClearanceTanksB) && FillLevelT7 != FillState.Full) ||
(HasClearanceTank8(false, P5HasClearanceTanksB) && FillLevelT8 != FillState.Full) ||
(HasClearanceTank9(false, P5HasClearanceTanksB) && FillLevelT9 != FillState.Full) ||
false);
protected bool P5HasClearancePress1 => AreValvesOpen(48, 49, 50) && AreValvesClosed(46, 47, 54);
protected bool P5HasClearancePress2 => AreValvesOpen(48, 49, 54) && AreValvesClosed(46, 47, 50);
protected bool P5HasClearanceTanksB => AreValvesOpen(48, 46, 10) && AreValvesClosed(9, 44, 45, 47, 49);
public MotorState P5 {
get => Actuators.P5;
set => Actuators.P5 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P5") : value;
}
public bool P6HasClearance =>
(IsValveOpen(53) && IsValveClosed(57) && FillLevelPress1 != FillState.Full) ||
(IsValveOpen(57) && IsValveClosed(53) && FillLevelPress2 != FillState.Full);
public MotorState P6 {
get => Actuators.P6;
set => Actuators.P6 = (value != MotorState.Halt && value != MotorState.Forward) ? throw new ArgumentException("Invalid state for P6") : value;
@@ -153,157 +368,198 @@ namespace PamhagenSysCtrl.Helpers {
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);
ActuatorsChanged = true;
}
public void SelectA1() {
public void SelectMW1() {
Actuators.SetV(58, true);
//if (IsReblerActive) Actuators.StirrerA1 = true;
//if (IsReblerActive) Actuators.StirrerMW1 = true;
ActuatorsChanged = true;
}
public void SelectA2() {
public void SelectMW2() {
Actuators.SetV(58, false);
//if (IsReblerActive) Actuators.StirrerA2 = true;
//if (IsReblerActive) Actuators.StirrerMW2 = true;
ActuatorsChanged = true;
}
public void StartTroughAuger() {
if (!IsReblerActive || (IsMWSelected && FillLevelMW1 == FillState.Full) || (IsMW2Selected && FillLevelMW2 == FillState.Full))
throw new NoClearanceException("Schnecke Auffangwanne hat keine Freigabe");
Actuators.TroughAuger = true;
ActuatorsChanged = true;
}
public void StopTroughAuger() {
Actuators.TroughAuger = false;
ActuatorsChanged = true;
}
public void StartRebler() {
Actuators.Rebler = true;
StartAuger1();
ActuatorsChanged = true;
}
public void StopRebler() {
StopTroughAuger();
Actuators.Rebler = false;
ActuatorsChanged = true;
}
public void StartStirrerA1() {
Actuators.StirrerA1 = true;
public void StartStirrerMW1() {
Actuators.StirrerMW1 = true;
ActuatorsChanged = true;
}
public void StopStirrerA1() {
Actuators.StirrerA1 = false;
public void StopStirrerMW1() {
Actuators.StirrerMW1 = false;
ActuatorsChanged = true;
}
public void StartStirrerA2() {
Actuators.StirrerA2 = true;
public void StartStirrerMW2() {
Actuators.StirrerMW2 = true;
ActuatorsChanged = true;
}
public void StopStirrerA2() {
Actuators.StirrerA2 = false;
public void StopStirrerMW2() {
Actuators.StirrerMW2 = false;
ActuatorsChanged = true;
}
public void StartBelt() {
Actuators.Belt = true;
StartAuger2();
ActuatorsChanged = true;
}
public void StopBelt() {
if (IsPresseQuerSchneckeActive) throw new NoClearanceException("Presse-Querschnecke aktiv");
if (IsAuger1Active) throw new NoClearanceException("Förderschnecke 1 aktiv");
Actuators.Belt = false;
ActuatorsChanged = true;
}
public void StartAuger1() {
Actuators.Auger1 = true;
StartBelt();
ActuatorsChanged = true;
}
public void StopAuger1() {
if (IsReblerActive) throw new NoClearanceException("Rebler aktiv");
Actuators.Auger1 = false;
ActuatorsChanged = true;
}
public void StartAuger2() {
Actuators.Auger2 = true;
ActuatorsChanged = true;
}
public void StopAuger2() {
if (IsBeltActive) throw new NoClearanceException("Förderband aktiv");
Actuators.Auger2 = false;
}
public void StartWasteDisposal() {
StartBelt();
StartAuger1();
StartAuger2();
}
public void StopWasteDisposal() {
StopBelt();
StopAuger1();
StopAuger2();
ActuatorsChanged = true;
}
public void StartGradationPump() {
Actuators.GradationPump = true;
ActuatorsChanged = true;
}
public void StopGradationPump() {
Actuators.GradationPump = false;
ActuatorsChanged = true;
}
public void StartMP1Forward() {
if (!MP1HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
Actuators.MP1 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StartMP1Backward() {
if (!MP1HasClearance) throw new NoClearanceException("MP1 hat keine Freigabe");
Actuators.MP1 = MotorState.Backward;
ActuatorsChanged = true;
}
public void StopMP1() {
Actuators.MP1 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartMP2Forward() {
if (!MP2HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
Actuators.MP2 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StartMP2Backward() {
if (!MP2HasClearance) throw new NoClearanceException("MP2 hat keine Freigabe");
Actuators.MP2 = MotorState.Backward;
ActuatorsChanged = true;
}
public void StopMP2() {
Actuators.MP2 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP12() {
if (!P12HasClearance) throw new NoClearanceException("P1/2 hat keine Freigabe");
Actuators.P12 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP12() {
Actuators.P12 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP3() {
if (!P3HasClearance) throw new NoClearanceException("P3 hat keine Freigabe");
Actuators.P3 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP3() {
Actuators.P3 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP4() {
if (!P4HasClearance) throw new NoClearanceException("P4 hat keine Freigabe");
Actuators.P4 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP4() {
Actuators.P4 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP5() {
if (!P5HasClearance) throw new NoClearanceException("P5 hat keine Freigabe");
Actuators.P5 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP5() {
Actuators.P5 = MotorState.Halt;
ActuatorsChanged = true;
}
public void StartP6() {
if (!P6HasClearance) throw new NoClearanceException("P6 hat keine Freigabe");
Actuators.P6 = MotorState.Forward;
ActuatorsChanged = true;
}
public void StopP6() {
Actuators.P6 = MotorState.Halt;
ActuatorsChanged = true;
}
}
}
+10 -10
View File
@@ -5,7 +5,7 @@ namespace PamhagenSysCtrl.Helpers {
public record struct SensorStates(
long PressureSensors,
(FillState A1, FillState A2, FillState Press1, FillState Press2) FillingLevels,
(FillState MW1, FillState MW2, FillState Press1, FillState Press2) FillingLevels,
int TroughSelector,
double GradationOe,
FillState[] FillingLevelTanks,
@@ -17,7 +17,7 @@ namespace PamhagenSysCtrl.Helpers {
public record struct ActuatorStates(
long Valves,
MotorState MP1, MotorState MP2, MotorState P12, MotorState P3, MotorState P4, MotorState P5, MotorState P6,
bool TroughAuger, bool Rebler, bool StirrerA1, bool StirrerA2, bool Belt, bool Auger1, bool Auger2, bool GradationPump
bool TroughAuger, bool Rebler, bool StirrerMW1, bool StirrerMW2, bool Belt, bool Auger1, bool Auger2, bool GradationPump
) {
public readonly bool GetV(int n) => (Valves & (1L << (n - 1))) != 0;
public void SetV(int n, bool val) {
@@ -107,11 +107,11 @@ namespace PamhagenSysCtrl.Helpers {
long pressure = (long)r1 | ((long)r2 << 16) | ((long)r3 << 32) | ((long)r4 << 48);
pressure = (pressure & 0x01FFFFFFFFFFFFFF) | ((pressure & 0x0600000000000000) << 1);
var a1 = Int3ToFillState((f1 ) & 0x7); // 111 011 001 000
var a2 = Int3ToFillState((f1 >> 3) & 0x7); // 111 011 001 000
var p1 = Int1ToFillState((f1 >> 6) & 0x1); // 1 0
var p2 = Int1ToFillState((f1 >> 7) & 0x1); // 1 0
var wp = ((f1 >> 8) & 0x3); // 10 01
var mw1 = Int3ToFillState((f1 ) & 0x7); // 111 011 001 000
var mw2 = Int3ToFillState((f1 >> 3) & 0x7); // 111 011 001 000
var p1 = Int1ToFillState((f1 >> 6) & 0x1); // 1 0
var p2 = Int1ToFillState((f1 >> 7) & 0x1); // 1 0
var wp = ((f1 >> 8) & 0x3); // 10 01
// Masseligerät : 4mA => 50 Oe
// 20mA => 150 Oe
@@ -137,7 +137,7 @@ namespace PamhagenSysCtrl.Helpers {
var t9 = Int1ToFillState((f2 >> 13) & 0x1); // 1 0
var q1 = Int1ToPumpState((f2 >> 15) & 0x1); // 1 0
return new SensorStates(pressure, (a1, a2, p1, p2), wp == 3 ? -1 : wp == 1 ? 2 : wp == 2 ? 1 : 0, oe, [t1, t2, t3, t4, t5, t6, t7, t8, t9], q1);
return new SensorStates(pressure, (mw1, mw2, p1, p2), wp == 3 ? -1 : wp == 1 ? 2 : wp == 2 ? 1 : 0, oe, [t1, t2, t3, t4, t5, t6, t7, t8, t9], q1);
}
protected async Task<(ushort RW000, ushort RW001, ushort RW002, ushort RW003, ushort RW004, ushort RW005, ushort RW006)> ReadOutputRegisters() {
@@ -210,8 +210,8 @@ namespace PamhagenSysCtrl.Helpers {
(state.TroughAuger ? 0x01 : 0x00) |
(state.Rebler ? 0x02 : 0x00) |
(state.GetV(58) ? 0x04 : 0x00) |
(state.StirrerA1 ? 0x08 : 0x00) |
(state.StirrerA2 ? 0x10 : 0x00) |
(state.StirrerMW1 ? 0x08 : 0x00) |
(state.StirrerMW2 ? 0x10 : 0x00) |
(state.Belt ? 0x20 : 0x00) |
(state.Auger1 ? 0x40 : 0x00) |
(state.Auger2 ? 0x80 : 0x00);
+1 -1
View File
@@ -13,7 +13,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public double Height { get; set; }
public double Angle { get; set; }
public bool IsActive {
public bool IsAnimationActive {
set {
if (value) {
_storyboard?.Resume();
@@ -2,13 +2,12 @@
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
public class ConveyorBelt : INode {
public const double WIDTH = 35;
public const double WIDTH = 30;
public const double HEIGHT = 120;
public double CenterX { get; set; }
@@ -17,10 +16,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_animationActive = value;
if (value) {
_storyboard?.Resume();
} else {
@@ -29,15 +29,18 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _rect;
private Polyline? _polyline;
private Storyboard? _storyboard;
public ConveyorBelt(string label, double x, double y) {
public ConveyorBelt(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -54,7 +57,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
_rect.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2);
_rect.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2);
var d = 20;
var d = 15;
int n = (int)(HEIGHT / d) + 2;
_polyline = new Polyline() {
Points = [.. Enumerable.Range(0, n).SelectMany(i => new List<Point>() {
@@ -77,12 +80,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
Storyboard.SetTarget(slideUp, _polyline);
Storyboard.SetTargetProperty(slideUp, new PropertyPath(Canvas.TopProperty));
var clipCanvas = new Canvas() {
Width = WIDTH - 20,
Height = HEIGHT - 2,
Width = WIDTH - 15,
Height = HEIGHT - 8,
ClipToBounds = true,
};
clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 2);
clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 10);
clipCanvas.SetValue(Canvas.TopProperty, CenterY - HEIGHT / 2 + 4);
clipCanvas.SetValue(Canvas.LeftProperty, CenterX - WIDTH / 2 + 7.5);
clipCanvas.Children.Add(_polyline);
canvas.Children.Add(_rect);
@@ -97,12 +100,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
IsAnimationActive = IsActive;
_rect?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
@@ -16,25 +16,31 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsClickable { get; private set; }
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_auger?.IsActive = value;
_animationActive = value;
_auger?.IsAnimationActive = value;
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _inner;
private Shape? _outer;
private Auger? _auger;
private TextBlock? _text;
public EncasedAuger(string label, double x, double y, double angle = 0) {
public EncasedAuger(string label, double x, double y, Func<bool> cbActive, double angle = 0, bool clickable = true) {
CenterX = x;
CenterY = y;
Label = label;
Angle = angle;
CallbackActive = cbActive;
IsClickable = clickable;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -80,12 +86,14 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
isHovering = isHovering && IsClickable;
IsAnimationActive = IsActive;
_inner?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
+16 -11
View File
@@ -16,11 +16,12 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive {
get => _active;
public bool IsActive => CallbackActive();
public bool IsAnimationActive {
get => _animationActive;
set {
_active = value;
_auger?.IsActive = value;
_animationActive = value;
_auger?.IsAnimationActive = value;
if (value) {
_doorTransform?.BeginAnimation(
RotateTransform.AngleProperty,
@@ -41,7 +42,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
}
private bool _active;
protected Func<bool> CallbackActive;
private bool _animationActive;
private Shape? _inner;
private Shape? _outer;
private TextBlock? _text;
@@ -49,10 +52,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
private Shape? _door;
private RotateTransform? _doorTransform;
public EntryTrough(string label, double x, double y) {
public EntryTrough(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -99,12 +103,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPressed) {
IsAnimationActive = IsActive;
_inner?.Fill =
IsActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsActive && isHovering ? PamhagenBrushes.Red :
!IsActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsActive && isHovering ? PamhagenBrushes.Green :
IsActive ? PamhagenBrushes.Green :
IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Red :
IsAnimationActive && isHovering ? PamhagenBrushes.Red :
!IsAnimationActive && isHovering && isPressed ? PamhagenBrushes.Green :
!IsAnimationActive && isHovering ? PamhagenBrushes.Green :
IsAnimationActive ? PamhagenBrushes.Green :
Brushes.WhiteSmoke;
}
}
+20 -2
View File
@@ -15,14 +15,26 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public Brush? Highlight { get; set; }
public bool IsActive => CallbackActive();
public bool HasClearance => CallbackClearance();
public bool IsSelected => CallbackSelected(this);
protected Func<bool> CallbackActive;
protected Func<bool> CallbackClearance;
protected Func<Pump, bool> CallbackSelected;
private Shape? _circle;
private Shape? _triangle;
private TextBlock? _text;
public Pump(string label, double x, double y) {
public Pump(string label, double x, double y, Func<bool> cbActive, Func<bool> cbClearance, Func<Pump, bool> cbSelected) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
CallbackClearance = cbClearance;
CallbackSelected = cbSelected;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -63,7 +75,13 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
}
public void Update(bool isHovering, bool isPresed) {
_circle?.Fill = isHovering ? Brushes.LightGray : Brushes.WhiteSmoke;
_circle?.Fill = Highlight ?? (
IsActive && isHovering ? PamhagenBrushes.Red :
IsActive ? PamhagenBrushes.Green :
HasClearance && IsSelected && isHovering ? PamhagenBrushes.Green :
HasClearance && IsSelected ? PamhagenBrushes.Yellow :
IsSelected ? PamhagenBrushes.Red :
isHovering ? Brushes.LightGray : Brushes.WhiteSmoke);
}
}
}
+5 -2
View File
@@ -15,7 +15,9 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
public bool IsActive { get; set; }
public bool IsActive => CallbackActive();
protected Func<bool> CallbackActive;
private TextBlock? _text;
private Shape? _rect;
@@ -24,10 +26,11 @@ namespace PamhagenSysCtrl.Helpers.Pipeline {
private Shape? _bottomInner;
private Shape? _bottomOuter;
public Rebler(string label, double x, double y) {
public Rebler(string label, double x, double y, Func<bool> cbActive) {
CenterX = x;
CenterY = y;
Label = label;
CallbackActive = cbActive;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
@@ -0,0 +1,87 @@
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace PamhagenSysCtrl.Helpers.Pipeline {
public class Switcher : INode {
public const double WIDTH = 100;
public const double HEIGHT = 50;
public double CenterX { get; set; }
public double CenterY { get; set; }
public string Label { get; set; }
public ISet<IEdge> Inputs { get; init; }
public ISet<IEdge> Outputs { get; init; }
private Line? _main;
private Line? _shadow;
private RotateTransform? _mainTransform;
private RotateTransform? _shadowTransform;
protected Func<int> CallbackIsPosition;
protected Func<int> CallbackWantPosition;
public Switcher(string label, double x, double y, Func<int> cbIsPosition, Func<int> cbWantPosition) {
CenterX = x;
CenterY = y;
Label = label;
CallbackIsPosition = cbIsPosition;
CallbackWantPosition = cbWantPosition;
Inputs = new HashSet<IEdge>();
Outputs = new HashSet<IEdge>();
}
public void Draw(Canvas canvas) {
_mainTransform = new RotateTransform(0, CenterX, CenterY);
_shadowTransform = new RotateTransform(0, CenterX, CenterY);
_main = new Line() {
X1 = CenterX - WIDTH / 2, Y1 = CenterY,
X2 = CenterX + WIDTH / 2, Y2 = CenterY,
StrokeThickness = 5,
Stroke = Brushes.Black,
StrokeStartLineCap = PenLineCap.Square,
StrokeEndLineCap = PenLineCap.Square,
RenderTransform = _mainTransform,
};
_shadow = new Line() {
X1 = CenterX - WIDTH / 2, Y1 = CenterY,
X2 = CenterX + WIDTH / 2, Y2 = CenterY,
StrokeThickness = 5,
Stroke = Brushes.DarkGray,
StrokeStartLineCap = PenLineCap.Square,
StrokeEndLineCap = PenLineCap.Square,
RenderTransform = _shadowTransform,
};
canvas.Children.Add(_shadow);
canvas.Children.Add(_main);
}
public bool IsInside(double x, double y) {
return Math.Abs(x - CenterX) <= WIDTH / 2 && Math.Abs(y - CenterY) <= HEIGHT / 2;
}
public void Update(bool isHovering, bool isPressed) {
var isPos = CallbackIsPosition();
var wantPos = CallbackWantPosition();
if (isHovering && wantPos == isPos) wantPos = wantPos == 1 ? 2 : 1;
var target1 = isPos == 0 ? 0 : isPos == 1 ? 15 : -15;
var target2 = wantPos == 0 ? 0 : wantPos == 1 ? 15 : -15;
_mainTransform?.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation {
From = _mainTransform.Angle,
To = target1,
Duration = TimeSpan.FromSeconds(Math.Abs(_mainTransform.Angle - target1) / 120.0)
});
_shadowTransform?.BeginAnimation(
RotateTransform.AngleProperty,
new DoubleAnimation {
From = _shadowTransform.Angle,
To = target2,
Duration = TimeSpan.FromSeconds(Math.Abs(_shadowTransform.Angle - target2) / 120.0)
});
}
}
}
+3 -1
View File
@@ -7,10 +7,12 @@
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>App.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.10" />
<PackageReference Include="System.IO.Ports" Version="10.0.10" />
</ItemGroup>
</Project>
-278
View File
@@ -1,278 +0,0 @@
using PamhagenSysCtrl.Helpers;
using PamhagenSysCtrl.Windows;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace PamhagenSysCtrl {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
for (int i = 1; i <= 60; i++) {
var b = new Button() {
Content = $"V{i}",
Margin = new(10 + ((i - 1) / 10) * 50, 10 + ((i - 1) % 10) * 40, 10, 10),
BorderThickness = new(2),
FontWeight = FontWeights.Bold,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
Height = 30,
Width = 40,
FontSize = 14,
};
var borderStyle = new Style(typeof(Border));
borderStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5)));
b.Resources.Add(typeof(Border), borderStyle);
b.Click += (sender, evt) => {
if (App.Plant == null || sender is not Button b) return;
var i = int.Parse($"{b.Content}"[1..]);
if (i > 57) {
return;
} else if (App.Plant.WantValveOpen(i)) {
App.Plant.CloseV(i);
} else {
App.Plant.OpenV(i);
}
App.Plant.CommitChanges();
};
ValvePanel.Children.Add(b);
}
var w = new PlantSchemeWindow();
w.Show();
}
public async void ConnectButton_Click(object? sender, RoutedEventArgs evt) {
try {
App.Plant = new(PortInput.Text);
App.Plant.Update += OnUpdate;
await App.Plant.StartThread();
} catch (Exception exc) {
App.Plant?.Dispose();
App.Plant = null;
var str = $"Beim Aufbauen einer Verbindung zur SPS ist ein Fehler aufgetreten:\n\n{exc.GetType().Name}: {exc.Message}";
if (exc.InnerException != null) str += $"\n\n{exc.InnerException.GetType().Name}: {exc.InnerException.Message}";
MessageBox.Show(str, "SPS-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
public void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant plant) return;
for (int i = 1; i <= 60; i++) {
var target = plant.WantValveClosed(i);
var actual = plant.IsValveClosed(i);
if (ValvePanel.Children[i - 1] is not Button b)
continue;
b.BorderBrush = target ? Brushes.DarkRed : Brushes.SlateGray;
b.Foreground = target ? Brushes.DarkRed : Brushes.Black;
b.Background = actual ? Brushes.MistyRose : Brushes.WhiteSmoke;
}
ReblerButton.BorderBrush = plant.IsReblerActive ? Brushes.DarkGreen : Brushes.DarkRed;
ReblerButton.Foreground = plant.IsReblerActive ? Brushes.DarkGreen : Brushes.DarkRed;
ReblerButton.Background = plant.IsReblerActive ? Brushes.MintCream: Brushes.MistyRose;
TroughAugerButton.BorderBrush = plant.IsTroughAugerActive ? Brushes.DarkGreen : Brushes.DarkRed;
TroughAugerButton.Foreground = plant.IsTroughAugerActive ? Brushes.DarkGreen : Brushes.DarkRed;
TroughAugerButton.Background = plant.IsTroughAugerActive ? Brushes.MintCream : Brushes.MistyRose;
StirrerA1Button.BorderBrush = plant.IsStirrerA1Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerA1Button.Foreground = plant.IsStirrerA1Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerA1Button.Background = plant.IsStirrerA1Active ? Brushes.MintCream : Brushes.MistyRose;
StirrerA2Button.BorderBrush = plant.IsStirrerA2Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerA2Button.Foreground = plant.IsStirrerA2Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerA2Button.Background = plant.IsStirrerA2Active ? Brushes.MintCream : Brushes.MistyRose;
BeltButton.BorderBrush = plant.IsBeltActive ? Brushes.DarkGreen : Brushes.DarkRed;
BeltButton.Foreground = plant.IsBeltActive ? Brushes.DarkGreen : Brushes.DarkRed;
BeltButton.Background = plant.IsBeltActive ? Brushes.MintCream : Brushes.MistyRose;
Auger1Button.BorderBrush = plant.IsAuger1Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger1Button.Foreground = plant.IsAuger1Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger1Button.Background = plant.IsAuger1Active ? Brushes.MintCream : Brushes.MistyRose;
Auger2Button.BorderBrush = plant.IsAuger2Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger2Button.Foreground = plant.IsAuger2Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger2Button.Background = plant.IsAuger2Active ? Brushes.MintCream : Brushes.MistyRose;
GradationPumpButton.BorderBrush = plant.IsGradationPumpActive ? Brushes.DarkGreen : Brushes.DarkRed;
GradationPumpButton.Foreground = plant.IsGradationPumpActive ? Brushes.DarkGreen : Brushes.DarkRed;
GradationPumpButton.Background = plant.IsGradationPumpActive ? Brushes.MintCream : Brushes.MistyRose;
MP1BackwardButton.BorderBrush = plant.MP1 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1BackwardButton.Foreground = plant.MP1 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1BackwardButton.Background = plant.MP1 == MotorState.Backward ? Brushes.MintCream : Brushes.WhiteSmoke;
MP1HaltButton.BorderBrush = plant.MP1 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP1HaltButton.Foreground = plant.MP1 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP1HaltButton.Background = plant.MP1 == MotorState.Halt ? Brushes.MistyRose : Brushes.WhiteSmoke;
MP1ForwardButton.BorderBrush = plant.MP1 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1ForwardButton.Foreground = plant.MP1 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1ForwardButton.Background = plant.MP1 == MotorState.Forward ? Brushes.MintCream: Brushes.WhiteSmoke;
MP2BackwardButton.BorderBrush = plant.MP2 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2BackwardButton.Foreground = plant.MP2 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2BackwardButton.Background = plant.MP2 == MotorState.Backward ? Brushes.MintCream : Brushes.WhiteSmoke;
MP2HaltButton.BorderBrush = plant.MP2 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP2HaltButton.Foreground = plant.MP2 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP2HaltButton.Background = plant.MP2 == MotorState.Halt ? Brushes.MistyRose : Brushes.WhiteSmoke;
MP2ForwardButton.BorderBrush = plant.MP2 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2ForwardButton.Foreground = plant.MP2 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2ForwardButton.Background = plant.MP2 == MotorState.Forward ? Brushes.MintCream : Brushes.WhiteSmoke;
P12Button.BorderBrush = plant.P12 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P12Button.Foreground = plant.P12 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P12Button.Background = plant.P12 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
Status.Text = $"""
Gradation °Oe: {plant.GradationOe:N2}
Presse Querschnecke: {plant.PresseQuerSchnecke}
Füllstände:
Wanne A1: {plant.FillLevelA1} (ausgewählt: {plant.WantA1Selected}, Status: {plant.IsA1Selected})
Wanne A2: {plant.FillLevelA2} (ausgewählt: {plant.WantA2Selected}, Status: {plant.IsA2Selected})
Presse 1: {plant.FillLevelPress1}
Presse 2: {plant.FillLevelPress2}
Tank 1: {plant.FillLevelT1}
Tank 2: {plant.FillLevelT2}
Tank 3: {plant.FillLevelT3}
Tank 4: {plant.FillLevelT4}
Tank 5: {plant.FillLevelT5}
Tank 6: {plant.FillLevelT6}
Tank 7: {plant.FillLevelT7}
Tank 8: {plant.FillLevelT8}
Tank 9: {plant.FillLevelT9}
""";
}
private void TroughAugerButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsTroughAugerActive) {
App.Plant.StopTroughAuger();
} else {
App.Plant.StartTroughAuger();
}
App.Plant.CommitChanges();
}
private void ReblerButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsReblerActive) {
App.Plant.StopRebler();
} else {
App.Plant.StartRebler();
}
App.Plant.CommitChanges();
}
private void StirrerA1Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsStirrerA1Active) {
App.Plant.StopStirrerA1();
} else {
App.Plant.StartStirrerA1();
}
App.Plant.CommitChanges();
}
private void StirrerA2Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsStirrerA2Active) {
App.Plant.StopStirrerA2();
} else {
App.Plant.StartStirrerA2();
}
App.Plant.CommitChanges();
}
private void BeltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsBeltActive) {
App.Plant.StopBelt();
} else {
App.Plant.StartBelt();
}
App.Plant.CommitChanges();
}
private void Auger1Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsAuger1Active) {
App.Plant.StopAuger1();
} else {
App.Plant.StartAuger1();
}
App.Plant.CommitChanges();
}
private void Auger2Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsAuger2Active) {
App.Plant.StopAuger2();
} else {
App.Plant.StartAuger2();
}
App.Plant.CommitChanges();
}
private void GradationPumpButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.IsGradationPumpActive) {
App.Plant.StopGradationPump();
} else {
App.Plant.StartGradationPump();
}
App.Plant.CommitChanges();
}
private void MP1BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP1Backward();
App.Plant.CommitChanges();
}
private void MP1HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StopMP1();
App.Plant.CommitChanges();
}
private void MP1ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP1Forward();
App.Plant.CommitChanges();
}
private void MP2BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP2Backward();
App.Plant.CommitChanges();
}
private void MP2HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StopMP2();
App.Plant.CommitChanges();
}
private void MP2ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
App.Plant.StartMP2Forward();
App.Plant.CommitChanges();
}
private void P12Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
if (App.Plant.P12 == MotorState.Forward) {
App.Plant.StopP12();
} else {
App.Plant.StartP12();
}
App.Plant.CommitChanges();
}
}
}
@@ -1,19 +1,13 @@
<Window x:Class="PamhagenSysCtrl.MainWindow"
<Window x:Class="PamhagenSysCtrl.ManualControlWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PamhagenSysCtrl"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="860">
Title="Manuelle Steuerung - Anlagensteuerung Pamhagen" Height="550" Width="860">
<Grid>
<TextBox x:Name="PortInput" Text="COM1"
Margin="10,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" Height="25" Width="80" FontSize="14" Padding="2,2,2,2"/>
<Button x:Name="ConnectButton" Content="Verbinden"
Margin="100,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" Height="25" Width="80" FontSize="14"
Click="ConnectButton_Click"/>
<Grid x:Name="ValvePanel" Margin="5,50,5,5">
<Grid x:Name="ValvePanel" Margin="5,5,5,5">
</Grid>
<TextBlock x:Name="Status" FontSize="14"
@@ -31,66 +25,75 @@
Margin="10,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="ReblerButton_Click"/>
<Button x:Name="StirrerA1Button" Content="Rührer A1" Padding="2" Height="30" Width="120"
<Button x:Name="StirrerMW1Button" Content="Rührer MW1" Padding="2" Height="30" Width="120"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="10,80,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="StirrerA1Button_Click"/>
Click="StirrerMW1Button_Click"/>
<Button x:Name="StirrerA2Button" Content="Rührer A2" Padding="2" Height="30" Width="120"
<Button x:Name="StirrerMW2Button" Content="Rührer MW2" Padding="2" Height="30" Width="120"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="10,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="StirrerA2Button_Click"/>
<Button x:Name="BeltButton" Content="Förderband" Padding="2" Height="30" Width="150"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="135,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="BeltButton_Click"/>
Click="StirrerMW2Button_Click"/>
<Button x:Name="Auger1Button" Content="Förderschnecke 1" Padding="2" Height="30" Width="150"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="135,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="135,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="Auger1Button_Click"/>
<Button x:Name="BeltButton" Content="Förderband" Padding="2" Height="30" Width="150"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="135,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="BeltButton_Click"/>
<Button x:Name="Auger2Button" Content="Förderschnecke 2" Padding="2" Height="30" Width="150"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="135,80,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="Auger2Button_Click"/>
<Button x:Name="GradationPumpButton" Content="Gradationspumpe" Padding="2" Height="30" Width="150"
<Button x:Name="P6Button" Content="Pumpe 6" Padding="2" Height="30" Width="150"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="135,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="GradationPumpButton_Click"/>
<Button x:Name="MP1ForwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
Click="P6Button_Click"/>
<Button x:Name="MP1BackwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1ForwardButton_Click"/>
Click="MP1BackwardButton_Click"/>
<Button x:Name="MP1HaltButton" Content="MP1" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1HaltButton_Click"/>
<Button x:Name="MP1BackwardButton" Content="Vor" Padding="2" Height="30" Width="60"
<Button x:Name="MP1ForwardButton" Content="Vor" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP1BackwardButton_Click"/>
Click="MP1ForwardButton_Click"/>
<Button x:Name="MP2ForwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
<Button x:Name="MP2BackwardButton" Content="Zurück" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2ForwardButton_Click"/>
Click="MP2BackwardButton_Click"/>
<Button x:Name="MP2HaltButton" Content="MP2" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="350,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2HaltButton_Click"/>
<Button x:Name="MP2BackwardButton" Content="Vor" Padding="2" Height="30" Width="60"
<Button x:Name="MP2ForwardButton" Content="Vor" Padding="2" Height="30" Width="60"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="410,45,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="MP2BackwardButton_Click"/>
Click="MP2ForwardButton_Click"/>
<Button x:Name="P12Button" Content="Pumpe 1/2" Padding="2" Height="30" Width="180"
<Button x:Name="P12Button" Content="Pumpe 1/2" Padding="2" Height="30" Width="87.5"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,80,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="P12Button_Click"/>
<Button x:Name="P3Button" Content="Pumpe 3" Padding="2" Height="30" Width="87.5"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="382.5,80,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="P3Button_Click"/>
<Button x:Name="P4Button" Content="Pumpe 4" Padding="2" Height="30" Width="87.5"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="290,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="P4Button_Click"/>
<Button x:Name="P5Button" Content="Pumpe 5" Padding="2" Height="30" Width="87.5"
FontSize="14" BorderThickness="2" FontWeight="Bold"
Margin="382.5,115,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Click="P5Button_Click"/>
</Grid>
</Grid>
</Window>
@@ -0,0 +1,362 @@
using PamhagenSysCtrl.Helpers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace PamhagenSysCtrl {
public partial class ManualControlWindow : Window {
public ManualControlWindow() {
InitializeComponent();
for (int i = 1; i <= 58; i++) {
var b = new Button() {
Content = $"V{i}",
Margin = new(10 + ((i - 1) / 10) * 50, 10 + ((i - 1) % 10) * 40, 10, 10),
BorderThickness = new(2),
FontWeight = FontWeights.Bold,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
Height = 30,
Width = 40,
FontSize = 14,
};
var borderStyle = new Style(typeof(Border));
borderStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5)));
b.Resources.Add(typeof(Border), borderStyle);
b.Click += (sender, evt) => {
if (App.Plant == null || sender is not Button b) return;
var i = int.Parse($"{b.Content}"[1..]);
if (i == 58) {
if (App.Plant.WantMW1Selected) {
App.Plant.SelectMW2();
} else {
App.Plant.SelectMW1();
}
} else if (i > 57) {
return;
} else if (App.Plant.WantValveOpen(i)) {
App.Plant.CloseV(i);
} else {
App.Plant.OpenV(i);
}
};
ValvePanel.Children.Add(b);
}
App.Plant?.Update += OnUpdate;
}
public void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant plant) return;
for (int i = 1; i <= 58; i++) {
var target = plant.WantValveClosed(i);
var actual = plant.IsValveClosed(i);
if (ValvePanel.Children[i - 1] is not Button b)
continue;
b.BorderBrush = target ? Brushes.DarkRed : Brushes.DarkGreen;
b.Foreground = target ? Brushes.DarkRed : Brushes.DarkGreen;
b.Background = actual ? Brushes.MistyRose : Brushes.MintCream;
}
ReblerButton.BorderBrush = plant.IsReblerActive ? Brushes.DarkGreen : Brushes.DarkRed;
ReblerButton.Foreground = plant.IsReblerActive ? Brushes.DarkGreen : Brushes.DarkRed;
ReblerButton.Background = plant.IsReblerActive ? Brushes.MintCream: Brushes.MistyRose;
TroughAugerButton.BorderBrush = plant.IsTroughAugerActive ? Brushes.DarkGreen : Brushes.DarkRed;
TroughAugerButton.Foreground = plant.IsTroughAugerActive ? Brushes.DarkGreen : Brushes.DarkRed;
TroughAugerButton.Background = plant.IsTroughAugerActive ? Brushes.MintCream : Brushes.MistyRose;
StirrerMW1Button.BorderBrush = plant.IsStirrerMW1Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerMW1Button.Foreground = plant.IsStirrerMW1Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerMW1Button.Background = plant.IsStirrerMW1Active ? Brushes.MintCream : Brushes.MistyRose;
StirrerMW2Button.BorderBrush = plant.IsStirrerMW2Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerMW2Button.Foreground = plant.IsStirrerMW2Active ? Brushes.DarkGreen : Brushes.DarkRed;
StirrerMW2Button.Background = plant.IsStirrerMW2Active ? Brushes.MintCream : Brushes.MistyRose;
BeltButton.BorderBrush = plant.IsBeltActive ? Brushes.DarkGreen : Brushes.DarkRed;
BeltButton.Foreground = plant.IsBeltActive ? Brushes.DarkGreen : Brushes.DarkRed;
BeltButton.Background = plant.IsBeltActive ? Brushes.MintCream : Brushes.MistyRose;
Auger1Button.BorderBrush = plant.IsAuger1Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger1Button.Foreground = plant.IsAuger1Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger1Button.Background = plant.IsAuger1Active ? Brushes.MintCream : Brushes.MistyRose;
Auger2Button.BorderBrush = plant.IsAuger2Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger2Button.Foreground = plant.IsAuger2Active ? Brushes.DarkGreen : Brushes.DarkRed;
Auger2Button.Background = plant.IsAuger2Active ? Brushes.MintCream : Brushes.MistyRose;
MP1BackwardButton.BorderBrush = plant.MP1 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1BackwardButton.Foreground = plant.MP1 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1BackwardButton.Background = plant.MP1 == MotorState.Backward ? Brushes.MintCream : Brushes.WhiteSmoke;
MP1HaltButton.BorderBrush = plant.MP1 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP1HaltButton.Foreground = plant.MP1 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP1HaltButton.Background = plant.MP1 == MotorState.Halt ? Brushes.MistyRose : Brushes.WhiteSmoke;
MP1ForwardButton.BorderBrush = plant.MP1 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1ForwardButton.Foreground = plant.MP1 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP1ForwardButton.Background = plant.MP1 == MotorState.Forward ? Brushes.MintCream: Brushes.WhiteSmoke;
MP2BackwardButton.BorderBrush = plant.MP2 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2BackwardButton.Foreground = plant.MP2 == MotorState.Backward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2BackwardButton.Background = plant.MP2 == MotorState.Backward ? Brushes.MintCream : Brushes.WhiteSmoke;
MP2HaltButton.BorderBrush = plant.MP2 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP2HaltButton.Foreground = plant.MP2 == MotorState.Halt ? Brushes.DarkRed : Brushes.SlateGray;
MP2HaltButton.Background = plant.MP2 == MotorState.Halt ? Brushes.MistyRose : Brushes.WhiteSmoke;
MP2ForwardButton.BorderBrush = plant.MP2 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2ForwardButton.Foreground = plant.MP2 == MotorState.Forward ? Brushes.DarkGreen : Brushes.SlateGray;
MP2ForwardButton.Background = plant.MP2 == MotorState.Forward ? Brushes.MintCream : Brushes.WhiteSmoke;
P12Button.BorderBrush = plant.P12 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P12Button.Foreground = plant.P12 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P12Button.Background = plant.P12 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
P3Button.BorderBrush = plant.P3 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P3Button.Foreground = plant.P3 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P3Button.Background = plant.P3 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
P4Button.BorderBrush = plant.P4 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P4Button.Foreground = plant.P4 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P4Button.Background = plant.P4 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
P5Button.BorderBrush = plant.P5 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P5Button.Foreground = plant.P5 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P5Button.Background = plant.P5 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
P6Button.BorderBrush = plant.P6 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P6Button.Foreground = plant.P6 == MotorState.Forward ? Brushes.DarkGreen : Brushes.DarkRed;
P6Button.Background = plant.P6 == MotorState.Forward ? Brushes.MintCream : Brushes.MistyRose;
Status.Text = $"""
Gradation °Oe: {plant.GradationOe:N2}
Presse Querschnecke: {plant.PresseQuerSchnecke}
Füllstände:
Maischewanne 1: {plant.FillLevelMW1} (ausgewählt: {plant.WantMW1Selected}, Status: {plant.IsMWSelected})
Maischewanne 2: {plant.FillLevelMW2} (ausgewählt: {plant.WantMW2Selected}, Status: {plant.IsMW2Selected})
Presse 1: {plant.FillLevelPress1}
Presse 2: {plant.FillLevelPress2}
Tank 1: {plant.FillLevelT1}
Tank 2: {plant.FillLevelT2}
Tank 3: {plant.FillLevelT3}
Tank 4: {plant.FillLevelT4}
Tank 5: {plant.FillLevelT5}
Tank 6: {plant.FillLevelT6}
Tank 7: {plant.FillLevelT7}
Tank 8: {plant.FillLevelT8}
Tank 9: {plant.FillLevelT9}
""";
}
private void TroughAugerButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsTroughAugerActive) {
App.Plant.StopTroughAuger();
} else {
App.Plant.StartTroughAuger();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ReblerButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsReblerActive) {
App.Plant.StopRebler();
} else {
App.Plant.StartRebler();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void StirrerMW1Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsStirrerMW1Active) {
App.Plant.StopStirrerMW1();
} else {
App.Plant.StartStirrerMW1();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void StirrerMW2Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsStirrerMW2Active) {
App.Plant.StopStirrerMW2();
} else {
App.Plant.StartStirrerMW2();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void BeltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsBeltActive) {
App.Plant.StopBelt();
} else {
App.Plant.StartBelt();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void Auger1Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsAuger1Active) {
App.Plant.StopAuger1();
} else {
App.Plant.StartAuger1();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void Auger2Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.IsAuger2Active) {
App.Plant.StopAuger2();
} else {
App.Plant.StartAuger2();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP1BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StartMP1Backward();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP1HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StopMP1();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP1ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StartMP1Forward();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP2BackwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StartMP2Backward();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP2HaltButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StopMP2();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MP2ForwardButton_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
App.Plant.StartMP2Forward();
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void P12Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.P12 == MotorState.Forward) {
App.Plant.StopP12();
} else {
App.Plant.StartP12();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void P3Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.P3 == MotorState.Forward) {
App.Plant.StopP3();
} else {
App.Plant.StartP3();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void P4Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.P4 == MotorState.Forward) {
App.Plant.StopP4();
} else {
App.Plant.StartP4();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void P5Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.P5 == MotorState.Forward) {
App.Plant.StopP5();
} else {
App.Plant.StartP5();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void P6Button_Click(object? sender, RoutedEventArgs? evt) {
if (App.Plant == null) return;
try {
if (App.Plant.P6 == MotorState.Forward) {
App.Plant.StopP6();
} else {
App.Plant.StartP6();
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
+45 -4
View File
@@ -4,10 +4,51 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PamhagenSysCtrl.Windows"
Title="Schema - Anlagensteuerung Pamhagen" Height="900" Width="1600" MinWidth="1500" MinHeight="900">
Title="Anlagensteuerung Pamhagen" Height="950" Width="1600" MinWidth="1500" MinHeight="950">
<Grid>
<Canvas x:Name="SchemeCanvas" Width="1550" Height="900" VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="True"
MouseMove="SchemeCanvas_MouseMove" MouseLeftButtonDown="SchemeCanvas_MouseLeftButtonDown" MouseLeftButtonUp="SchemeCanvas_MouseLeftButtonUp">
</Canvas>
<Grid.RowDefinitions>
<RowDefinition Height="19"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
<MenuItem Header="Einstellungen">
<MenuItem x:Name="Menu_Settings_ManualControl" Header="Manuelle Steuerung" Click="Menu_Settings_ManualControl_Click">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xF271;"/>
</MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem x:Name="Menu_Settings_Config" Header="Konfigurationsdatei öffnen..." Click="Menu_Settings_Config_Click">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xEC7A;"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="Menu_Settings_Directory" Header="Konfigurationsspeicherort öffnen..." Click="Menu_Settings_Directory_Click">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xED25;"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Hilfe">
<MenuItem Header="Über">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE946;"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
<Grid Grid.Row="1" ClipToBounds="True">
<Canvas x:Name="SchemeCanvas" Width="1550" Height="900" VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="True"
MouseMove="SchemeCanvas_MouseMove" MouseLeftButtonDown="SchemeCanvas_MouseLeftButtonDown" MouseLeftButtonUp="SchemeCanvas_MouseLeftButtonUp" Grid.ColumnSpan="2" Margin="25,0,0,0">
</Canvas>
</Grid>
<StatusBar Grid.Row="2" BorderThickness="0,1,0,0" BorderBrush="Gray">
</StatusBar>
</Grid>
</Window>
+137 -20
View File
@@ -1,5 +1,6 @@
using PamhagenSysCtrl.Helpers;
using PamhagenSysCtrl.Helpers.Pipeline;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
@@ -11,6 +12,7 @@ namespace PamhagenSysCtrl.Windows {
private ISource? _lastSource;
private List<INode> _path = [];
private ISet<INode>? _lastSelected;
private ISet<INode>? _hover;
public PlantSchemeWindow() {
InitializeComponent();
@@ -19,6 +21,28 @@ namespace PamhagenSysCtrl.Windows {
Graph.Draw(SchemeCanvas);
}
private void Menu_Settings_ManualControl_Click(object sender, RoutedEventArgs evt) {
var w = new ManualControlWindow();
w.Show();
}
private void Menu_Settings_Directory_Click(object sender, RoutedEventArgs evt) {
try {
Process.Start("explorer.exe", App.DataPath);
} catch { }
}
private void Menu_Settings_Config_Click(object sender, RoutedEventArgs evt) {
try {
Process.Start(new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = App.ConfigPath,
Verb = "runas",
UseShellExecute = true,
});
} catch { }
}
private void SchemeCanvas_MouseMove(object sender, MouseEventArgs evt) {
var p = evt.GetPosition(SchemeCanvas);
UpdateScheme(evt.GetPosition(SchemeCanvas), evt.LeftButton == MouseButtonState.Pressed);
@@ -39,7 +63,9 @@ namespace PamhagenSysCtrl.Windows {
foreach (var c in clicked) {
if (_lastSource == null && Graph.SelectedPaths.Any(p => p.Start == c)) {
var path = Graph.SelectedPaths.First(p => p.Start == c);
Graph.RemovePath(path);
if (!path.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false)) {
Graph.RemovePath(path);
}
} else if (_lastSource != null && c is ISink sink) {
var res = Graph.GetPath([_lastSource, .._path, sink], (n) => n is not ISink && (n is not Valve v || !v.IsLocked));
if (res is Path path) {
@@ -57,14 +83,92 @@ namespace PamhagenSysCtrl.Windows {
} else {
_lastSource = null;
}
if (c is EntryTrough trough) {
trough.IsActive = !trough.IsActive;
} else if (c is Rebler rebler) {
rebler.IsActive = !rebler.IsActive;
} else if (c is EncasedAuger auger) {
auger.IsActive = !auger.IsActive;
} else if (c is ConveyorBelt belt) {
belt.IsActive = !belt.IsActive;
try {
if (c is EntryTrough trough) {
if (trough.IsActive) {
App.Plant?.StopTroughAuger();
} else {
App.Plant?.StartTroughAuger();
}
} else if (c is Rebler rebler) {
if (rebler.IsActive) {
App.Plant?.StopRebler();
} else {
App.Plant?.StartRebler();
}
} else if (c is Switcher switcher) {
if (App.Plant?.WantMW1Selected ?? false) {
App.Plant?.SelectMW2();
} else {
App.Plant?.SelectMW1();
}
} else if (c is EncasedAuger auger) {
if (auger == Graph.Auger1) {
if (auger.IsActive) {
App.Plant?.StopAuger1();
} else {
App.Plant?.StartAuger1();
}
} else if (auger == Graph.Auger2) {
if (auger.IsActive) {
App.Plant?.StopAuger2();
} else {
App.Plant?.StartAuger2();
}
}
} else if (c is ConveyorBelt belt) {
if (belt.IsActive) {
App.Plant?.StopBelt();
} else {
App.Plant?.StartBelt();
}
} else if (c is Pump pump) {
if (pump == Graph.MP1) {
if (pump.IsActive) {
App.Plant?.StopMP1();
} else {
App.Plant?.StartMP1Forward();
}
} else if (pump == Graph.MP2) {
if (pump.IsActive) {
App.Plant?.StopMP2();
} else {
App.Plant?.StartMP2Forward();
}
} else if (pump == Graph.P12) {
if (pump.IsActive) {
App.Plant?.StopP12();
} else {
App.Plant?.StartP12();
}
} else if (pump == Graph.P3) {
if (pump.IsActive) {
App.Plant?.StopP3();
} else {
App.Plant?.StartP3();
}
} else if (pump == Graph.P4) {
if (pump.IsActive) {
App.Plant?.StopP4();
} else {
App.Plant?.StartP4();
}
} else if (pump == Graph.P5) {
if (pump.IsActive) {
App.Plant?.StopP5();
} else {
App.Plant?.StartP5();
}
} else if (pump == Graph.P6) {
if (pump.IsActive) {
App.Plant?.StopP6();
} else {
App.Plant?.StartP6();
}
}
}
} catch (NoClearanceException exc) {
MessageBox.Show($"{exc.Message}", "Keine Freigabe", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
UpdateScheme(pos, evt.LeftButton == MouseButtonState.Pressed);
@@ -75,14 +179,19 @@ namespace PamhagenSysCtrl.Windows {
e.Highlight = null;
e.Flow = null;
}
foreach (var p in Graph.SelectedPaths) {
Graph.ColorPipesAdjacientToPath(p, PamhagenBrushes.Green, true, PamhagenBrushes.DimOrange);
foreach (var n in Graph.Nodes) {
if (n is Pump p) {
p.Highlight = null;
}
}
var hover = Graph.GetHover(pos.X, pos.Y);
if (_lastSource != null && (hover.Count > 0 || _path.Count > 0)) {
foreach (var p in Graph.SelectedPaths) {
Graph.ColorPipesAdjacientToPath(p, PamhagenBrushes.Green, p.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false), PamhagenBrushes.DimOrange);
}
_hover = Graph.GetHover(pos.X, pos.Y);
if (_lastSource != null && (_hover.Count > 0 || _path.Count > 0)) {
List<INode> points = [_lastSource, .. _path];
if (hover.Count > 0 && !points.Contains(hover.First())) {
points.Add(hover.First());
if (_hover.Count > 0 && !points.Contains(_hover.First())) {
points.Add(_hover.First());
}
if (points.Count >= 2) {
var res = Graph.GetPath(points, (n) => n is not ISink && (n is not Valve v || !v.IsLocked));
@@ -90,21 +199,29 @@ namespace PamhagenSysCtrl.Windows {
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Green, false, PamhagenBrushes.DimOrange);
}
}
} else if (_lastSource == null && hover.Count > 0 && Graph.SelectedPaths.Any(p => p.Start == hover.First())) {
var path = Graph.SelectedPaths.First(p => p.Start == hover.First());
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Red, true, null);
} else if (_lastSource == null && _hover.Count > 0 && Graph.SelectedPaths.Any(p => p.Start == _hover.First())) {
var path = Graph.SelectedPaths.First(p => p.Start == _hover.First());
var pumpActive = path.Hops.Any(h => (h.Node as Pump)?.IsActive ?? false);
if (pumpActive) {
foreach (var pump in path.Hops.Select(h => h.Node as Pump).Where(p => p != null)) {
pump?.Highlight = PamhagenBrushes.Red;
}
} else {
Graph.ColorPipesAdjacientToPath(path, PamhagenBrushes.Red, false, null);
}
}
if (_lastSource != null) {
foreach (var edge in _lastSource.Outputs) {
edge.Highlight = PamhagenBrushes.Green;
}
}
Graph.Update(hover, down);
return hover;
Graph.Update(_hover, down);
return _hover;
}
public void OnUpdate(object? sender, PlantEventArgs evt) {
if (sender is not PamhagenPlant plant) return;
UpdateScheme(Mouse.GetPosition(SchemeCanvas), Mouse.LeftButton == MouseButtonState.Pressed);
}
}
}