Add basic program logic
This commit is contained in:
25
Sharp7.Monitor.sln
Normal file
25
Sharp7.Monitor.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34728.123
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharp7.Monitor", "Sharp7.Monitor\Sharp7.Monitor.csproj", "{9E5BF5E6-D1A1-4252-92DA-B66A04C744D0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9E5BF5E6-D1A1-4252-92DA-B66A04C744D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9E5BF5E6-D1A1-4252-92DA-B66A04C744D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9E5BF5E6-D1A1-4252-92DA-B66A04C744D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9E5BF5E6-D1A1-4252-92DA-B66A04C744D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D9D2B518-DC9C-4776-85F3-BB507BC3DA21}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
160
Sharp7.Monitor/Program.cs
Normal file
160
Sharp7.Monitor/Program.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Threading.Tasks;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Sharp7.Read;
|
||||
using Sharp7.Rx;
|
||||
using Sharp7.Rx.Enums;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
Console.InputEncoding = Console.OutputEncoding = Encoding.UTF8;
|
||||
|
||||
using var cancellationSource = new CancellationTokenSource();
|
||||
|
||||
Console.CancelKeyPress += OnCancelKeyPress;
|
||||
AppDomain.CurrentDomain.ProcessExit += onProcessExit;
|
||||
|
||||
|
||||
void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e)
|
||||
{
|
||||
if (!cancellationSource.IsCancellationRequested)
|
||||
// NOTE: cancel event, don't terminate the process
|
||||
e.Cancel = true;
|
||||
|
||||
cancellationSource.Cancel();
|
||||
}
|
||||
|
||||
void onProcessExit(object? sender, EventArgs e)
|
||||
{
|
||||
if (cancellationSource.IsCancellationRequested)
|
||||
{
|
||||
// NOTE: SIGINT (cancel key was pressed, this shouldn't ever actually hit however, as we remove the event handler upon cancellation of the `cancellationSource`)
|
||||
return;
|
||||
}
|
||||
|
||||
cancellationSource.Cancel();
|
||||
}
|
||||
|
||||
await using var t = cancellationSource.Token.Register(() => Console.WriteLine("Cancelled!"));
|
||||
|
||||
try
|
||||
{
|
||||
var app = new CommandApp<ReadPlcCommand>();
|
||||
app.WithData(cancellationSource.Token);
|
||||
return await app.RunAsync(args);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.WriteLine("all done");
|
||||
AppDomain.CurrentDomain.ProcessExit -= onProcessExit;
|
||||
Console.CancelKeyPress -= OnCancelKeyPress;
|
||||
}
|
||||
|
||||
internal sealed class ReadPlcCommand : AsyncCommand<ReadPlcCommand.Settings>
|
||||
{
|
||||
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
|
||||
{
|
||||
var token = (CancellationToken) (context.Data ?? CancellationToken.None);
|
||||
AnsiConsole.WriteLine();
|
||||
AnsiConsole.MarkupLine($"Establishing connection to plc [green]{settings.PlcIp}[/], CPU [green]{settings.CpuMpiAddress}[/], rack [green]{settings.RackNumber}[/].");
|
||||
using var plc = new Sharp7Plc(settings.PlcIp, settings.RackNumber, settings.CpuMpiAddress);
|
||||
|
||||
await plc.InitializeAsync();
|
||||
|
||||
// Connect
|
||||
await AnsiConsole.Status()
|
||||
.Spinner(Spinner.Known.BouncingBar)
|
||||
.StartAsync("Connecting...", async ctx =>
|
||||
{
|
||||
var lastState = ConnectionState.Initial;
|
||||
ctx.Status(lastState.ToString());
|
||||
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var state = await plc.ConnectionState.FirstAsync(s => s != lastState).ToTask(token);
|
||||
ctx.Status(state.ToString());
|
||||
|
||||
if (state == ConnectionState.Connected)
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return 0;
|
||||
|
||||
// Create a table
|
||||
var table = new Table();
|
||||
|
||||
table.AddColumn("Variable");
|
||||
table.AddColumn("Value");
|
||||
|
||||
foreach (var variable in settings.Variables)
|
||||
{
|
||||
table.AddRow(variable, "");
|
||||
}
|
||||
|
||||
await AnsiConsole.Live(table)
|
||||
.StartAsync(async ctx =>
|
||||
{
|
||||
int i = 0;
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
table.Rows.Update(0, 1, new Text((++i).ToString()));
|
||||
ctx.Refresh();
|
||||
await Task.Delay(1000, token);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//for (int i = 0; i < 10; i++)
|
||||
//{
|
||||
// await plc.SetValue($"DB{db}.Int6", (short)i);
|
||||
// var value = await plc.GetValue<short>($"DB{db}.Int6");
|
||||
// value.Dump();
|
||||
|
||||
// await Task.Delay(200);
|
||||
//}
|
||||
|
||||
|
||||
// AnsiConsole.MarkupLine($"Total file size for [green]{searchPattern}[/] files in [green]{searchPath}[/]: [blue]{totalFileSize:N0}[/] bytes");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[NoReorder]
|
||||
public sealed class Settings : CommandSettings
|
||||
{
|
||||
[Description("IP address of S7")]
|
||||
[CommandArgument(0, "<IP address>")]
|
||||
public string PlcIp { get; init; }
|
||||
|
||||
[CommandArgument(1, "[variables]")]
|
||||
[Description("Variables to read from S7, like Db200.Int4.\r\nFor format description see https://github.com/evopro-ag/Sharp7Reactive.")]
|
||||
public string[] Variables { get; init; }
|
||||
|
||||
[CommandOption("-c|--cpu")]
|
||||
[Description("CPU MPI address of S7 instance.\r\nSee https://github.com/fbarresi/Sharp7/wiki/Connection#rack-and-slot.\r\n")]
|
||||
[DefaultValue(0)]
|
||||
public int CpuMpiAddress { get; init; }
|
||||
|
||||
[CommandOption("-r|--rack")]
|
||||
[Description("Rack number of S7 instance.\r\nSee https://github.com/fbarresi/Sharp7/wiki/Connection#rack-and-slot.\r\n")]
|
||||
[DefaultValue(0)]
|
||||
public int RackNumber { get; init; }
|
||||
|
||||
public override ValidationResult Validate()
|
||||
{
|
||||
if (!StringHelper.IsValidIp4(PlcIp))
|
||||
return ValidationResult.Error($"\"{PlcIp}\" is not a valid IP V4 address");
|
||||
|
||||
if (Variables == null || Variables.Length == 0)
|
||||
return ValidationResult.Error("Please supply at least one variable to read");
|
||||
|
||||
return ValidationResult.Success();
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Sharp7.Monitor/Properties/launchSettings.json
Normal file
8
Sharp7.Monitor/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Sharp7.Monitor": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "10.30.110.62 DB2050.String10.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Sharp7.Monitor/Sharp7.Monitor.csproj
Normal file
17
Sharp7.Monitor/Sharp7.Monitor.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Spectre.Console" Version="0.49.0" />
|
||||
<PackageReference Include="Spectre.Console.Cli" Version="0.49.0" />
|
||||
<PackageReference Include="Sharp7.Rx" Version="2.0.8-prerelease" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" PrivateAssets="All"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
13
Sharp7.Monitor/StringHelper.cs
Normal file
13
Sharp7.Monitor/StringHelper.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Sharp7.Read;
|
||||
|
||||
public static class StringHelper
|
||||
{
|
||||
public static bool IsValidIp4(string? ipString)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ipString))
|
||||
return false;
|
||||
|
||||
var splitValues = ipString.Split('.');
|
||||
return splitValues.Length == 4 && splitValues.All(r => byte.TryParse(r, out _));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user