//  This program connects to a Sealevel type 463E-OEM I/O processor https://www.sealevel.com/seai-o-463e-oem/
//  Note: this program cannot be started until at least five seconds after powering up the I/O processor
//  Note: if the program is interrupted and does not terminate normally, a power reset is required on the 463E

using Modbus.Device;
using System.Net.Sockets;
using static System.Console;

namespace ModbusReadRegisters
{
    internal class ModbusProgram
    {
        private const string    IPaddress = "10.10.10.110";     // Modbus device IP
        private const int       Port = 502;                     // Default Modbus TCP port
        private const byte      SlaveID = 247;                  // Modbus slave ID
        private const ushort    RegisterStartAddress = 0;       // Starting address to read
        private const ushort    NumRegisters = 9;               // Number of registers to read
        private const ushort    CoilStartAddress = 0;           // Starting address to write coils

        private static void Main(string[] args)
        {
            WriteLine("ModbusProgram begins here...\n\n");
            try
            {
                using TcpClient client = new(IPaddress, Port);
                // Build a client
                ModbusIpMaster master = ModbusIpMaster.CreateIp(client);
                WriteLine("CreateIp done\n");
                // Read register values
                ushort[] registers = master.ReadHoldingRegisters(SlaveID, RegisterStartAddress, NumRegisters);
                WriteLine("ReadHoldingRegisters done\n");
                DisplayRegisters(registers, RegisterStartAddress);
                WriteLine("\nDisplayRegisters done\n");
                // Set all channels as outputs
                master.WriteSingleRegister(SlaveID, 2, 0);
                WriteLine("WriteSingleRegister done.");
                // Write to specific outputs
                WriteIndividualCoils(master, registers, CoilStartAddress);
                WriteLine("WriteIndividualCoils done\n");
                // Write to groups of eight outputs at a time
                WriteAllOutputs(SlaveID, master);
                WriteLine("WriteAllOutputs done\n");
                ShutDown(SlaveID, master);
            }
            catch (Exception ex)
            {
                WriteLine("An error occurred:\n\n" + ex.Message);
            }
            finally
            {
                WriteLine("\nModbusProgram ends here.\n");
                _ = ReadKey(true);
            }
        }

        // Print registers we found and their values
        private static void DisplayRegisters(ushort[] registers, ushort startAddress)
        {
            WriteLine($"Read {registers.Length} registers starting at address {startAddress}:");
            for (int i = 0; i < registers.Length; i++)
            {
                WriteLine($"Register {startAddress + i}: {registers[i]}");
            }
        }

        // Exercise two racks, eight points at a time
        private static void WriteAllOutputs(ushort slaveID, ModbusIpMaster master)
        {
            bool[] valueArrayON = [true, false, true, false, true, false, true, false];
            bool[] valueArrayOFF = [false, true, false, true, false, true, false, true];

            WriteLine("Writing to two boards at once:\n");
            for (ushort j = 0; j < 4; j++)
            {
                for (ushort i = 0; i < 6; i++)
                {
                    master.WriteMultipleCoils((byte)slaveID, (ushort)(i * 8), valueArrayON);
                }
                Thread.Sleep(150);
                for (ushort i = 0; i < 6; i++)
                {
                    master.WriteMultipleCoils((byte)slaveID, (ushort)(i * 8), valueArrayOFF);
                }
            }
        }

        // Execise individual outputs
        private static void WriteIndividualCoils(ModbusIpMaster master, ushort[] registers, ushort coilStartAddress)
        {
            WriteLine("The value of 'coilStartAddress' is {0}", coilStartAddress);
            for (int i = 0; i < registers.Length; i++)
            {
                WriteLine(registers[i]);
            }
            DisplayRegisters(registers, RegisterStartAddress);
            for (ushort j = 0; j < 4; j++)
            {
                WriteLine("Turning the outputs ON.");

                for (ushort i = 0; i < 48; i++)
                {
                    master.WriteSingleCoil(SlaveID, i, true);
                }
                for (ushort i = 0; i < 48; i++)
                {
                    master.WriteSingleCoil(SlaveID, i, false);
                }
            }
            WriteLine("\nDone writing individual outputs!\n\n");
        }

        // Shut off all outputs
        private static void ShutDown(ushort slaveID, ModbusIpMaster master)
        {
            bool[] valueArrayOFF = [false, false, false, false, false, false, false, false];

            for (ushort i = 0; i < 6; i++)
            {
                master.WriteMultipleCoils((byte)slaveID, (ushort)(i * 8), valueArrayOFF);
            }
        }
    }
}