Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpReadCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public TcpReadCommand(ITcpModbusClient client,
                              ILogger <TcpReadCommand> logger)
            : base("read", "Supporting Modbus TCP 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).");
                }

                return(null);
            });

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

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

                // Using TCP client options.
                client.TcpSlave.Address         = options.Address;
                client.TcpSlave.Port            = options.Port;
                client.TcpSlave.ID              = options.SlaveID;
                client.TcpMaster.ReceiveTimeout = options.ReceiveTimeout;
                client.TcpMaster.SendTimeout    = options.SendTimeout;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("TcpMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpMasterData>(client.TcpMaster, _jsonoptions));
                    console.Out.Write("TcpSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpSlaveData>(client.TcpSlave, _jsonoptions));
                    console.Out.WriteLine();
                }

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

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

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

                        // Reading input registers.
                        if (options.Input)
                        {
                            CommandHelper.ReadingInputRegisters(console,
                                                                client,
                                                                options.SlaveID,
                                                                options.Number,
                                                                options.Offset,
                                                                options.Type,
                                                                options.Hex);
                        }
                    }
                    else
                    {
                        console.Out.WriteLine($"Modbus TCP slave not found at {options.Address}:{options.Port}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }

                return(ExitCodes.SuccessfullyCompleted);
            });
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpMonitorCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public TcpMonitorCommand(ITcpModbusClient client,
                                 ILogger <TcpMonitorCommand> logger)
            : base("monitor", "Supporting Modbus TCP 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, TcpMonitorCommandOptions>(async(console, token, verbose, options) =>
            {
                logger.LogInformation("Handler()");

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

                // Using TCP client options.
                client.TcpSlave.Address         = options.Address;
                client.TcpSlave.Port            = options.Port;
                client.TcpSlave.ID              = options.SlaveID;
                client.TcpMaster.ReceiveTimeout = options.ReceiveTimeout;
                client.TcpMaster.SendTimeout    = options.SendTimeout;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("TcpMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpMasterData>(client.TcpMaster, _jsonoptions));
                    console.Out.Write("TcpSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpSlaveData>(client.TcpSlave, _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 TCP slave not found at {options.Address}:{options.Port}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.NotSuccessfullyCompleted);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }

                return(ExitCodes.SuccessfullyCompleted);
            });
        }
Beispiel #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="tcpReadCommand"></param>
        /// <param name="tcpWriteCommand"></param>
        /// <param name="tcpMonitorCommand"></param>
        /// <param name="settings"></param>
        /// <param name="logger"></param>
        public TcpCommand(ITcpModbusClient client,
                          TcpReadCommand tcpReadCommand,
                          TcpWriteCommand tcpWriteCommand,
                          TcpMonitorCommand tcpMonitorCommand,
                          AppSettings settings,
                          ILogger <TcpCommand> logger)
            : base("tcp", "Subcommand supporting standard Modbus TCP operations.")
        {
            // Setup command options.
            AddGlobalOption(new Option <string>("--address", "Sets the Modbus slave IP address").Name("Address").Default(settings.TcpSlave.Address).IPAddress());
            AddGlobalOption(new Option <int>("--port", "Sets the Modbus slave IP port").Name("Port").Default(settings.TcpSlave.Port).Range(0, 65535));
            AddGlobalOption(new Option <byte>("--slaveid", "Sets the Modbus slave ID").Name("SlaveID").Default(settings.TcpSlave.ID));
            AddGlobalOption(new Option <int>("--receive-timeout", "Sets the receive timeout").Name("ReceiveTimeout").Default(settings.TcpMaster.ReceiveTimeout).Range(0, Int32.MaxValue).Hide());
            AddGlobalOption(new Option <int>("--send-timeout", "Sets the send timeout").Name("SendTimeout").Default(settings.TcpMaster.SendTimeout).Range(0, Int32.MaxValue).Hide());

            // Add sub commands.
            AddCommand(tcpReadCommand);
            AddCommand(tcpWriteCommand);
            AddCommand(tcpMonitorCommand);

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

                // Using TCP client options.
                client.TcpSlave.Address         = options.Address;
                client.TcpSlave.Port            = options.Port;
                client.TcpSlave.ID              = options.SlaveID;
                client.TcpMaster.ReceiveTimeout = options.ReceiveTimeout;
                client.TcpMaster.SendTimeout    = options.SendTimeout;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("TcpMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpMasterData>(client.TcpMaster, _jsonoptions));
                    console.Out.Write("TcpSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpSlaveData>(client.TcpSlave, _jsonoptions));
                    console.Out.WriteLine();
                }

                try
                {
                    if (client.Connect())
                    {
                        console.Out.WriteLine($"Modbus TCP slave found at {options.Address}:{options.Port}.");
                        return(ExitCodes.SuccessfullyCompleted);
                    }
                    else
                    {
                        console.Out.WriteLine($"Modbus TCP slave not found at {options.Address}:{options.Port}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }
            });
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TcpWriteCommand"/> class.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="logger"></param>
        public TcpWriteCommand(ITcpModbusClient client,
                               ILogger <TcpWriteCommand> logger)
            : base("write", "Supporting Modbus TCP 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 optionN    = r.Children.Contains("n");
                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, TcpWriteCommandOptions>((console, verbose, options) =>
            {
                logger.LogInformation("Handler()");

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

                // Using TCP client options.
                client.TcpSlave.Address         = options.Address;
                client.TcpSlave.Port            = options.Port;
                client.TcpSlave.ID              = options.SlaveID;
                client.TcpMaster.ReceiveTimeout = options.ReceiveTimeout;
                client.TcpMaster.SendTimeout    = options.SendTimeout;

                if (verbose)
                {
                    console.Out.WriteLine($"Modbus Commandline Application: {RootCommand.ExecutableName}");
                    console.Out.WriteLine();
                    console.Out.Write("TcpMasterData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpMasterData>(client.TcpMaster, _jsonoptions));
                    console.Out.Write("TcpSlaveData: ");
                    console.Out.WriteLine(JsonSerializer.Serialize <TcpSlaveData>(client.TcpSlave, _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.Out.WriteLine($"Modbus TCP slave not found at {options.Address}:{options.Port}.");
                        return(ExitCodes.NotSuccessfullyCompleted);
                    }
                }
                catch (JsonException jex)
                {
                    logger.LogError(jex, $"Exception parsing JSON data values.");
                    return(ExitCodes.NotSuccessfullyCompleted);
                }
                catch (Exception ex)
                {
                    console.Out.WriteLine($"Exception: {ex.Message}");
                    return(ExitCodes.UnhandledException);
                }
                finally
                {
                    if (client.Connected)
                    {
                        client.Disconnect();
                    }
                }

                return(ExitCodes.SuccessfullyCompleted);
            });
        }