From 4c8352929275020a28f072a3e0a67797011a8a94 Mon Sep 17 00:00:00 2001 From: mharb Date: Sat, 2 Aug 2025 19:40:47 -0400 Subject: [PATCH] Check-in Source P.2 Signed-off-by: mharb --- px-tcp1/ProtosXExercise/Data.cs | 73 +++++++++++++++++++++ px-tcp1/ProtosXExercise/DigitalInputread.cs | 47 +++++++++++++ px-tcp1/ProtosXExercise/LoadFailureCodes.cs | 14 ++++ px-tcp1/ProtosXExercise/OutputWriter.cs | 59 +++++++++++++++++ px-tcp1/ProtosXExercise/Program.cs | 41 ++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 px-tcp1/ProtosXExercise/Data.cs create mode 100644 px-tcp1/ProtosXExercise/DigitalInputread.cs create mode 100644 px-tcp1/ProtosXExercise/LoadFailureCodes.cs create mode 100644 px-tcp1/ProtosXExercise/OutputWriter.cs create mode 100644 px-tcp1/ProtosXExercise/Program.cs diff --git a/px-tcp1/ProtosXExercise/Data.cs b/px-tcp1/ProtosXExercise/Data.cs new file mode 100644 index 0000000..7c6fb72 --- /dev/null +++ b/px-tcp1/ProtosXExercise/Data.cs @@ -0,0 +1,73 @@ +namespace ProtosXdigitalDemo +{ + public static class Data + { + public static class MachineState + { + + public static bool[] digitalInputChannels { get; } = new bool[16]; + public static bool[] digitalOutputChannels { get; } = new bool[16]; + + + public static double[] analogInputChannels { get; } = new double[8]; + + + public static byte[] failureCode { get; } = new byte[256]; + + + public static ushort digitalInputCount { get; private set; } + public static ushort digitalOutputCount { get; private set; } + public static ushort analogInputCount { get; private set; } + + public static void InitializeCounts() + { + digitalInputCount = (ushort)digitalInputChannels.Length; + digitalOutputCount = (ushort)digitalOutputChannels.Length; + analogInputCount = (ushort)analogInputChannels.Length; + } + } + internal enum digitalInputChannels + { + DigitalInput0, + DigitalInput1, + DigitalInput2, + DigitalInput3, + DigitalInput4, + DigitalInput5, + DigitalInput6, + DigitalInput7, + DigitalInput8, + DigitalInput9, + DigitalInput10, + DigitalInput11, + DigitalInput12, + DigitalInput13, + DigitalInput14, + DigitalInput15 + } + internal enum digitalOutputChannels + { + KitchenLight1, + KitchenLight2, + KitchenLight3, + PorchLight1, + Porchlight2, + OutsideFloodlight1, + OutsideFloodlight2, + PantryLight1, + FrontRoomLight1, + FrontRoomLight2, + FrontRoomLight3, + Radio, + LandingLight1, + ServerRoomLights, + HallLight1, + HallLight2 + } + internal enum analogInputChannels + { + TemperatureSensor1, + TemperatureSensor2 + } + } +} diff --git a/px-tcp1/ProtosXExercise/DigitalInputread.cs b/px-tcp1/ProtosXExercise/DigitalInputread.cs new file mode 100644 index 0000000..3329daf --- /dev/null +++ b/px-tcp1/ProtosXExercise/DigitalInputread.cs @@ -0,0 +1,47 @@ +using System; +using Modbus.Device; +using static System.Console; + +namespace ProtosXdigitalDemo +{ + internal class InputReader + { + private readonly ModbusIpMaster _master; + + public InputReader(ModbusIpMaster master) + { + _master = master; + } + + public void ReadAll() + { + WriteLine("Reading all discrete inputs…"); + try + { + bool[] inputs = _master.ReadInputs(0, ChannelCache.DigitalInputCount); + Display(inputs); + } + catch (Exception ex) + { + WriteLine($"[Error] Reading inputs failed → {ex.Message}"); + PromptKey("Press any key to continue…"); + } + } + + private void Display(bool[] inputs) + { + WriteLine("Discrete Inputs:"); + for (int i = 0; i < inputs.Length; i++) + { + string state = inputs[i] ? "On" : "Off"; + WriteLine($" Input #{i + 1}: {state}"); + } + } + + private void PromptKey(string prompt) + { + WriteLine(prompt); + ReadKey(intercept: true); + } + } +} \ No newline at end of file diff --git a/px-tcp1/ProtosXExercise/LoadFailureCodes.cs b/px-tcp1/ProtosXExercise/LoadFailureCodes.cs new file mode 100644 index 0000000..a00c69d --- /dev/null +++ b/px-tcp1/ProtosXExercise/LoadFailureCodes.cs @@ -0,0 +1,14 @@ + +namespace ProtosXdigitalDemo +{ + internal class LoadFailureCodes + { + public static void FailureCodeValues() + { + Data.MachineState.failureCode[0] = 0; // success + Data.MachineState.failureCode[1] = 1; // digital write error from hardware + Data.MachineState.failureCode[2] = 2; // too many CLI parameters + Data.MachineState.failureCode[255] = 255; // other error + } + } +} \ No newline at end of file diff --git a/px-tcp1/ProtosXExercise/OutputWriter.cs b/px-tcp1/ProtosXExercise/OutputWriter.cs new file mode 100644 index 0000000..cb84a6d --- /dev/null +++ b/px-tcp1/ProtosXExercise/OutputWriter.cs @@ -0,0 +1,59 @@ +using System; +using Modbus.Device; +using static System.Console; + +namespace ProtosXdigitalDemo +{ + internal class OutputExerciser + { + private readonly ModbusIpMaster _master; + + public OutputExerciser(ModbusIpMaster master) + { + _master = master; + } + + public void RunSequence() + { + SetAllOutputs(false, "Turning all outputs OFF…"); + WaitForKey("Press any key to turn outputs ON…"); + + SetAllOutputs(true, "Turning all outputs ON…"); + WaitForKey("Press any key to turn outputs OFF and finish…"); + + SetAllOutputs(false, "Turning all outputs OFF…"); + } + + private void SetAllOutputs(bool state, string message) + { + WriteLine(message); + UpdateMachineState(state); + + int result = WriteMachineDigitalStateToIO.WriteMachineStateToIO(_master, 0); + if (result == Data.MachineState.failureCode[0]) + { + WriteLine($"All digital outputs are now {(state ? "ON" : "OFF")}"); + } + else + { + WriteLine("[Error] Writing machine-state failed"); + WaitForKey("Press any key to exit…"); + Environment.Exit(Data.MachineState.failureCode[1]); + } + } + + private void UpdateMachineState(bool state) + { + for (int i = 0; i < Data.MachineState.digitalOutputChannels.Length; i++) + { + Data.MachineState.digitalOutputChannels[i] = state; + } + } + + private void WaitForKey(string prompt) + { + WriteLine(prompt); + ReadKey(intercept: true); + } + } +} diff --git a/px-tcp1/ProtosXExercise/Program.cs b/px-tcp1/ProtosXExercise/Program.cs new file mode 100644 index 0000000..10ce140 --- /dev/null +++ b/px-tcp1/ProtosXExercise/Program.cs @@ -0,0 +1,41 @@ +using System; +using System.Net.Sockets; +using Modbus.Device; +using static System.Console; + +namespace ProtosXdigitalDemo +{ + public class Program + { + private const string IpAddress = "10.10.1.1"; + private const int Port = 502; + + public static int Main(string[] args) + { + //ConsoleSetup.ApplyDefaultAppearance(); + var cmd = CommandLineParser.Parse(args); // still available + LoadFailureCodes.FailureCodeValues(); // assumed static initializer + + try + { + using var tcpClient = new TcpClientConnector(IpAddress, Port).Connect(); + var master = ModbusIpMaster.CreateIp(tcpClient); + + ChannelCache.Initialize(); + new InputReader(master).ReadAll(); + new OutputExerciser(master).RunSequence(); + } + catch (OperationCanceledException) + { + // an Exit was requested + } + catch (Exception ex) + { + WriteLine($"[Fatal] {ex}"); + return Data.MachineState.failureCode[1]; + } + + return Data.MachineState.failureCode[0]; + } + } +} \ No newline at end of file