Cache S7 variable names

This commit is contained in:
Peter Butzhammer
2024-02-06 13:39:55 +01:00
parent 49fe1968d9
commit 9b0749baae
5 changed files with 34 additions and 27 deletions

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Concurrent;
using Sharp7.Rx.Interfaces;
namespace Sharp7.Rx
{
internal class CacheVariableNameParser : IS7VariableNameParser
{
private static readonly ConcurrentDictionary<string, S7VariableAddress> addressCache = new ConcurrentDictionary<string, S7VariableAddress>(StringComparer.OrdinalIgnoreCase);
private readonly IS7VariableNameParser inner;
public CacheVariableNameParser(IS7VariableNameParser inner)
{
this.inner = inner;
}
public S7VariableAddress Parse(string input) => addressCache.GetOrAdd(input, inner.Parse);
}
}

View File

@@ -21,6 +21,6 @@ namespace Sharp7.Rx.Interfaces
Task<bool> WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNr, CancellationToken token); Task<bool> WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNr, CancellationToken token);
Task<ushort> WriteBytes(Operand operand, ushort startByteAdress, byte[] data, ushort dBNr, CancellationToken token); Task<ushort> WriteBytes(Operand operand, ushort startByteAdress, byte[] data, ushort dBNr, CancellationToken token);
ILogger Logger { get; } ILogger Logger { get; }
Task<Dictionary<string, byte[]>> ExecuteMultiVarRequest(IEnumerable<string> variableNames); Task<Dictionary<string, byte[]>> ExecuteMultiVarRequest(IReadOnlyList<string> variableNames);
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Sharp7.Rx
{ {
private static readonly Regex regex = new Regex(@"^(?<operand>db{1})(?<dbNr>\d{1,4})\.?(?<type>dbx|x|s|string|b|dbb|d|int|dbw|w|dint|dul|dulint|dulong|){1}(?<start>\d+)(\.(?<bitOrLength>\d+))?$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex regex = new Regex(@"^(?<operand>db{1})(?<dbNr>\d{1,4})\.?(?<type>dbx|x|s|string|b|dbb|d|int|dbw|w|dint|dul|dulint|dulong|){1}(?<start>\d+)(\.(?<bitOrLength>\d+))?$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly IReadOnlyDictionary<string, DbType> types = new Dictionary<string, DbType>(StringComparer.InvariantCultureIgnoreCase) private static readonly IReadOnlyDictionary<string, DbType> types = new Dictionary<string, DbType>(StringComparer.OrdinalIgnoreCase)
{ {
{"x", DbType.Bit}, {"x", DbType.Bit},
{"dbx", DbType.Bit}, {"dbx", DbType.Bit},

View File

@@ -21,7 +21,6 @@ namespace Sharp7.Rx
{ {
private readonly IS7VariableNameParser variableNameParser; private readonly IS7VariableNameParser variableNameParser;
private readonly BehaviorSubject<ConnectionState> connectionStateSubject = new BehaviorSubject<ConnectionState>(Enums.ConnectionState.Initial); private readonly BehaviorSubject<ConnectionState> connectionStateSubject = new BehaviorSubject<ConnectionState>(Enums.ConnectionState.Initial);
private ConcurrentDictionary<string, S7VariableAddress> s7VariableAddresses = new ConcurrentDictionary<string, S7VariableAddress>();
private readonly CompositeDisposable disposables = new CompositeDisposable(); private readonly CompositeDisposable disposables = new CompositeDisposable();
private readonly LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(maxDegreeOfParallelism:1); private readonly LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(maxDegreeOfParallelism:1);
@@ -34,16 +33,15 @@ namespace Sharp7.Rx
private bool disposed; private bool disposed;
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public async Task<Dictionary<string, byte[]>> ExecuteMultiVarRequest(IEnumerable<string> variableNames) public async Task<Dictionary<string, byte[]>> ExecuteMultiVarRequest(IReadOnlyList<string> variableNames)
{ {
var enumerable = variableNames as string[] ?? variableNames.ToArray(); if (variableNames.IsEmpty())
if (enumerable.IsEmpty())
return new Dictionary<string, byte[]>(); return new Dictionary<string, byte[]>();
var s7MultiVar = new S7MultiVar(sharp7); var s7MultiVar = new S7MultiVar(sharp7);
var buffers = enumerable.Select(key => new {VariableName = key, Address = s7VariableAddresses.GetOrAdd(key, s => variableNameParser.Parse(s))}) var buffers = variableNames
.Select(key => new {VariableName = key, Address = variableNameParser.Parse(key)})
.Select(x => .Select(x =>
{ {
var buffer = new byte[x.Address.Length]; var buffer = new byte[x.Address.Length];
@@ -67,10 +65,10 @@ namespace Sharp7.Rx
public Sharp7Connector(PlcConnectionSettings settings, IS7VariableNameParser variableNameParser) public Sharp7Connector(PlcConnectionSettings settings, IS7VariableNameParser variableNameParser)
{ {
this.variableNameParser = variableNameParser; this.variableNameParser = variableNameParser;
this.ipAddress = settings.IpAddress; ipAddress = settings.IpAddress;
this.cpuSlotNr = settings.CpuMpiAddress; cpuSlotNr = settings.CpuMpiAddress;
this.port = settings.Port; port = settings.Port;
this.rackNr = settings.RackNumber; rackNr = settings.RackNumber;
ReconnectDelay = TimeSpan.FromSeconds(5); ReconnectDelay = TimeSpan.FromSeconds(5);
} }
@@ -120,7 +118,7 @@ namespace Sharp7.Rx
try try
{ {
sharp7 = new S7Client(); sharp7 = new S7Client();
sharp7.PLCPort = this.port; sharp7.PLCPort = port;
var subscription = var subscription =
ConnectionState ConnectionState
@@ -223,7 +221,7 @@ namespace Sharp7.Rx
if (result != 0) if (result != 0)
{ {
await EvaluateErrorCode(result); await EvaluateErrorCode(result);
var errorText = this.sharp7.ErrorText(result); var errorText = sharp7.ErrorText(result);
throw new InvalidOperationException($"Error reading {operand}{dBNr}:{startByteAddress}->{bytesToRead} ({errorText})"); throw new InvalidOperationException($"Error reading {operand}{dBNr}:{startByteAddress}->{bytesToRead} ({errorText})");
} }

View File

@@ -20,11 +20,7 @@ namespace Sharp7.Rx
{ {
public class Sharp7Plc : IPlc public class Sharp7Plc : IPlc
{ {
private readonly string ipAddress; private readonly IS7VariableNameParser varaibleNameParser = new CacheVariableNameParser(new S7VariableNameParser());
private readonly int rackNumber;
private readonly int cpuMpiAddress;
private readonly int port;
private readonly IS7VariableNameParser varaibleNameParser;
private bool disposed; private bool disposed;
private ISubject<Unit> disposingSubject = new Subject<Unit>(); private ISubject<Unit> disposingSubject = new Subject<Unit>();
private IS7Connector s7Connector; private IS7Connector s7Connector;
@@ -37,14 +33,7 @@ namespace Sharp7.Rx
public Sharp7Plc(string ipAddress, int rackNumber, int cpuMpiAddress, int port = 102) public Sharp7Plc(string ipAddress, int rackNumber, int cpuMpiAddress, int port = 102)
{ {
this.ipAddress = ipAddress;
this.rackNumber = rackNumber;
this.cpuMpiAddress = cpuMpiAddress;
this.port = port;
plcConnectionSettings = new PlcConnectionSettings(){IpAddress = ipAddress, RackNumber = rackNumber, CpuMpiAddress = cpuMpiAddress, Port = port}; plcConnectionSettings = new PlcConnectionSettings(){IpAddress = ipAddress, RackNumber = rackNumber, CpuMpiAddress = cpuMpiAddress, Port = port};
varaibleNameParser = new S7VariableNameParser();
} }
public IObservable<ConnectionState> ConnectionState { get; private set; } public IObservable<ConnectionState> ConnectionState { get; private set; }
@@ -403,7 +392,7 @@ namespace Sharp7.Rx
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
foreach (var partsOfMultiVarRequest in multiVariableSubscriptions.ExistingKeys.Buffer(MultiVarRequestMaxItems)) foreach (var partsOfMultiVarRequest in multiVariableSubscriptions.ExistingKeys.Buffer(MultiVarRequestMaxItems))
{ {
var multiVarRequest = await connector.ExecuteMultiVarRequest(partsOfMultiVarRequest); var multiVarRequest = await connector.ExecuteMultiVarRequest(partsOfMultiVarRequest as IReadOnlyList<string>??partsOfMultiVarRequest.ToList());
foreach (var pair in multiVarRequest) foreach (var pair in multiVarRequest)
{ {