mirror of
https://github.com/evopro-ag/Sharp7Reactive.git
synced 2025-12-16 19:52:53 +00:00
Improve and unity logging
This commit is contained in:
@@ -10,7 +10,7 @@ using Sharp7.Rx.Settings;
|
|||||||
|
|
||||||
namespace Sharp7.Rx;
|
namespace Sharp7.Rx;
|
||||||
|
|
||||||
internal class Sharp7Connector: IDisposable
|
internal class Sharp7Connector : IDisposable
|
||||||
{
|
{
|
||||||
private readonly BehaviorSubject<ConnectionState> connectionStateSubject = new(Enums.ConnectionState.Initial);
|
private readonly BehaviorSubject<ConnectionState> connectionStateSubject = new(Enums.ConnectionState.Initial);
|
||||||
private readonly int cpuSlotNr;
|
private readonly int cpuSlotNr;
|
||||||
@@ -35,16 +35,20 @@ internal class Sharp7Connector: IDisposable
|
|||||||
rackNr = settings.RackNumber;
|
rackNr = settings.RackNumber;
|
||||||
|
|
||||||
ReconnectDelay = TimeSpan.FromSeconds(5);
|
ReconnectDelay = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
|
ConnectionIdentifier = $"{ipAddress}:{port} Cpu {cpuSlotNr} Rack {rackNr}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public IObservable<ConnectionState> ConnectionState => connectionStateSubject.DistinctUntilChanged().AsObservable();
|
public IObservable<ConnectionState> ConnectionState => connectionStateSubject.DistinctUntilChanged().AsObservable();
|
||||||
|
|
||||||
public ILogger Logger { get; set; }
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public TimeSpan ReconnectDelay { get; set; }
|
private string ConnectionIdentifier { get; }
|
||||||
|
|
||||||
private bool IsConnected => connectionStateSubject.Value == Enums.ConnectionState.Connected;
|
private bool IsConnected => connectionStateSubject.Value == Enums.ConnectionState.Connected;
|
||||||
|
|
||||||
|
private TimeSpan ReconnectDelay { get; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
@@ -67,13 +71,13 @@ internal class Sharp7Connector: IDisposable
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var errorText = EvaluateErrorCode(errorCode);
|
var errorText = EvaluateErrorCode(errorCode);
|
||||||
Logger.LogError("Failed to establish initial connection: {Error}", errorText);
|
Logger.LogError("Failed to establish initial connection to {Connection}: {Error}", ConnectionIdentifier, errorText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
connectionStateSubject.OnNext(Enums.ConnectionState.ConnectionLost);
|
connectionStateSubject.OnNext(Enums.ConnectionState.ConnectionLost);
|
||||||
Logger.LogError(ex, "Failed to establish initial connection.");
|
Logger.LogError(ex, "Failed to establish initial connection ro {Connection}.", ConnectionIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -125,14 +129,14 @@ internal class Sharp7Connector: IDisposable
|
|||||||
.Take(1)
|
.Take(1)
|
||||||
.SelectMany(_ => Reconnect())
|
.SelectMany(_ => Reconnect())
|
||||||
.RepeatAfterDelay(ReconnectDelay)
|
.RepeatAfterDelay(ReconnectDelay)
|
||||||
.LogAndRetry(Logger, "Error while reconnecting to S7.")
|
.LogAndRetry(Logger, $"Error while reconnecting to {ConnectionIdentifier}.")
|
||||||
.Subscribe();
|
.Subscribe();
|
||||||
|
|
||||||
disposables.Add(subscription);
|
disposables.Add(subscription);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger?.LogError(ex, "S7 driver could not be initialized");
|
Logger?.LogError(ex, "S7 driver for {Connection} could not be initialized", ConnectionIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
@@ -149,11 +153,13 @@ internal class Sharp7Connector: IDisposable
|
|||||||
await Task.Factory.StartNew(() => sharp7.ReadArea(operand.ToArea(), dbNo, startByteAddress, bytesToRead, S7WordLength.Byte, buffer), token, TaskCreationOptions.None, scheduler);
|
await Task.Factory.StartNew(() => sharp7.ReadArea(operand.ToArea(), dbNo, startByteAddress, bytesToRead, S7WordLength.Byte, buffer), token, TaskCreationOptions.None, scheduler);
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
EnsureSuccessOrThrow(result, $"Error reading {operand}{dbNo}:{startByteAddress}->{bytesToRead}");
|
EnsureSuccessOrThrow(result, $"Error reading {operand}{dbNo}:{startByteAddress} ({bytesToRead} bytes)");
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => ConnectionIdentifier;
|
||||||
|
|
||||||
public async Task WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNo, CancellationToken token)
|
public async Task WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNo, CancellationToken token)
|
||||||
{
|
{
|
||||||
EnsureConnectionValid();
|
EnsureConnectionValid();
|
||||||
@@ -175,7 +181,7 @@ internal class Sharp7Connector: IDisposable
|
|||||||
var result = await Task.Factory.StartNew(() => sharp7.WriteArea(operand.ToArea(), dbNo, startByteAddress, bytesToWrite, S7WordLength.Byte, data), token, TaskCreationOptions.None, scheduler);
|
var result = await Task.Factory.StartNew(() => sharp7.WriteArea(operand.ToArea(), dbNo, startByteAddress, bytesToWrite, S7WordLength.Byte, data), token, TaskCreationOptions.None, scheduler);
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
EnsureSuccessOrThrow(result, $"Error writing {operand}{dbNo}:{startByteAddress}.{data.Length}");
|
EnsureSuccessOrThrow(result, $"Error writing {operand}{dbNo}:{startByteAddress} ({data.Length} bytes)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -222,18 +228,18 @@ internal class Sharp7Connector: IDisposable
|
|||||||
throw new InvalidOperationException("Plc is not connected");
|
throw new InvalidOperationException("Plc is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureSuccessOrThrow(int result, string message)
|
private void EnsureSuccessOrThrow(int errorCode, string message)
|
||||||
{
|
{
|
||||||
if (result == 0) return;
|
if (errorCode == 0) return;
|
||||||
|
|
||||||
var errorText = EvaluateErrorCode(result);
|
var errorText = EvaluateErrorCode(errorCode);
|
||||||
var completeMessage = $"{message}: {errorText}";
|
var completeMessage = $"{message}: {errorText}";
|
||||||
|
|
||||||
var additionalErrorText = S7ErrorCodes.GetAdditionalErrorText(result);
|
var additionalErrorText = S7ErrorCodes.GetAdditionalErrorText(errorCode);
|
||||||
if (additionalErrorText != null)
|
if (additionalErrorText != null)
|
||||||
completeMessage += Environment.NewLine + additionalErrorText;
|
completeMessage += Environment.NewLine + additionalErrorText;
|
||||||
|
|
||||||
throw new S7CommunicationException(completeMessage, result, errorText);
|
throw new S7CommunicationException(completeMessage, errorCode, errorText);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EvaluateErrorCode(int errorCode)
|
private string EvaluateErrorCode(int errorCode)
|
||||||
@@ -245,7 +251,6 @@ internal class Sharp7Connector: IDisposable
|
|||||||
throw new InvalidOperationException("S7 driver is not initialized.");
|
throw new InvalidOperationException("S7 driver is not initialized.");
|
||||||
|
|
||||||
var errorText = $"0x{errorCode:X}, {sharp7.ErrorText(errorCode)}";
|
var errorText = $"0x{errorCode:X}, {sharp7.ErrorText(errorCode)}";
|
||||||
Logger?.LogError($"S7 Error {errorText}");
|
|
||||||
|
|
||||||
if (S7ErrorCodes.AssumeConnectionLost(errorCode))
|
if (S7ErrorCodes.AssumeConnectionLost(errorCode))
|
||||||
SetConnectionLostState();
|
SetConnectionLostState();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class Sharp7Plc : IPlc
|
|||||||
/// </param>
|
/// </param>
|
||||||
public Sharp7Plc(string ipAddress, int rackNumber, int cpuMpiAddress, int port = 102, TimeSpan? multiVarRequestCycleTime = null)
|
public Sharp7Plc(string ipAddress, int rackNumber, int cpuMpiAddress, int port = 102, TimeSpan? multiVarRequestCycleTime = null)
|
||||||
{
|
{
|
||||||
plcConnectionSettings = new PlcConnectionSettings {IpAddress = ipAddress, RackNumber = rackNumber, CpuMpiAddress = cpuMpiAddress, Port = port};
|
plcConnectionSettings = new PlcConnectionSettings { IpAddress = ipAddress, RackNumber = rackNumber, CpuMpiAddress = cpuMpiAddress, Port = port };
|
||||||
s7Connector = new Sharp7Connector(plcConnectionSettings, variableNameParser);
|
s7Connector = new Sharp7Connector(plcConnectionSettings, variableNameParser);
|
||||||
ConnectionState = s7Connector.ConnectionState;
|
ConnectionState = s7Connector.ConnectionState;
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ public class Sharp7Plc : IPlc
|
|||||||
// Special handling for bools, which are written on a by-bit basis. Writing a complete byte would
|
// Special handling for bools, which are written on a by-bit basis. Writing a complete byte would
|
||||||
// overwrite other bits within this byte.
|
// overwrite other bits within this byte.
|
||||||
|
|
||||||
await s7Connector.WriteBit(address.Operand, address.Start, address.Bit!.Value, (bool) (object) value, address.DbNo, token);
|
await s7Connector.WriteBit(address.Operand, address.Start, address.Bit!.Value, (bool)(object)value, address.DbNo, token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -283,7 +283,7 @@ public class Sharp7Plc : IPlc
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger?.LogError(e, "Intiial PLC connection failed.");
|
// Ignore. Exception is logged in the connector
|
||||||
}
|
}
|
||||||
}, token);
|
}, token);
|
||||||
|
|
||||||
@@ -329,9 +329,12 @@ public class Sharp7Plc : IPlc
|
|||||||
|
|
||||||
private void PrintAndResetPerformanceStatistik()
|
private void PrintAndResetPerformanceStatistik()
|
||||||
{
|
{
|
||||||
if (performanceCounter.Count == performanceCounter.Capacity)
|
if (performanceCounter.Count != performanceCounter.Capacity) return;
|
||||||
|
|
||||||
|
if (Logger.IsEnabled(LogLevel.Trace))
|
||||||
{
|
{
|
||||||
var average = performanceCounter.Average();
|
var average = performanceCounter.Average();
|
||||||
|
|
||||||
var min = performanceCounter.Min();
|
var min = performanceCounter.Min();
|
||||||
var max = performanceCounter.Max();
|
var max = performanceCounter.Max();
|
||||||
|
|
||||||
@@ -340,8 +343,9 @@ public class Sharp7Plc : IPlc
|
|||||||
performanceCounter.Capacity, min, max, average,
|
performanceCounter.Capacity, min, max, average,
|
||||||
multiVariableSubscriptions.ExistingKeys.Count(),
|
multiVariableSubscriptions.ExistingKeys.Count(),
|
||||||
MultiVarRequestMaxItems);
|
MultiVarRequestMaxItems);
|
||||||
performanceCounter.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
performanceCounter.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartNotificationLoop()
|
private void StartNotificationLoop()
|
||||||
@@ -355,7 +359,7 @@ public class Sharp7Plc : IPlc
|
|||||||
.FirstAsync(states => states == Enums.ConnectionState.Connected)
|
.FirstAsync(states => states == Enums.ConnectionState.Connected)
|
||||||
.SelectMany(_ => GetAllValues(s7Connector))
|
.SelectMany(_ => GetAllValues(s7Connector))
|
||||||
.RepeatAfterDelay(MultiVarRequestCycleTime)
|
.RepeatAfterDelay(MultiVarRequestCycleTime)
|
||||||
.LogAndRetryAfterDelay(Logger, MultiVarRequestCycleTime, "Error while getting batch notifications from plc")
|
.LogAndRetryAfterDelay(Logger, MultiVarRequestCycleTime, $"Error while getting batch notifications from {s7Connector}")
|
||||||
.Subscribe();
|
.Subscribe();
|
||||||
|
|
||||||
if (Interlocked.CompareExchange(ref notificationSubscription, subscription, null) != null)
|
if (Interlocked.CompareExchange(ref notificationSubscription, subscription, null) != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user