/// <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); }); }
/// <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(); } } }); }
/// <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); }); }