Пример #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="RWSingleController"/> class.
 /// </summary>
 /// <param name="client"></param>
 /// <param name="settings"></param>
 /// <param name="config"></param>
 /// <param name="environment"></param>
 /// <param name="lifetime"></param>
 /// <param name="logger"></param>
 public RWSingleController(IRtuModbusClient client,
                           AppSettings settings,
                           IConfiguration config,
                           IHostEnvironment environment,
                           IHostApplicationLifetime lifetime,
                           ILogger <RWSingleController> logger)
     : base(client, settings, config, environment, lifetime, logger)
 {
 }
Пример #2
0
        /// <summary>
        /// Reading the specified data.
        /// </summary>
        private void ReadingData(IRtuModbusClient client,
                                 IConsole console,
                                 ILogger <RtuMonitorCommand> logger,
                                 RtuMonitorCommandOptions options,
                                 bool header)
        {
            logger?.LogDebug("TcpMonitor: Reading data...");

            // Reading coils.
            if (options.Coil)
            {
                CommandHelper.ReadingCoils(console,
                                           client,
                                           options.SlaveID,
                                           options.Number,
                                           options.Offset,
                                           header);
            }

            // Reading discrete inputs.
            if (options.Discrete)
            {
                CommandHelper.ReadingDiscreteInputs(console,
                                                    client,
                                                    options.SlaveID,
                                                    options.Number,
                                                    options.Offset,
                                                    header);
            }

            // Reading holding registers.
            if (options.Holding)
            {
                CommandHelper.ReadingHoldingRegisters(console,
                                                      client,
                                                      options.SlaveID,
                                                      options.Number,
                                                      options.Offset,
                                                      options.Type,
                                                      options.Hex,
                                                      header);
            }

            // Reading input registers.
            if (options.Input)
            {
                CommandHelper.ReadingInputRegisters(console,
                                                    client,
                                                    options.SlaveID,
                                                    options.Number,
                                                    options.Offset,
                                                    options.Type,
                                                    options.Hex,
                                                    header);
            }
        }
Пример #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RtuCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="rtuReadCommand"></param>
        /// <param name="rtuWriteCommand"></param>
        /// <param name="rtuMonitorCommand"></param>
        /// <param name="settings"></param>
        /// <param name="logger"></param>
        public RtuCommand(IRtuModbusClient client,
                          RtuReadCommand rtuReadCommand,
                          RtuWriteCommand rtuWriteCommand,
                          RtuMonitorCommand rtuMonitorCommand,
                          AppSettings settings,
                          ILogger <RtuCommand> logger)
            : base("rtu", "Subcommand supporting standard Modbus RTU operations.")
        {
            // Setup command options.
            AddGlobalOption(new Option <string>  ("--serialport", "Sets the Modbus master COM port").Name("SerialPort").Default(settings.RtuMaster.SerialPort));
            AddGlobalOption(new Option <int>     ("--baudrate", "Sets the Modbus COM port baud rate").Name("Baudrate").Default(settings.RtuMaster.Baudrate));
            AddGlobalOption(new Option <Parity>  ("--parity", "Sets the Modbus COM port parity").Name("Parity").Default(settings.RtuMaster.Parity));
            AddGlobalOption(new Option <int>     ("--databits", "Sets the Modbus COM port data bits").Name("DataBits").Default(settings.RtuMaster.DataBits).Range(5, 8));
            AddGlobalOption(new Option <StopBits>("--stopbits", "Sets the Modbus COM port stop bits").Name("StopBits").Default(settings.RtuMaster.StopBits));
            AddGlobalOption(new Option <byte>    ("--slaveid", "Sets the Modbus slave ID").Name("SlaveID").Default(settings.RtuSlave.ID));
            AddGlobalOption(new Option <int>     ("--read-timeout", "Sets the read timeout").Name("ReadTimeout").Default(settings.RtuMaster.ReadTimeout).Range(-1, Int32.MaxValue).Hide());
            AddGlobalOption(new Option <int>     ("--write-timeout", "Sets the read timeout").Name("WriteTimeout").Default(settings.RtuMaster.WriteTimeout).Range(-1, Int32.MaxValue).Hide());

            // Add sub commands.
            AddCommand(rtuReadCommand);
            AddCommand(rtuWriteCommand);
            AddCommand(rtuMonitorCommand);

            // Add custom validation.
            AddValidator(r =>
            {
                var valid = new System.Collections.Generic.List <int> {
                    110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 31250, 38400, 56000, 57600, 76800, 115200, 128000, 230400, 256000
                };
                var result = r.Children["baudrate"];
                var value  = (result.Tokens.Count == 0) ? settings.RtuMaster.Baudrate : r.ValueForOption <int>("baudrate");
                if (valid.Contains(value))
                {
                    return(null);
                }
                return("Invalid Baudrate (select from: 110|150|300|600|1200|1800|2400|4800|7200|9600|14400|19200|31250|38400|56000|57600|76800|115200|128000|230400|256000).");
            });

            // Setup execution handler.
            Handler = CommandHandler.Create <IConsole, bool, RtuCommandOptions>((console, verbose, options) =>
            {
                logger.LogInformation("Handler()");

                // Using RTU client options.
                client.RtuMaster.SerialPort   = options.SerialPort;
                client.RtuMaster.Baudrate     = options.Baudrate;
                client.RtuMaster.Parity       = options.Parity;
                client.RtuMaster.DataBits     = options.DataBits;
                client.RtuMaster.StopBits     = options.StopBits;
                client.RtuMaster.ReadTimeout  = options.ReadTimeout;
                client.RtuMaster.WriteTimeout = options.WriteTimeout;
                client.RtuSlave.ID            = options.SlaveID;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("RtuMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuMasterData>(client.RtuMaster, _jsonoptions));
                    console.Out.Write("RtuSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuSlaveData>(client.RtuSlave, _jsonoptions));
                    console.Out.WriteLine();
                }

                try
                {
                    if (client.Connect())
                    {
                        Console.WriteLine($"RTU serial port found at {options.SerialPort}.");
                        return(ExitCodes.SuccessfullyCompleted);
                    }
                    else
                    {
                        Console.WriteLine($"RTU serial port not found at {options.SerialPort}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }
            });
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RtuMonitorCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public RtuMonitorCommand(IRtuModbusClient client,
                                 ILogger <RtuMonitorCommand> logger)
            : base("monitor", "Supporting Modbus RTU monitor operations.")
        {
            // Setup command options.
            AddOption(new Option <bool>  (new string[] { "-?", "--help" }, "Show help and usage information"));
            AddOption(new Option <bool>  (new string[] { "-c", "--coil" }, "Reads coil(s)"));
            AddOption(new Option <bool>  (new string[] { "-d", "--discrete" }, "Reads discrete input(s)"));
            AddOption(new Option <bool>  (new string[] { "-h", "--holding" }, "Reads holding register(s)"));
            AddOption(new Option <bool>  (new string[] { "-i", "--input" }, "Reads input register(s)"));
            AddOption(new Option <bool>  (new string[] { "-x", "--hex" }, "Displays the values in HEX"));
            AddOption(new Option <ushort>(new string[] { "-n", "--number" }, "The number of items to read").Name("Number").Default((ushort)1));
            AddOption(new Option <ushort>(new string[] { "-o", "--offset" }, "The offset of the first item").Name("Offset").Default((ushort)0));
            AddOption(new Option <string>(new string[] { "-t", "--type" }, "Reads the specified data type").Name("Type")
                      .FromAmong("bits", "string", "byte", "short", "ushort", "int", "uint", "float", "double", "long", "ulong"));
            AddOption(new Option <uint>  (new string[] { "-r", "--repeat" }, "The number of times to read").Name("Repeat").Default((uint)10));
            AddOption(new Option <uint>  (new string[] { "-s", "--seconds" }, "The seconds between read times").Name("Seconds").Default((uint)1));

            // Add custom validation.
            AddValidator(r =>
            {
                var optionHelp = r.Children.Contains("?");
                var optionC    = r.Children.Contains("c");
                var optionD    = r.Children.Contains("d");
                var optionH    = r.Children.Contains("h");
                var optionI    = r.Children.Contains("i");
                var optionX    = r.Children.Contains("x");
                var optionN    = r.Children.Contains("n");
                var optionO    = r.Children.Contains("o");
                var optionT    = r.Children.Contains("t");

                if ((!optionC && !optionD && !optionH && !optionI) ||
                    ((optionC && (optionD || optionH || optionI)) ||
                     (optionD && (optionC || optionH || optionI)) ||
                     (optionH && (optionD || optionC || optionI)) ||
                     (optionI && (optionD || optionH || optionC))) || optionHelp)
                {
                    return("Specify a single read option (coils, discrete inputs, holding registers, input registers).");
                }

                return(null);
            });

            // Setup execution handler.
            Handler = CommandHandler.Create <IConsole, CancellationToken, bool, RtuMonitorCommandOptions>(async(console, token, verbose, options) =>
            {
                logger.LogInformation("Handler()");

                // Run additional checks on options.
                options.CheckOptions(console);

                // Using RTU client options.
                client.RtuMaster.SerialPort   = options.SerialPort;
                client.RtuMaster.Baudrate     = options.Baudrate;
                client.RtuMaster.Parity       = options.Parity;
                client.RtuMaster.DataBits     = options.DataBits;
                client.RtuMaster.StopBits     = options.StopBits;
                client.RtuMaster.ReadTimeout  = options.ReadTimeout;
                client.RtuMaster.WriteTimeout = options.WriteTimeout;
                client.RtuSlave.ID            = options.SlaveID;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("RtuMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuMasterData>(client.RtuMaster, _jsonoptions));
                    console.Out.Write("RtuSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuSlaveData>(client.RtuSlave, _jsonoptions));
                    console.Out.WriteLine();
                }

                try
                {
                    if (client.Connect())
                    {
                        try
                        {
                            bool forever = (options.Repeat == 0);
                            bool header  = true;
                            var time     = DateTime.UtcNow;

                            while (!token.IsCancellationRequested)
                            {
                                var start = DateTime.UtcNow;
#pragma warning disable CS8604 // Possible null reference argument (logger).
                                if (verbose && !header)
                                {
                                    console.Out.WriteLine($"Time elapsed {start - time:d'.'hh':'mm':'ss'.'fff}");
                                }
                                ReadingData(client, console, logger, options, header);
#pragma warning restore CS8604 // Possible null reference argument (logger).
                                // Only first call is printing the header.
                                header       = false;
                                var end      = DateTime.UtcNow;
                                double delay = options.Seconds - (end - start).TotalSeconds;

                                if (delay < 0)
                                {
                                    logger?.LogWarning($"Monitoring: no time between reads (min. {delay + options.Seconds}).");
                                }

                                if ((--options.Repeat > 0) && delay > 0)
                                {
                                    await Task.Delay(TimeSpan.FromSeconds(delay), token);
                                }

                                if (!forever && (options.Repeat == 0))
                                {
                                    break;
                                }
                            }
                        }
                        catch (AggregateException aex) when(aex.InnerExceptions.All(e => e is OperationCanceledException))
                        {
                            console.Out.WriteLine("Monitoring cancelled.");
                        }
                        catch (OperationCanceledException)
                        {
                            console.Out.WriteLine("Monitoring cancelled.");
                        }
                        catch (Exception ex)
                        {
                            console.Out.WriteLine($"Exception: {ex.Message}");
                            return(ExitCodes.UnhandledException);
                        }
                    }
                    else
                    {
                        console.Out.WriteLine($"Modbus RTU slave not found at {options.SerialPort}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }

                return(ExitCodes.SuccessfullyCompleted);
            });
        }
Пример #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RtuWriteCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public RtuWriteCommand(IRtuModbusClient client,
                               ILogger <RtuReadCommand> logger)
            : base("write", "Supporting Modbus RTU write operations.")
        {
            // Setup command arguments and options.
            AddOption(new Option <bool>  (new string[] { "-?", "--help" }, "Show help and usage information"));
            AddOption(new Option <string>(new string[] { "-c", "--coil" }, "Write coil(s).").Name("Json"));
            AddOption(new Option <string>(new string[] { "-h", "--holding" }, "Writes holding register(s).").Name("Json"));
            AddOption(new Option <bool>  (new string[] { "-x", "--hex" }, "Writes the HEX values (string)"));
            AddOption(new Option <ushort>(new string[] { "-o", "--offset" }, "The offset of the first item.").Name("Offset").Default((ushort)0));
            AddOption(new Option <string>(new string[] { "-t", "--type" }, "Reads the specified data type").Name("Type")
                      .FromAmong("bits", "string", "byte", "short", "ushort", "int", "uint", "float", "double", "long", "ulong"));

            // Add custom validation.
            AddValidator(r =>
            {
                var optionHelp = r.Children.Contains("?");
                var optionC    = r.Children.Contains("c");
                var optionH    = r.Children.Contains("h");
                var optionX    = r.Children.Contains("x");
                var optionO    = r.Children.Contains("o");
                var optionT    = r.Children.Contains("t");

                if ((!optionC && !optionH) || (optionC && optionH) || optionHelp)
                {
                    return("Specify a single write option (coils or holding registers).");
                }

                return(null);
            });

            // Setup execution handler.
            Handler = CommandHandler.Create <IConsole, bool, RtuWriteCommandOptions>((console, verbose, options) =>
            {
                logger.LogInformation("Handler()");

                // Run additional checks on options.
                options.CheckOptions(console);

                // Using RTU client options.
                client.RtuMaster.SerialPort   = options.SerialPort;
                client.RtuMaster.Baudrate     = options.Baudrate;
                client.RtuMaster.Parity       = options.Parity;
                client.RtuMaster.DataBits     = options.DataBits;
                client.RtuMaster.StopBits     = options.StopBits;
                client.RtuMaster.ReadTimeout  = options.ReadTimeout;
                client.RtuMaster.WriteTimeout = options.WriteTimeout;
                client.RtuSlave.ID            = options.SlaveID;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("RtuMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuMasterData>(client.RtuMaster, _jsonoptions));
                    console.Out.Write("RtuSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <RtuSlaveData>(client.RtuSlave, _jsonoptions));
                    console.Out.WriteLine();
                }

                try
                {
                    if (client.Connect())
                    {
                        // Writing coils.
                        CommandHelper.WritingCoils(console,
                                                   client,
                                                   options.SlaveID,
                                                   options.Offset,
                                                   options.Coil);

                        // Writing holding registers.
                        CommandHelper.WritingHoldingRegisters(console,
                                                              client,
                                                              options.SlaveID,
                                                              options.Offset,
                                                              options.Holding,
                                                              options.Type,
                                                              options.Hex);
                    }
                    else
                    {
                        Console.WriteLine($"Modbus RTU slave not found at {options.SerialPort}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (JsonException jex)
                {
                    console.Out.WriteLine(jex.Message);
                    return(ExitCodes.NotSuccessfullyCompleted);
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }

                return(ExitCodes.SuccessfullyCompleted);
            });
        }
Пример #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RtuReadCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public RtuReadCommand(IRtuModbusClient client,
                              ILogger <RtuReadCommand> logger)
            : base("read", "Supporting Modbus RTU read operations.")
        {
            // Setup command options.
            AddOption(new Option <bool>  (new string[] { "-?", "--help" }, "Show help and usage information"));
            AddOption(new Option <bool>  (new string[] { "-c", "--coil" }, "Reads coil(s)"));
            AddOption(new Option <bool>  (new string[] { "-d", "--discrete" }, "Reads discrete input(s)"));
            AddOption(new Option <bool>  (new string[] { "-h", "--holding" }, "Reads holding register(s)"));
            AddOption(new Option <bool>  (new string[] { "-i", "--input" }, "Reads input register(s)"));
            AddOption(new Option <bool>  (new string[] { "-x", "--hex" }, "Displays the values in HEX"));
            AddOption(new Option <ushort>(new string[] { "-n", "--number" }, "The number of items to read").Name("Number").Default((ushort)1));
            AddOption(new Option <ushort>(new string[] { "-o", "--offset" }, "The offset of the first item").Name("Offset").Default((ushort)0));
            AddOption(new Option <string>(new string[] { "-t", "--type" }, "Reads the specified data type").Name("Type")
                      .FromAmong("bits", "string", "byte", "short", "ushort", "int", "uint", "float", "double", "long", "ulong"));

            // Add custom validation.
            AddValidator(r =>
            {
                var optionHelp = r.Children.Contains("?");
                var optionC    = r.Children.Contains("c");
                var optionD    = r.Children.Contains("d");
                var optionH    = r.Children.Contains("h");
                var optionI    = r.Children.Contains("i");
                var optionX    = r.Children.Contains("x");
                var optionN    = r.Children.Contains("n");
                var optionO    = r.Children.Contains("o");
                var optionT    = r.Children.Contains("t");

                if ((!optionC && !optionD && !optionH && !optionI) ||
                    ((optionC && (optionD || optionH || optionI)) ||
                     (optionD && (optionC || optionH || optionI)) ||
                     (optionH && (optionD || optionC || optionI)) ||
                     (optionI && (optionD || optionH || optionC))) || optionHelp)
                {
                    return("Specify a single read option (coils, discrete inputs, holding registers, input registers).");
                }

                if (optionC || optionD)
                {
                    ushort number = (ushort)r.ValueForOption("n");

                    if ((number < 1) || (number > IModbusClient.MaxBooleanPoints))
                    {
                        return($"Number {number} is out of the range of valid values (1..{IModbusClient.MaxBooleanPoints}).");
                    }
                }

                if (optionH || optionI)
                {
                    ushort number = (ushort)r.ValueForOption("n");

                    if (optionT)
                    {
                        var type = (string)r.ValueForOption("t");

                        return(type switch
                        {
                            "bits" => (number > 1) ? "Only a single bit array value is supported." : null,
                            "string" => ((number < 1) || ((number + 1) / 2 > IModbusClient.MaxRegisterPoints)) ? $"Reading string values: number {number} is out of the range (max. {IModbusClient.MaxRegisterPoints} registers)."    : null,
                            "byte" => ((number < 1) || ((number + 1) / 2 > IModbusClient.MaxRegisterPoints)) ? $"Reading byte values: number {number} is out of the range (max. {IModbusClient.MaxRegisterPoints} registers)."      : null,
                            "short" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints))           ? $"Reading short values: number {number} is out of the range (max. {IModbusClient.MaxRegisterPoints} registers)."     : null,
                            "ushort" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints))           ? $"Reading ushort values: number {number} is out of the range (max. {IModbusClient.MaxRegisterPoints} registers)."    : null,
                            "int" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 2))       ? $"Reading int values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)."    : null,
                            "uint" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 2))       ? $"Reading uint values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)."   : null,
                            "float" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 2))       ? $"Reading float values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)."  : null,
                            "double" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 4))       ? $"Reading double values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)." : null,
                            "long" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 4))       ? $"Reading long values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)."   : null,
                            "ulong" => ((number < 1) || (number > IModbusClient.MaxRegisterPoints / 4))       ? $"Reading ulong values: number {number} is out of the range of (max. {IModbusClient.MaxRegisterPoints} registers)."  : null,
                            _ => $"Unknown type '{type}' (should not happen)."
                        });
                    }