From 50f6174af1b87261c5c31b9b5efa17b2d07d72c5 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Fri, 6 Nov 2026 09:49:23 +0100 Subject: [PATCH] Implement remaining XBE-24 and stirrer keys --- Installer/Files/config.ini | 8 +- PamhagenSysCtrl/Helpers/Config.cs | 4 + PamhagenSysCtrl/Helpers/Extensions.cs | 4 + PamhagenSysCtrl/Helpers/FillState.cs | 2 +- PamhagenSysCtrl/Helpers/PamhagenBrushes.cs | 15 + PamhagenSysCtrl/Helpers/PamhagenGraph.cs | 6 +- PamhagenSysCtrl/Helpers/PamhagenPlant.cs | 372 +++++++++++++++--- PamhagenSysCtrl/Helpers/Pipeline/ISink.cs | 1 + PamhagenSysCtrl/Helpers/Pipeline/Press.cs | 5 +- PamhagenSysCtrl/Helpers/Pipeline/Tank.cs | 5 +- .../Helpers/Plc/LegacyPamhagenPlc.cs | 2 +- PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs | 42 +- PamhagenSysCtrl/Helpers/Plc/PamhagenState.cs | 48 ++- PamhagenSysCtrl/Helpers/Xbe24Keyboard.cs | 2 + 14 files changed, 438 insertions(+), 78 deletions(-) diff --git a/Installer/Files/config.ini b/Installer/Files/config.ini index 8fa0152..390e71d 100644 --- a/Installer/Files/config.ini +++ b/Installer/Files/config.ini @@ -1,8 +1,12 @@ [plc] port = COM1 -sensor_delay_open = 0 ; seconds -sensor_delay_close = 2 ; seconds +; sensor delay in seconds +sensor_delay_open = 0 +sensor_delay_close = 2 +sensor_delay_mw = 10 +; from which filling level on does the stirrer start (or stop when below) automatically when pumping +auto_stirrer = Half [update] url = https://elwig.at/files/pamhagen-sysctrl/latest diff --git a/PamhagenSysCtrl/Helpers/Config.cs b/PamhagenSysCtrl/Helpers/Config.cs index 1a62160..7ffde28 100644 --- a/PamhagenSysCtrl/Helpers/Config.cs +++ b/PamhagenSysCtrl/Helpers/Config.cs @@ -11,6 +11,8 @@ namespace PamhagenSysCtrl.Helpers { public string PlcPort = "COM1"; public int PlcSensorDelayOpen = 0; public int PlcSensorDelayClose = 0; + public int PlcSensorDelayMW = 0; + public FillState PlcAutoStirrer = FillState.Half; public string? UpdateUrl; public bool UpdateAuto; @@ -28,6 +30,8 @@ namespace PamhagenSysCtrl.Helpers { PlcPort = config["plc:port"] ?? "COM1"; PlcSensorDelayOpen = int.Parse(config["plc:sensor_delay_open"] ?? "0"); PlcSensorDelayClose = int.Parse(config["plc:sensor_delay_close"] ?? "0"); + PlcSensorDelayMW = int.Parse(config["plc:sensor_delay_mw"] ?? "0"); + PlcAutoStirrer = Enum.Parse(config["plc:auto_stirrer"] ?? "Half"); UpdateUrl = config["update:url"]; UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower()); var xbe24 = config.GetSection("xbe24"); diff --git a/PamhagenSysCtrl/Helpers/Extensions.cs b/PamhagenSysCtrl/Helpers/Extensions.cs index 73de93c..4e2cc98 100644 --- a/PamhagenSysCtrl/Helpers/Extensions.cs +++ b/PamhagenSysCtrl/Helpers/Extensions.cs @@ -3,6 +3,10 @@ using System.Drawing; namespace PamhagenSysCtrl.Helpers { public static class Extensions { + public static void SetBacklight(this Xbe24Keyboard k, PamhagenPlant.ShortcutKey key, (Color Color, bool Flashing) state) { + k.SetBacklight(key, state.Color, state.Flashing); + } + public static void SetBacklight(this Xbe24Keyboard k, PamhagenPlant.ShortcutKey key, Color color, bool flashing = false) { if (App.Config.MapKey(key) is int n) k.SetBacklight(n, color, flashing); diff --git a/PamhagenSysCtrl/Helpers/FillState.cs b/PamhagenSysCtrl/Helpers/FillState.cs index 4ea5376..56d8cbb 100644 --- a/PamhagenSysCtrl/Helpers/FillState.cs +++ b/PamhagenSysCtrl/Helpers/FillState.cs @@ -1,3 +1,3 @@ namespace PamhagenSysCtrl.Helpers { - public enum FillState { Empty = 0, Filled = 1, Half = 2, Full = 3, Invalid = -1, Unknown = -2 } + public enum FillState { Unknown = 0, Empty = 1, Filled = 2, Quarter = 3, Half = 4, ThreeQuarter = 5, AlmostFull = 6, Full = 7, Invalid = -1 } } diff --git a/PamhagenSysCtrl/Helpers/PamhagenBrushes.cs b/PamhagenSysCtrl/Helpers/PamhagenBrushes.cs index 8df9855..0fbc6e5 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenBrushes.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenBrushes.cs @@ -16,7 +16,10 @@ namespace PamhagenSysCtrl.Helpers { return state switch { FillState.Empty => GetEmpty(background), FillState.Filled => GetFilled(background), + FillState.Quarter => GetQuarter(background), FillState.Half => GetHalf(background), + FillState.ThreeQuarter => GetThreeQuarter(background), + FillState.AlmostFull => GetAlmostFull(background), FillState.Full => GetFull(background), _ => GetEmpty(background), }; @@ -34,10 +37,22 @@ namespace PamhagenSysCtrl.Helpers { return new LinearGradientBrush(background, Green.Color, new(0.5, 0.875 - TRANSITION), new(0.5, 0.875 + TRANSITION)); } + public static Brush GetQuarter(Color background) { + return new LinearGradientBrush(background, Green.Color, new(0.5, 0.75 - TRANSITION), new(0.5, 0.75 + TRANSITION)); + } + public static Brush GetHalf(Color background) { return new LinearGradientBrush(background, Green.Color, new(0.5, 0.5 - TRANSITION), new(0.5, 0.5 + TRANSITION)); } + public static Brush GetThreeQuarter(Color background) { + return new LinearGradientBrush(background, Green.Color, new(0.5, 0.25 - TRANSITION), new(0.5, 0.25 + TRANSITION)); + } + + public static Brush GetAlmostFull(Color background) { + return new LinearGradientBrush(background, Green.Color, new(0.5, 0.125 - TRANSITION), new(0.5, 0.125 + TRANSITION)); + } + public static Brush GetFull(Color background) { return new LinearGradientBrush(background, Red.Color, new(0.5, 0.0625 - TRANSITION), new(0.5, 0.0625 + TRANSITION)); } diff --git a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs index d5851df..2b4526f 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenGraph.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenGraph.cs @@ -367,8 +367,8 @@ namespace PamhagenSysCtrl.Helpers { var prX = (pr1X + pr2X) / 2; var pr1cX = prX - 3; var pr2cX = prX + 3; - Press1 = new Press("Presse 1", pr1X, prY, 20000, () => FillState.Unknown); - Press2 = new Press("Presse 2", pr2X, prY, 15000, () => FillState.Unknown); + Press1 = new Press("Presse 1", pr1X, prY, 20000, () => FillState.Unknown, () => App.Plant?.State.Press1_HasClearance ?? false); + Press2 = new Press("Presse 2", pr2X, prY, 15000, () => FillState.Unknown, () => App.Plant?.State.Press2_HasClearance ?? false); var v50 = CreateValve(50, pr2cX + 6, ltg3Y, 1); var v51 = CreateValve(51, pr1cX - 6, ltg3Y, 1); var v52 = CreateValve(52, pr1cX - 6, ltg4Y, 3); @@ -492,7 +492,7 @@ namespace PamhagenSysCtrl.Helpers { } protected static Tank CreateTank(int n, double x, double y, int capacity) { - return new($"Tank {n}", x, y, capacity, () => App.Plant?.State.Tanks_FillLevel[n - 1] ?? FillState.Unknown); + return new($"Tank {n}", x, y, capacity, () => App.Plant?.State.Tanks_FillLevel[n - 1] ?? FillState.Unknown, () => true); } private int PathCost(Path p) { diff --git a/PamhagenSysCtrl/Helpers/PamhagenPlant.cs b/PamhagenSysCtrl/Helpers/PamhagenPlant.cs index 60c616c..110aa96 100644 --- a/PamhagenSysCtrl/Helpers/PamhagenPlant.cs +++ b/PamhagenSysCtrl/Helpers/PamhagenPlant.cs @@ -16,8 +16,6 @@ namespace PamhagenSysCtrl.Helpers { START_TROUGH_AUGER, STOP_TROUGH_AUGER, TOGGLE_TROUGH_AUGER, INDICATE_TROUGH_AUGER, SELECT_MW1, INDICATE_MW1_SELECTED, SELECT_MW2, INDICATE_MW2_SELECTED, - INDICATE_MW1, INDICATE_MW1_EMPTY, INDICATE_MW1_FILLED, INDICATE_MW1_HALF, INDICATE_MW1_FULL, - INDICATE_MW2, INDICATE_MW2_EMPTY, INDICATE_MW2_FILLED, INDICATE_MW2_HALF, INDICATE_MW2_FULL, START_STIRRER_MW1, STOP_STIRRER_MW1, TOGGLE_STIRRER_MW1, INDICATE_STIRRER_MW1, START_STIRRER_MW2, STOP_STIRRER_MW2, TOGGLE_STIRRER_MW2, INDICATE_STIRRER_MW2, START_MP1, STOP_MP1, TOGGLE_MP1, INDICATE_MP1, @@ -97,7 +95,7 @@ namespace PamhagenSysCtrl.Helpers { PlcThread = null; PamhagenPlc? tmp = null; try { - tmp = new PamhagenPlc(PlcComPort, App.Config.PlcSensorDelayOpen * 1000, App.Config.PlcSensorDelayClose * 1000); + tmp = new PamhagenPlc(PlcComPort, App.Config.PlcSensorDelayOpen * 1000, App.Config.PlcSensorDelayClose * 1000, App.Config.PlcSensorDelayMW * 1000); await tmp.Initialize(); Plc = tmp; PlcConnectionError = null; @@ -147,50 +145,179 @@ namespace PamhagenSysCtrl.Helpers { App.MainDispatcher?.BeginInvoke(() => Update?.Invoke(this, evt)); } + private static void UpdatePumpKeys(Xbe24Keyboard k, ShortcutKey start, ShortcutKey stop, ShortcutKey toggle, ShortcutKey indicate, PamhagenState.PumpState state, bool highlightOff, bool directControl) { + var waiting = !state.HasPathClearance && state.HasDryRunClearance && state.WantsPathClearance; + k.SetBacklight(start, + state.State == MotorState.Forward ? (Xbe24Keyboard.Green, false) : + state.State == MotorState.Backward ? (Xbe24Keyboard.Lime, true) : + waiting && state.WantActive ? (Xbe24Keyboard.Green, true) : + waiting && !state.WantActive ? (Xbe24Keyboard.LightGreen, true) : + state.HasClearance ? (Xbe24Keyboard.LightGreen, false) : + k.IsKeyPressed(start) ? (Xbe24Keyboard.Orange, false) : + (Xbe24Keyboard.LightRed, false)); + k.SetBacklight(stop, + highlightOff ? Xbe24Keyboard.Orange : + !state.IsActive ? Xbe24Keyboard.Red : + Xbe24Keyboard.LightRed); + k.SetBacklight(toggle, + highlightOff ? (Xbe24Keyboard.Orange, false) : + state.State == MotorState.Forward ? (Xbe24Keyboard.Green, false) : + state.State == MotorState.Backward ? (Xbe24Keyboard.Lime, true) : + waiting && state.WantActive ? (Xbe24Keyboard.Green, true) : + waiting && !state.WantActive ? (Xbe24Keyboard.Yellow, true) : + state.HasClearance ? (Xbe24Keyboard.Yellow, false) : + k.IsKeyPressed(toggle) ? (Xbe24Keyboard.Orange, false) : + (Xbe24Keyboard.Red, false)); + k.SetBacklight(indicate, + state.State == MotorState.Forward ? (Xbe24Keyboard.Green, false) : + state.State == MotorState.Backward ? (Xbe24Keyboard.Lime, true) : + waiting && state.WantActive ? (Xbe24Keyboard.Green, true) : + waiting && !state.WantActive ? (Xbe24Keyboard.Yellow, true) : + state.HasClearance ? (Xbe24Keyboard.Yellow, false) : + (Xbe24Keyboard.Red, false)); + } + + private static void UpdateMotorKeys(Xbe24Keyboard k, ShortcutKey start, ShortcutKey stop, ShortcutKey toggle, ShortcutKey indicate, bool active, bool clearance, bool consistent = true) { + k.SetBacklight(start, + active && consistent ? Xbe24Keyboard.Green : + active ? Xbe24Keyboard.Yellow : + clearance ? Xbe24Keyboard.LightGreen : + k.IsKeyPressed(start) ? Xbe24Keyboard.Orange : + Xbe24Keyboard.LightRed); + k.SetBacklight(stop, + !active && consistent ? Xbe24Keyboard.Red : + Xbe24Keyboard.LightRed); + k.SetBacklight(toggle, + active && consistent ? Xbe24Keyboard.Green : + active ? Xbe24Keyboard.Yellow : + !clearance && k.IsKeyPressed(toggle) ? Xbe24Keyboard.Orange : + Xbe24Keyboard.Red); + k.SetBacklight(indicate, + active && consistent ? Xbe24Keyboard.Green : + active ? Xbe24Keyboard.Yellow : + Xbe24Keyboard.Red); + } + + private static void UpdateMwSelectKeys(Xbe24Keyboard k, ShortcutKey select, ShortcutKey indicate, bool selected, bool wantSelected, bool clearance) { + k.SetBacklight(select, + selected && !clearance ? (Xbe24Keyboard.Red, true) : + selected ? (Xbe24Keyboard.Blue, false) : + !clearance && k.IsKeyPressed(select) ? (Xbe24Keyboard.Orange, false) : + wantSelected && !clearance ? (Xbe24Keyboard.Red, true) : + wantSelected ? (Xbe24Keyboard.Blue, true) : + clearance ? (Xbe24Keyboard.LightBlue, false) : + (Xbe24Keyboard.LightRed, false)); + k.SetBacklight(indicate, + selected && !clearance ? (Xbe24Keyboard.Red, true) : + selected ? (Xbe24Keyboard.Blue, false) : + wantSelected && !clearance ? (Xbe24Keyboard.Red, true) : + wantSelected ? (Xbe24Keyboard.Blue, true) : + clearance ? (Xbe24Keyboard.LightBlue, false) : + (Xbe24Keyboard.LightRed, false)); + } + + private static void UpdateMwStirrerKeys(Xbe24Keyboard k, FillState auto, ShortcutKey start, ShortcutKey stop, ShortcutKey toggle, ShortcutKey indicate, bool active, bool pumping, FillState filling) { + k.SetBacklight(start, + active && pumping && filling >= auto ? (Xbe24Keyboard.Green, false) : + active ? (Xbe24Keyboard.Green, true) : + pumping && filling >= auto ? (Xbe24Keyboard.LightGreen, true) : + filling >= auto ? (Xbe24Keyboard.LightGreen, false) : + (Xbe24Keyboard.LightRed, false)); + k.SetBacklight(stop, + active && pumping && filling >= auto ? (Xbe24Keyboard.LightRed, false) : + active ? (Xbe24Keyboard.LightRed, true) : + pumping && filling >= auto ? (Xbe24Keyboard.Red, true) : + (Xbe24Keyboard.Red, false)); + k.SetBacklight(toggle, + active && pumping && filling >= auto ? (Xbe24Keyboard.Green, false) : + active ? (Xbe24Keyboard.Green, true) : + pumping && filling >= auto ? (Xbe24Keyboard.Red, true) : + filling >= auto ? (Xbe24Keyboard.Yellow, false) : + (Xbe24Keyboard.Red, false)); + k.SetBacklight(indicate, + active && pumping && filling >= auto ? (Xbe24Keyboard.Green, false) : + active ? (Xbe24Keyboard.Green, true) : + pumping && filling >= auto ? (Xbe24Keyboard.Red, true) : + filling >= auto ? (Xbe24Keyboard.Yellow, false) : + (Xbe24Keyboard.Red, false)); + } + protected void UpdateKeyboardBacklights(object? sender, PlantEventArgs evt) { if (sender is not PamhagenPlant plant || plant.Keyboard is not Xbe24Keyboard k) return; - // TODO update all keys + k.SetBacklight(ShortcutKey.INDICATE_PRESS_CROSS_AUGER, State.PressCrossAuger_IsActive ? Xbe24Keyboard.Green : Xbe24Keyboard.Red); + k.SetBacklight(ShortcutKey.INDICATE_PRESS1_CLEARANCE, State.Press1_HasClearance ? Xbe24Keyboard.Green : Xbe24Keyboard.Red); + k.SetBacklight(ShortcutKey.INDICATE_PRESS2_CLEARANCE, State.Press2_HasClearance ? Xbe24Keyboard.Green : Xbe24Keyboard.Red); - k.SetBacklight(ShortcutKey.START_REBLER, State.Rebler_IsActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen); - k.SetBacklight(ShortcutKey.STOP_REBLER, !State.Rebler_IsActive ? Xbe24Keyboard.Red : Xbe24Keyboard.LightRed); + UpdateMotorKeys(k, ShortcutKey.START_AUGER1, ShortcutKey.STOP_AUGER1, ShortcutKey.TOGGLE_AUGER1, ShortcutKey.INDICATE_AUGER1, + State.Auger1_IsActive, true); + UpdateMotorKeys(k, ShortcutKey.START_AUGER2, ShortcutKey.STOP_AUGER2, ShortcutKey.TOGGLE_AUGER2, ShortcutKey.INDICATE_AUGER2, + State.Auger2_IsActive, true); + UpdateMotorKeys(k, ShortcutKey.START_AUGER3, ShortcutKey.STOP_AUGER3, ShortcutKey.TOGGLE_AUGER3, ShortcutKey.INDICATE_AUGER3, + State.Auger3_IsActive, true); + UpdateMotorKeys(k, ShortcutKey.START_REBLER, ShortcutKey.STOP_REBLER, ShortcutKey.TOGGLE_REBLER, ShortcutKey.INDICATE_REBLER, + State.Rebler_IsActive, true); + UpdateMotorKeys(k, ShortcutKey.START_TROUGH_AUGER, ShortcutKey.STOP_TROUGH_AUGER, ShortcutKey.TOGGLE_TROUGH_AUGER, ShortcutKey.INDICATE_TROUGH_AUGER, + State.TroughAuger_IsActive, State.TroughAuger_HasClearance); + UpdateMotorKeys(k, ShortcutKey.START_WASTE_DISPOSAL, ShortcutKey.STOP_WASTE_DISPOSAL, ShortcutKey.TOGGLE_WASTE_DISPOSAL, ShortcutKey.INDICATE_WASTE_DISPOSAL, + true, State.WasteDisposal_IsActive, State.WasteDisposal_IsConsistent); - k.SetBacklight(ShortcutKey.START_TROUGH_AUGER, !State.TroughAuger_HasClearance ? k.IsKeyPressed(ShortcutKey.START_TROUGH_AUGER) ? Xbe24Keyboard.Orange : Xbe24Keyboard.LightRed : State.TroughAuger_IsActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen); - k.SetBacklight(ShortcutKey.STOP_TROUGH_AUGER, !State.TroughAuger_IsActive ? Xbe24Keyboard.Red : Xbe24Keyboard.LightRed); + UpdateMwSelectKeys(k, ShortcutKey.SELECT_MW1, ShortcutKey.INDICATE_MW1_SELECTED, + State.MW1_IsSelected, State.MW1_WantSelected, State.MW1_FillLevel != FillState.Full); + UpdateMwSelectKeys(k, ShortcutKey.SELECT_MW2, ShortcutKey.INDICATE_MW2_SELECTED, + State.MW2_IsSelected, State.MW2_WantSelected, State.MW2_FillLevel != FillState.Full); - k.SetBacklight(ShortcutKey.SELECT_MW2, State.MW2_WantSelected || State.MW2_IsSelected ? Xbe24Keyboard.Blue : Xbe24Keyboard.LightBlue, State.MW2_WantSelected && !State.MW2_IsSelected); - k.SetBacklight(ShortcutKey.SELECT_MW1, State.MW1_WantSelected || State.MW1_IsSelected ? Xbe24Keyboard.Blue : Xbe24Keyboard.LightBlue, State.MW1_WantSelected && !State.MW1_IsSelected); + UpdateMwStirrerKeys(k, Plc?.AutoStirrer ?? App.Config.PlcAutoStirrer, + ShortcutKey.START_STIRRER_MW1, ShortcutKey.STOP_STIRRER_MW1, ShortcutKey.TOGGLE_STIRRER_MW1, ShortcutKey.INDICATE_STIRRER_MW1, + State.MW1_Stirrer_IsActive, State.MP1_State == MotorState.Forward, State.MW1_FillLevel); + UpdateMwStirrerKeys(k, Plc?.AutoStirrer ?? App.Config.PlcAutoStirrer, + ShortcutKey.START_STIRRER_MW2, ShortcutKey.STOP_STIRRER_MW2, ShortcutKey.TOGGLE_STIRRER_MW2, ShortcutKey.INDICATE_STIRRER_MW2, + State.MW2_Stirrer_IsActive, State.MP2_State == MotorState.Forward, State.MW2_FillLevel); Dictionary pumpHighlightOff = []; foreach (var (key, d) in Graph.PathShortcuts) { if (App.Config.MapKey(key) is not int idx) continue; var isActive = d.Pump.IsActive; + var hasClearnace = d.Sink.HasFillingClearance; var paths = plant.Graph.SelectedPaths.Select(p => (Pipeline.Path?)p) .Where(p => p?.Matches(d.Source, d.Intermediate, d.Sink) ?? false); if (paths.FirstOrDefault() is Pipeline.Path path) { var isReady = path.IsReady; var isDefault = !path.Hops.SkipLast(1).Any(h => h.Node is not Valve && h.Node is not PipeJoin && h.Node is not Pump); - k.SetBacklight(idx, isActive ? isDefault ? Xbe24Keyboard.Cyan : Xbe24Keyboard.Purple : isDefault ? Xbe24Keyboard.Blue : Xbe24Keyboard.DarkPurple, !isReady); + k.SetBacklight(idx, + !hasClearnace && k.IsKeyPressed(idx) ? Xbe24Keyboard.Orange : + !hasClearnace ? Xbe24Keyboard.Red : + isActive && isDefault ? Xbe24Keyboard.Cyan : + isActive ? Xbe24Keyboard.Purple : + isDefault ? Xbe24Keyboard.Blue : + Xbe24Keyboard.DarkPurple, !hasClearnace || !isReady); } else { var isFree = Graph.GetFreePath([d.Source, d.Sink], overrideStart: true) != null; if (isActive && k.IsKeyPressed(idx)) pumpHighlightOff[d.Pump] = true; - k.SetBacklight(idx, isActive ? k.IsKeyPressed(idx) ? Xbe24Keyboard.Orange : Xbe24Keyboard.Neutral : isFree ? Xbe24Keyboard.LightBlue : k.IsKeyPressed(idx) ? Xbe24Keyboard.Orange : Xbe24Keyboard.Neutral); + k.SetBacklight(idx, + (!isFree || !hasClearnace) && k.IsKeyPressed(idx) ? Xbe24Keyboard.Orange : + (!isFree || !hasClearnace) ? Xbe24Keyboard.LightRed : + isActive && k.IsKeyPressed(idx) ? Xbe24Keyboard.Orange : + isActive ? Xbe24Keyboard.Neutral : + Xbe24Keyboard.LightBlue); } } - if (!plant.State.MP2_HasPathClearance && plant.State.MP2_HasDryRunClearance && plant.State.MP2_WantsPathClearance) { - k.SetBacklight(ShortcutKey.START_MP2, plant.State.MP2_WantActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen, true); - } else { - k.SetBacklight(ShortcutKey.START_MP2, !State.MP2_HasClearance ? k.IsKeyPressed(ShortcutKey.START_MP2) ? Xbe24Keyboard.Orange : Xbe24Keyboard.LightRed : State.MP2_IsActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen); - } - if (!plant.State.MP1_HasPathClearance && plant.State.MP1_HasDryRunClearance && plant.State.MP1_WantsPathClearance) { - k.SetBacklight(ShortcutKey.START_MP1, plant.State.MP1_WantActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen, true); - } else { - k.SetBacklight(ShortcutKey.START_MP1, !State.MP1_HasClearance ? k.IsKeyPressed(ShortcutKey.START_MP1) ? Xbe24Keyboard.Orange : Xbe24Keyboard.LightRed : State.MP1_IsActive ? Xbe24Keyboard.Green : Xbe24Keyboard.LightGreen); - } - k.SetBacklight(ShortcutKey.STOP_MP2, pumpHighlightOff.GetValueOrDefault(Graph.MP2) ? Xbe24Keyboard.Orange : !State.MP2_IsActive ? Xbe24Keyboard.Red : Xbe24Keyboard.LightRed); - k.SetBacklight(ShortcutKey.STOP_MP1, pumpHighlightOff.GetValueOrDefault(Graph.MP1) ? Xbe24Keyboard.Orange : !State.MP1_IsActive ? Xbe24Keyboard.Red : Xbe24Keyboard.LightRed); + UpdatePumpKeys(k, ShortcutKey.START_MP1, ShortcutKey.STOP_MP1, ShortcutKey.TOGGLE_MP1, ShortcutKey.INDICATE_MP1, + plant.State.MP1, pumpHighlightOff.GetValueOrDefault(Graph.MP1), true); + UpdatePumpKeys(k, ShortcutKey.START_MP2, ShortcutKey.STOP_MP2, ShortcutKey.TOGGLE_MP2, ShortcutKey.INDICATE_MP2, + plant.State.MP2, pumpHighlightOff.GetValueOrDefault(Graph.MP2), true); + UpdatePumpKeys(k, ShortcutKey.ENABLE_P12, ShortcutKey.DISABLE_P12, ShortcutKey.TOGGLE_P12, ShortcutKey.INDICATE_P12, + plant.State.P12, pumpHighlightOff.GetValueOrDefault(Graph.P12), false); + UpdatePumpKeys(k, ShortcutKey.ENABLE_P3, ShortcutKey.DISABLE_P3, ShortcutKey.TOGGLE_P3, ShortcutKey.INDICATE_P3, + plant.State.P3, pumpHighlightOff.GetValueOrDefault(Graph.P3), false); + UpdatePumpKeys(k, ShortcutKey.ENABLE_P4, ShortcutKey.DISABLE_P4, ShortcutKey.TOGGLE_P4, ShortcutKey.INDICATE_P4, + plant.State.P4, pumpHighlightOff.GetValueOrDefault(Graph.P4), false); + UpdatePumpKeys(k, ShortcutKey.ENABLE_P5, ShortcutKey.DISABLE_P5, ShortcutKey.TOGGLE_P5, ShortcutKey.INDICATE_P5, + plant.State.P5, pumpHighlightOff.GetValueOrDefault(Graph.P5), false); + UpdatePumpKeys(k, ShortcutKey.ENABLE_P6, ShortcutKey.DISABLE_P6, ShortcutKey.TOGGLE_P6, ShortcutKey.INDICATE_P6, + plant.State.P6, pumpHighlightOff.GetValueOrDefault(Graph.P6), false); } public void Dispose() { @@ -279,34 +406,61 @@ namespace PamhagenSysCtrl.Helpers { private void Keyboard_KeyDown(object? sender, int keyIndex) { if (Plc == null || App.Config.MapKey(keyIndex) is not ShortcutKey key) return; try { - if (key == ShortcutKey.START_REBLER) { - Plc.StartRebler(); - } else if (key == ShortcutKey.STOP_REBLER) { - Plc.StopRebler(); - } else if (key == ShortcutKey.START_TROUGH_AUGER) { - Plc.StartTroughAuger(); - } else if (key == ShortcutKey.STOP_TROUGH_AUGER) { - Plc.StopTroughAuger(); - } else if (key == ShortcutKey.SELECT_MW2) { - Plc.SelectMW2(); - } else if (key == ShortcutKey.SELECT_MW1) { - Plc.SelectMW1(); - } else if (key == ShortcutKey.START_MP2) { - Plc.StartMP2Forward(); - } else if (key == ShortcutKey.STOP_MP2) { - Plc.StopMP2(); - } else if (key == ShortcutKey.START_MP1) { - Plc.StartMP1Forward(); - } else if (key == ShortcutKey.STOP_MP1) { - Plc.StopMP1(); - } else if (Graph.PathShortcuts.TryGetValue(key, out var path)) { + if (Graph.PathShortcuts.TryGetValue(key, out var path)) { FastSelect(path.Source, path.Intermediate, path.Sink); } else { - return; + switch (key) { + case ShortcutKey.START_REBLER: StartRebler(); break; + case ShortcutKey.STOP_REBLER: StopRebler(); break; + case ShortcutKey.TOGGLE_REBLER: ToggleRebler(); break; + case ShortcutKey.START_WASTE_DISPOSAL: StartWasteDisposal(); break; + case ShortcutKey.STOP_WASTE_DISPOSAL: StopWasteDisposal(); break; + case ShortcutKey.TOGGLE_WASTE_DISPOSAL: ToggleWasteDisposal(); break; + case ShortcutKey.START_AUGER1: StartAuger1(); break; + case ShortcutKey.STOP_AUGER1: StopAuger1(); break; + case ShortcutKey.TOGGLE_AUGER1: ToggleAuger1(); break; + case ShortcutKey.START_AUGER2: StartAuger2(); break; + case ShortcutKey.STOP_AUGER2: StopAuger2(); break; + case ShortcutKey.TOGGLE_AUGER2: ToggleAuger2(); break; + case ShortcutKey.START_AUGER3: StartAuger3(); break; + case ShortcutKey.STOP_AUGER3: StopAuger3(); break; + case ShortcutKey.TOGGLE_AUGER3: ToggleAuger3(); break; + case ShortcutKey.START_TROUGH_AUGER: StartTroughAuger(); break; + case ShortcutKey.STOP_TROUGH_AUGER: StopTroughAuger(); break; + case ShortcutKey.TOGGLE_TROUGH_AUGER: ToggleTroughAuger(); break; + case ShortcutKey.SELECT_MW1: SelectMW1(); break; + case ShortcutKey.SELECT_MW2: SelectMW2(); break; + case ShortcutKey.START_STIRRER_MW1: StartStirrerMW1(); break; + case ShortcutKey.STOP_STIRRER_MW1: StopStirrerMW1(); break; + case ShortcutKey.TOGGLE_STIRRER_MW1: ToggleStirrerMW1(); break; + case ShortcutKey.START_STIRRER_MW2: StartStirrerMW2(); break; + case ShortcutKey.STOP_STIRRER_MW2: StopStirrerMW2(); break; + case ShortcutKey.TOGGLE_STIRRER_MW2: ToggleStirrerMW2(); break; + case ShortcutKey.START_MP1: StartMP1Forward(); break; + case ShortcutKey.STOP_MP1: StopMP1(); break; + case ShortcutKey.TOGGLE_MP1: ToggleMP1(); break; + case ShortcutKey.START_MP2: StartMP2Forward(); break; + case ShortcutKey.STOP_MP2: StopMP2(); break; + case ShortcutKey.TOGGLE_MP2: ToggleMP2(); break; + case ShortcutKey.ENABLE_P12: EnableP12(); break; + case ShortcutKey.DISABLE_P12: DisableP12(); break; + case ShortcutKey.TOGGLE_P12: ToggleP12(); break; + case ShortcutKey.ENABLE_P3: EnableP3(); break; + case ShortcutKey.DISABLE_P3: DisableP3(); break; + case ShortcutKey.TOGGLE_P3: ToggleP3(); break; + case ShortcutKey.ENABLE_P4: EnableP4(); break; + case ShortcutKey.DISABLE_P4: DisableP4(); break; + case ShortcutKey.TOGGLE_P4: ToggleP4(); break; + case ShortcutKey.ENABLE_P5: EnableP5(); break; + case ShortcutKey.DISABLE_P5: DisableP5(); break; + case ShortcutKey.TOGGLE_P5: ToggleP5(); break; + case ShortcutKey.ENABLE_P6: EnableP6(); break; + case ShortcutKey.DISABLE_P6: DisableP6(); break; + case ShortcutKey.TOGGLE_P6: ToggleP6(); break; + default: return; + } } RaiseUpdateEvent(new()); - } catch (NoClearanceException) { - // Keyboard?.SetBacklight(keyIndex, Color.FromRgb(255, 0, 0)); } catch (Exception) { // ignore } @@ -334,6 +488,8 @@ namespace PamhagenSysCtrl.Helpers { public void StopAuger2() => Plc?.StopAuger2(); public void StartAuger3() => Plc?.StartAuger3(); public void StopAuger3() => Plc?.StopAuger3(); + public void StartWasteDisposal() => Plc?.StartWasteDisposal(); + public void StopWasteDisposal() => Plc?.StopWasteDisposal(); public void StartMP1Forward() => Plc?.StartMP1Forward(); public void StartMP1Backward() => Plc?.StartMP1Backward(); public void StopMP1() => Plc?.StopMP1(); @@ -350,5 +506,125 @@ namespace PamhagenSysCtrl.Helpers { public void DisableP5() => Plc?.DisableP5(); public void EnableP6() => Plc?.EnableP6(); public void DisableP6() => Plc?.DisableP6(); + + public void ToggleTroughAuger() { + if (State.TroughAuger_IsActive) { + StopTroughAuger(); + } else { + StartTroughAuger(); + } + } + + public void ToggleRebler() { + if (State.Rebler_IsActive) { + StopRebler(); + } else { + StartRebler(); + } + } + + public void ToggleAuger1() { + if (State.Auger1_IsActive) { + StopAuger1(); + } else { + StartAuger1(); + } + } + + public void ToggleAuger2() { + if (State.Auger2_IsActive) { + StopAuger2(); + } else { + StartAuger2(); + } + } + + public void ToggleAuger3() { + if (State.Auger3_IsActive) { + StopAuger3(); + } else { + StartAuger3(); + } + } + + public void ToggleWasteDisposal() { + if (State.WasteDisposal_IsActive) { + StopWasteDisposal(); + } else { + StartWasteDisposal(); + } + } + + public void ToggleStirrerMW1() { + if (State.MW1_Stirrer_IsActive) { + StopStirrerMW1(); + } else { + StartStirrerMW1(); + } + } + + public void ToggleStirrerMW2() { + if (State.MW2_Stirrer_IsActive) { + StopStirrerMW2(); + } else { + StartStirrerMW2(); + } + } + + public void ToggleMP1() { + if (State.MP1_IsActive || State.MP1_WantActive) { + StopMP1(); + } else { + StartMP1Forward(); + } + } + + public void ToggleMP2() { + if (State.MP2_IsActive || State.MP2_WantActive) { + StopMP2(); + } else { + StartMP2Forward(); + } + } + + public void ToggleP12() { + if (State.P12_IsActive || State.P12_WantActive) { + EnableP12(); + } else { + DisableP12(); + } + } + + public void ToggleP3() { + if (State.P3_IsActive || State.P3_WantActive) { + EnableP3(); + } else { + DisableP3(); + } + } + + public void ToggleP4() { + if (State.P4_IsActive || State.P4_WantActive) { + EnableP4(); + } else { + DisableP4(); + } + } + + public void ToggleP5() { + if (State.P5_IsActive || State.P5_WantActive) { + EnableP5(); + } else { + DisableP5(); + } + } + + public void ToggleP6() { + if (State.P6_IsActive || State.P6_WantActive) { + EnableP6(); + } else { + DisableP6(); + } + } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/ISink.cs b/PamhagenSysCtrl/Helpers/Pipeline/ISink.cs index e2edcb9..2584bcb 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/ISink.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/ISink.cs @@ -2,6 +2,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public interface ISink : INode { public double TopY { get; } public bool IsFull { get; } + public bool HasFillingClearance { get; } public int? CapacityLiters { get; } } } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Press.cs b/PamhagenSysCtrl/Helpers/Pipeline/Press.cs index 106206d..b8aa10d 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Press.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Press.cs @@ -18,21 +18,24 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public double TopY => CenterY - DIAMETER / 2; public FillState FillState => CallbackFillState(); public bool IsFull => FillState == FillState.Full; + public bool HasFillingClearance => CallbackFillingClearance(); public int? CapacityLiters { get; set; } protected Func CallbackFillState; + protected Func CallbackFillingClearance; private Polygon? _frame; private Ellipse? _circle; private TextBlock? _text; - public Press(string label, double x, double y, int capacityLiters, Func cbFillState) { + public Press(string label, double x, double y, int capacityLiters, Func cbFillState, Func cbFillingClearance) { CenterX = x; CenterY = y; Label = label; CapacityLiters = capacityLiters; CallbackFillState = cbFillState; + CallbackFillingClearance = cbFillingClearance; Inputs = new HashSet(); Outputs = new HashSet(); } diff --git a/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs b/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs index addf4d2..c979acf 100644 --- a/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs +++ b/PamhagenSysCtrl/Helpers/Pipeline/Tank.cs @@ -17,6 +17,7 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public FillState FillState => CallbackFillState(); public bool IsFull => FillState == FillState.Full; public bool IsFilled => FillState != FillState.Empty; + public bool HasFillingClearance => CallbackFillingClearance(); public ISet Inputs { get; init; } public ISet Outputs { get; init; } @@ -24,16 +25,18 @@ namespace PamhagenSysCtrl.Helpers.Pipeline { public int? CapacityLiters { get; set; } protected Func CallbackFillState; + protected Func CallbackFillingClearance; private Shape? _rect; private TextBlock? _text; - public Tank(string label, double x, double y, int capacityLiters, Func cbFillState) { + public Tank(string label, double x, double y, int capacityLiters, Func cbFillState, Func cbFillingClearance) { CenterX = x; CenterY = y; Label = label; CapacityLiters = capacityLiters; CallbackFillState = cbFillState; + CallbackFillingClearance = cbFillingClearance; Inputs = new HashSet(); Outputs = new HashSet(); } diff --git a/PamhagenSysCtrl/Helpers/Plc/LegacyPamhagenPlc.cs b/PamhagenSysCtrl/Helpers/Plc/LegacyPamhagenPlc.cs index 348fb1b..4d9d718 100644 --- a/PamhagenSysCtrl/Helpers/Plc/LegacyPamhagenPlc.cs +++ b/PamhagenSysCtrl/Helpers/Plc/LegacyPamhagenPlc.cs @@ -49,7 +49,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { protected static FillState Int3ToFillState(int n, bool bigEndian = true) { return - (bigEndian && (n & 0x4) != 0) || (!bigEndian && (n & 0x1) != 0) ? FillState.Full : + (bigEndian && (n & 0x4) != 0) || (!bigEndian && (n & 0x1) != 0) ? FillState.AlmostFull : (bigEndian && (n & 0x2) != 0) || (!bigEndian && (n & 0x2) != 0) ? FillState.Half : (bigEndian && (n & 0x1) != 0) || (!bigEndian && (n & 0x4) != 0) ? FillState.Filled : n == 0 ? FillState.Empty : diff --git a/PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs b/PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs index 550d822..343eae2 100644 --- a/PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs +++ b/PamhagenSysCtrl/Helpers/Plc/PamhagenPlc.cs @@ -20,6 +20,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { protected LegacyPamhagenPlc Plc; public PamhagenState State { get; private set; } + public PamhagenState LastState { get; private set; } public string? ComPort => Plc?.ComPort; public T1.Status? LastStatus => Plc?.LastStatus; @@ -31,12 +32,16 @@ namespace PamhagenSysCtrl.Helpers.Plc { internal readonly int ConsiderLastSensorsOpen; internal readonly int ConsiderLastSensorsClose; + internal readonly int ConsiderLastSensorsMW; + internal readonly FillState AutoStirrer; - public PamhagenPlc(string comPort, int sensorDelayOpenMs, int sensorDelayCloseMs, Parity parity = Parity.Odd) { + public PamhagenPlc(string comPort, int sensorDelayOpenMs, int sensorDelayCloseMs, int sensorDelayMwMs, FillState autoStirrer = FillState.Half, Parity parity = Parity.Odd) { Plc = new(comPort, parity); ConsiderLastSensorsOpen = sensorDelayOpenMs / 125 + 1; ConsiderLastSensorsClose = sensorDelayCloseMs / 125 + 1; - LastSensors = new LegacyPamhagenPlc.SensorStates[Math.Max(ConsiderLastSensorsOpen, ConsiderLastSensorsClose)]; + ConsiderLastSensorsMW = sensorDelayMwMs / 125 + 1; + AutoStirrer = autoStirrer; + LastSensors = new LegacyPamhagenPlc.SensorStates[Math.Max(Math.Max(ConsiderLastSensorsOpen, ConsiderLastSensorsClose), ConsiderLastSensorsMW)]; } public void Dispose() { @@ -51,6 +56,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { var sensors = await Plc.ReadInputs(); LastSensors[0] = sensors; State = new(LastSensors, this); + LastState = State; } public async Task Shutdown() { @@ -67,7 +73,9 @@ namespace PamhagenSysCtrl.Helpers.Plc { var sensors = await Plc.ReadInputs(); Array.Copy(LastSensors, 0, LastSensors, 1, LastSensors.Length - 1); LastSensors[0] = sensors; - State = new(LastSensors, this); + var current = new PamhagenState(LastSensors, this); + LastState = State; + State = current; UpdateInterlocks(); } @@ -103,14 +111,10 @@ namespace PamhagenSysCtrl.Helpers.Plc { if (P6_WantActive && State.P6_HasClearance) EnableP6(); 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)) { + if (State.MW1_Stirrer_IsActive && (State.MW1_FillLevel == FillState.Empty || (LastState.MW1_FillLevel >= AutoStirrer && State.MW1_FillLevel < AutoStirrer))) { 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)) { + if (State.MW2_Stirrer_IsActive && (State.MW2_FillLevel == FillState.Empty || (LastState.MW2_FillLevel >= AutoStirrer && State.MW2_FillLevel < AutoStirrer))) { StopStirrerMW2(); } } @@ -154,6 +158,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { } public void StartStirrerMW1() { + if (!ManualControlMode && State.MW1_FillLevel == FillState.Empty) throw new NoClearanceException("MW1 ist leer"); Actuators.StirrerMW1 = true; } @@ -162,6 +167,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { } public void StartStirrerMW2() { + if (!ManualControlMode && State.MW2_FillLevel == FillState.Empty) throw new NoClearanceException("MW2 ist leer"); Actuators.StirrerMW2 = true; } @@ -203,6 +209,18 @@ namespace PamhagenSysCtrl.Helpers.Plc { Actuators.Auger3 = false; } + public void StartWasteDisposal() { + StartAuger1(); + StartAuger2(); + StartAuger3(); + } + + public void StopWasteDisposal() { + StopAuger1(); + StopAuger2(); + StopAuger3(); + } + public void StartGradationPump() { Actuators.GradationPump = true; } @@ -221,7 +239,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { MP1_WantActive = false; 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(); + if (!ManualControlMode && State.MW1_FillLevel >= AutoStirrer) StartStirrerMW1(); } public void StartMP1Backward() { @@ -247,7 +265,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { MP2_WantActive = false; 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(); + if (!ManualControlMode && State.MW2_FillLevel >= AutoStirrer) StartStirrerMW2(); } public void StartMP2Backward() { @@ -260,7 +278,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { public void StopMP2() { MP2_WantActive = false; Actuators.MP2 = MotorState.Halt; - if (!ManualControlMode) StopStirrerMW1(); + if (!ManualControlMode) StopStirrerMW2(); } public void EnableP12() { diff --git a/PamhagenSysCtrl/Helpers/Plc/PamhagenState.cs b/PamhagenSysCtrl/Helpers/Plc/PamhagenState.cs index efd065d..798c20c 100644 --- a/PamhagenSysCtrl/Helpers/Plc/PamhagenState.cs +++ b/PamhagenSysCtrl/Helpers/Plc/PamhagenState.cs @@ -1,6 +1,11 @@ namespace PamhagenSysCtrl.Helpers.Plc { public readonly record struct PamhagenState { + public readonly record struct PumpState( + MotorState State, bool IsActive, + bool HasClearance, bool HasPathClearance, bool HasDryRunClearance, + bool WantsPathClearance, bool WantActive); + private readonly LegacyPamhagenPlc.SensorStates Sensors; private readonly PamhagenPlc Plc; private LegacyPamhagenPlc.ActuatorStates Actuators => Plc == null ? default : Plc.Actuators; @@ -17,8 +22,9 @@ namespace PamhagenSysCtrl.Helpers.Plc { public bool MW2_IsSelected => Sensors.TroughSelector == 2; public bool MW1_WantSelected => Actuators.GetV(58); public bool MW2_WantSelected => !Actuators.GetV(58); - public FillState MW1_FillLevel => Sensors.FillLevelMW1; - public FillState MW2_FillLevel => Sensors.FillLevelMW2; + + public readonly FillState MW1_FillLevel { get; } + public readonly FillState MW2_FillLevel { get; } public FillState[] Tanks_FillLevel => Sensors.FillLevelTanks ?? [FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown, FillState.Unknown]; public FillState T1_FillLevel => Sensors.FillLevelTanks[0]; @@ -42,6 +48,7 @@ namespace PamhagenSysCtrl.Helpers.Plc { public bool Auger2_IsActive => Actuators.Auger2; public bool Auger3_IsActive => Actuators.Auger3; public bool WasteDisposal_IsActive => Auger1_IsActive || Auger2_IsActive || Auger3_IsActive; + public bool WasteDisposal_IsConsistent => (Auger1_IsActive && Auger2_IsActive && Auger3_IsActive) || (!Auger1_IsActive && !Auger2_IsActive && !Auger3_IsActive); public MotorState MP1_State => Actuators.MP1; public MotorState MP2_State => Actuators.MP2; @@ -85,13 +92,13 @@ namespace PamhagenSysCtrl.Helpers.Plc { public readonly bool P5_WantsPathClearance { get; } public readonly bool P6_WantsPathClearance { get; } - public bool MP1_WantActive => Plc.MP1_WantActive; - public bool MP2_WantActive => Plc.MP2_WantActive; - public bool P12_WantActive => Plc.P12_WantActive; - public bool P3_WantActive => Plc.P3_WantActive; - public bool P4_WantActive => Plc.P4_WantActive; - public bool P5_WantActive => Plc.P5_WantActive; - public bool P6_WantActive => Plc.P6_WantActive; + public bool MP1_WantActive => Plc != null && Plc.MP1_WantActive; + public bool MP2_WantActive => Plc != null && Plc.MP2_WantActive; + public bool P12_WantActive => Plc != null && Plc.P12_WantActive; + public bool P3_WantActive => Plc != null && Plc.P3_WantActive; + public bool P4_WantActive => Plc != null && Plc.P4_WantActive; + public bool P5_WantActive => Plc != null && Plc.P5_WantActive; + public bool P6_WantActive => Plc != null && Plc.P6_WantActive; public bool MP1_HasPathClearance => OverridePathClearances || MP1_PathClearance; public bool MP2_HasPathClearance => OverridePathClearances || MP2_PathClearance; @@ -115,6 +122,14 @@ namespace PamhagenSysCtrl.Helpers.Plc { public bool P5_HasClearance => P4_HasDryRunClearance && P5_HasPathClearance; public bool P6_HasClearance => P6_HasDryRunClearance && P6_HasPathClearance; + public PumpState MP1 => new(MP1_State, MP1_IsActive, MP1_HasClearance, MP1_HasPathClearance, MP1_HasDryRunClearance, MP1_WantsPathClearance, MP1_WantActive); + public PumpState MP2 => new(MP2_State, MP2_IsActive, MP2_HasClearance, MP2_HasPathClearance, MP2_HasDryRunClearance, MP2_WantsPathClearance, MP2_WantActive); + public PumpState P12 => new(P12_State, P12_IsActive, P12_HasClearance, P12_HasPathClearance, P12_HasDryRunClearance, P12_WantsPathClearance, P12_WantActive); + public PumpState P3 => new(P3_State, P3_IsActive, P3_HasClearance, P3_HasPathClearance, P3_HasDryRunClearance, P3_WantsPathClearance, P3_WantActive); + public PumpState P4 => new(P4_State, P4_IsActive, P4_HasClearance, P4_HasPathClearance, P4_HasDryRunClearance, P4_WantsPathClearance, P4_WantActive); + public PumpState P5 => new(P5_State, P5_IsActive, P5_HasClearance, P5_HasPathClearance, P5_HasDryRunClearance, P5_WantsPathClearance, P5_WantActive); + public PumpState P6 => new(P6_State, P6_IsActive, P6_HasClearance, P6_HasPathClearance, P6_HasDryRunClearance, P6_WantsPathClearance, P6_WantActive); + public PamhagenState(IEnumerable sensors, PamhagenPlc plc) { Sensors = sensors.First(); Plc = plc; @@ -122,6 +137,21 @@ namespace PamhagenSysCtrl.Helpers.Plc { OpenValves = sensors.Take(Plc.ConsiderLastSensorsOpen).Aggregate(-1L, (m, s) => m & ~s.PressureSensors); ClosedValves = sensors.Take(Plc.ConsiderLastSensorsClose).Aggregate(-1L, (m, s) => m & s.PressureSensors); + var mw1 = sensors.Take(Plc.ConsiderLastSensorsMW).Select(s => s.FillLevelMW1).Where(s => s != FillState.Unknown).Distinct().ToArray(); + var mw2 = sensors.Take(Plc.ConsiderLastSensorsMW).Select(s => s.FillLevelMW2).Where(s => s != FillState.Unknown).Distinct().ToArray(); + MW1_FillLevel = + mw1.Contains(FillState.Invalid) ? FillState.Invalid : + mw1.Length == 1 && mw1[0] == FillState.Empty ? mw1[0] : + mw1.Length == 1 ? mw1[0] + 1 : + mw1.Length >= 2 ? mw1[0] > mw1[1] ? mw1[0] : mw1[1] : + FillState.Unknown; + MW2_FillLevel = + mw2.Contains(FillState.Invalid) ? FillState.Invalid : + mw2.Length == 1 && mw2[0] == FillState.Empty ? mw2[0] : + mw2.Length == 1 ? mw2[0] + 1 : + mw2.Length >= 2 ? mw2[0] > mw2[1] ? mw2[0] : mw2[1] : + FillState.Unknown; + MP1_WantsPathClearance = WantsPathClearnace(this, Paths.MP1); MP2_WantsPathClearance = WantsPathClearnace(this, Paths.MP2); P12_WantsPathClearance = WantsPathClearnace(this, Paths.P12); diff --git a/PamhagenSysCtrl/Helpers/Xbe24Keyboard.cs b/PamhagenSysCtrl/Helpers/Xbe24Keyboard.cs index 3732af6..6a238e1 100644 --- a/PamhagenSysCtrl/Helpers/Xbe24Keyboard.cs +++ b/PamhagenSysCtrl/Helpers/Xbe24Keyboard.cs @@ -11,6 +11,7 @@ namespace PamhagenSysCtrl.Helpers { public readonly bool GetKey(int n) => (Rows[n / 6] & (1 << (n % 6))) != 0; } + public static readonly Color Off = Color.FromArgb(0, 0, 0); public static readonly Color DefaltBacklight = Color.FromArgb(3, 3, 3); public static readonly Color Neutral = Color.FromArgb(4, 4, 4); public static readonly Color Red = Color.FromArgb(255, 0, 0); @@ -22,6 +23,7 @@ namespace PamhagenSysCtrl.Helpers { public static readonly Color Orange = Color.FromArgb(255, 32, 0); public static readonly Color DarkPurple = Color.FromArgb(128, 0, 128); public static readonly Color Purple = Color.FromArgb(255, 64, 255); + public static readonly Color Lime = Color.FromArgb(64, 255, 4); public static readonly Color LightRed = Color.FromArgb(32, 4, 4); public static readonly Color LightGreen = Color.FromArgb(4, 32, 4); public static readonly Color LightBlue = Color.FromArgb(4, 4, 32);