Skip to content

Commit

Permalink
Update bulk read, Add pause polling to enable larger manual reads
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisPulman committed Aug 2, 2023
1 parent 87e1d21 commit 3c76a83
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 161 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<ItemGroup>
<!--<Compile Update="**\*.cs" DependentUpon="I%(Filename).cs" />-->
<PackageReference Include="stylecop.analyzers" Version="1.2.0-beta.507" PrivateAssets="all" />
<PackageReference Include="Roslynator.Analyzers" Version="4.3.0" PrivateAssets="All" />
<PackageReference Include="Roslynator.Analyzers" Version="4.4.0" PrivateAssets="All" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)stylecop.json" Link="stylecop.json" />
</ItemGroup>
</Project>
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
</p>

# S7PlcRx
S7 PLC Communications Library
Reactive S7 PLC Communications Library

## Introduction
S7PlcRx is a library that provides a simple interface to communicate with Siemens S7 PLCs.

## Features
- Read and Write to PLC
- Read and Write to PLC with Subscription
- Read from PLC with Reactive Subscription


## Getting Started
Expand All @@ -36,12 +36,28 @@ dotnet add package S7PlcRx
```csharp
using S7PlcRx;

var plc = new RxS7(S7PlcRx.Enums.CpuType.S71500, "", 0, 1);
plc.AddUpdateTagItem<double>("Tag0", "DB500.DBD0");
var plc = new RxS7(S7PlcRx.Enums.CpuType.S71500, "PLC_IP_ADDRESS", 0, 5);
// Add Tag without Polling
plc.AddUpdateTagItem<double>("Tag0", "DB500.DBD0").SetTagPollIng(false);
// Add Tag with Polling
plc.AddUpdateTagItem<double>("Tag1", "DB500.DBD8");

plc.IsConnected
.Where(x => x)
.Take(1)
.Subscribe(async _ =>
{
Console.WriteLine("Connected");

// Read Tag Value manually
var tag0 = await plc.Value<double>("Tag0");
});

// Subscribe to Tag Values
plc.Observe<double>("Tag0").Subscribe(x => Console.WriteLine($"Tag0: {x}"));
plc.Observe<double>("Tag1").Subscribe(x => Console.WriteLine($"Tag1: {x}"));
// Start Polling on previously disabled Tag
plc?.GetTag("Tag0")?.SetTagPollIng(true);
```

#### Write to PLC
Expand Down
2 changes: 1 addition & 1 deletion Version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.1.1",
"version": "1.1.2",
"publicReleaseRefSpec": [
"^refs/heads/master$",
"^refs/heads/main$"
Expand Down
4 changes: 2 additions & 2 deletions build/_build.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CP.Nuke.BuildTools" Version="1.0.13" />
<PackageReference Include="CP.Nuke.BuildTools" Version="1.0.14" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" />
<PackageReference Include="Nuke.Common" Version="7.0.2" />
</ItemGroup>
Expand Down
116 changes: 60 additions & 56 deletions src/S7PlcRx.TestApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,76 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reactive.Linq;
using System.Text;
using S7PlcRx;

var plc = new RxS7(S7PlcRx.Enums.CpuType.S71500, "172.16.17.1", 0, 1, interval: 5);
plc.LastError.Subscribe(ex => Console.WriteLine(ex));
plc.Status.Subscribe(status => Console.WriteLine(status));
const string DB100_DBB3 = nameof(DB100_DBB3);
const string PlcData = nameof(PlcData);
const string TestItems = nameof(TestItems);
const string TagNames1 = nameof(TagNames1);
const string TagNames2 = nameof(TagNames2);
const string TagValues = nameof(TagValues);

const string Tag0_To_99 = nameof(Tag0_To_99);
const string StringArea = nameof(StringArea);
////for (var i = 0; i < 100; i++)
{
plc.AddUpdateTagItem<double[]>(Tag0_To_99, "DB103.DBD0", 99);
plc.AddUpdateTagItem<byte[]>(StringArea, "DB101.DBB0", 264).SetTagNoPoll(true);
}
plc.AddUpdateTagItem<byte>(DB100_DBB3, "DB100.DBB3");
plc.AddUpdateTagItem<byte[]>(PlcData, "DB100.DBB0", 64).SetTagPollIng(false);
plc.AddUpdateTagItem<byte[]>(TestItems, "DB101.DBB0", 520).SetTagPollIng(false);
plc.AddUpdateTagItem<byte[]>(TagNames1, "DB102.DBB0", 4096).SetTagPollIng(false);
plc.AddUpdateTagItem<double[]>(TagValues, "DB103.DBD0", 99).SetTagPollIng(false);

plc.IsConnected.Subscribe(x =>
{
if (x)
plc.IsConnected
.Where(x => x)
.Take(1)
.Subscribe(_ =>
{
Console.WriteLine("Connected");
var v = plc.Value<byte[]>(StringArea);
}
else
{
Console.WriteLine("Disconnected");
}
});

////plc.Observe<double>("Tag0").Subscribe(x => Console.WriteLine($"Tag0: {x}"));
////plc.Observe<double>("Tag1").Subscribe(x => Console.WriteLine($"Tag1: {x}"));
var count = 0;
plc.ReadTime
.Select(x => TimeSpan.FromTicks(x).TotalMilliseconds)
.TimeInterval()
.Buffer(200)
.Select(x => (ExectionTime: x.Select(x => x.Interval.TotalMilliseconds).Average(), Value: x.Select(x => x.Value).Average()))
.CombineLatest(
plc.Observe<double[]>(Tag0_To_99).ToTagValue(Tag0_To_99))
.Subscribe(values =>
{
count++;
if (count % 200 == 0)
{
count = 0;
var sb = new StringBuilder();
sb.Append("Read time: ").Append(values.First).Append(" ms");
if (values.First.Value > 5)
plc.IsPaused.Subscribe(x => Console.WriteLine($"Paused: {x}"));
var setupComplete = false;
plc.Observe<byte>(DB100_DBB3)
.Select(v => v == 1)
.Where(_ => !setupComplete)
.Do(v =>
{
Console.ForegroundColor = ConsoleColor.Red;
}
else
Console.WriteLine($"DB100 DBB3 value: {v}");
plc?.GetTag(DB100_DBB3)?.SetTagPollIng(false);
})
.Subscribe(async _ =>
{
Console.ForegroundColor = ConsoleColor.Green;
}

Console.WriteLine(sb.ToString());
Console.ResetColor();
sb.Clear().Append("Tag = ").Append(values.Second.Tag);
for (var i = 0; i < values.Second.Value.Length; i++)
{
sb.Append(", Value").Append(i).Append(" = ").Append(values.Second.Value[i]).Append(" / ");
}

Console.WriteLine(sb.ToString());
}
Console.WriteLine("Setup started");
Console.WriteLine("Reading PlcData");
var bytesPlcData = await plc?.Value<byte[]>(PlcData)!;
Console.WriteLine($"bytesPlcData: {bytesPlcData?.Length}");
await Task.Delay(500);
Console.WriteLine("Reading TestItems");
var bytesTestItems = await plc?.Value<byte[]>(TestItems)!;
Console.WriteLine($"bytesTestItems: {bytesTestItems?.Length}");
await Task.Delay(500);
Console.WriteLine("Reading TagNames");
var bytesTagNames1 = await plc?.Value<byte[]>(TagNames1)!;
Console.WriteLine($"bytesTagNames1: {bytesTagNames1?.Length}");
await Task.Delay(500);
var dummy = await plc?.Value<byte>(DB100_DBB3)!;
Console.WriteLine($"dummy: {dummy}");
await Task.Delay(500);
Console.WriteLine("Setup complete");
plc?.GetTag(TagValues)?.SetTagPollIng(true);
setupComplete = true;
});
plc.Observe<double[]>(TagValues)
.Where(_ => setupComplete)
.Subscribe(values =>
{
try
{
var tagValues = values?.Take(14).Select(Convert.ToSingle).ToArray();
Console.WriteLine($"TagValues: {string.Join(", ", tagValues!)}");
}
catch (Exception ex)
{
}
});
});

////plc.ReadTime.Select(x => TimeSpan.FromTicks(x).TotalMilliseconds).Buffer(200).Select(x => x.Average()).Subscribe(time => Console.WriteLine($"Read time: {time}"));

Console.WriteLine("Press any key to exit...");
Console.ReadKey();
26 changes: 22 additions & 4 deletions src/S7PlcRx/ExtensionsMixins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,29 @@ public static ITag AddUpdateTagItem<T>(this IRxS7 @this, string tagName, string
}

/// <summary>
/// Sets the tag no poll.
/// Sets the tag to poll for values.
/// </summary>
/// <param name="this">The instance of plc.</param>
/// <param name="poll">if set to <c>true</c> [poll].</param>
public static void SetTagNoPoll(this ITag @this, bool poll) => @this?.SetDoNotPoll(poll);
/// <param name="this">The instance of tag.</param>
/// <param name="polling">if set to <c>true</c> [poll].</param>
/// <returns>The instance.</returns>
public static ITag? SetTagPollIng(this ITag? @this, bool polling = true)
{
@this?.SetDoNotPoll(!polling);
return @this;
}

/// <summary>
/// Gets the tag.
/// </summary>
/// <param name="this">The rx s7 plc instance.</param>
/// <param name="tagName">Name of the tag.</param>
/// <returns>The instance of tag.</returns>
public static ITag? GetTag(this IRxS7 @this, string tagName) =>
@this?.TagList[tagName!] switch
{
Tag tag => tag,
_ => default
};

/// <summary>
/// Removes the tag item.
Expand Down
14 changes: 11 additions & 3 deletions src/S7PlcRx/IRxS7.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ public interface IRxS7 : ICancelable
/// </value>
short Slot { get; }

/// <summary>
/// Gets a value indicating whether this instance is paused.
/// </summary>
/// <value>
/// <c>true</c> if this instance is paused; otherwise, <c>false</c>.
/// </value>
IObservable<bool> IsPaused { get; }

/// <summary>
/// Gets the status.
/// </summary>
Expand Down Expand Up @@ -133,15 +141,15 @@ public interface IRxS7 : ICancelable
IObservable<T?> Observe<T>(string? variable);

/// <summary>
/// Values the specified variable.
/// Reads the specified variable.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="variable">The variable.</param>
/// <returns>A value of T.</returns>
T? Value<T>(string? variable);
Task<T?> Value<T>(string? variable);

/// <summary>
/// Values the specified variable.
/// Writes the specified variable.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <param name="variable">The variable.</param>
Expand Down
Loading

0 comments on commit 3c76a83

Please sign in to comment.