Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/S7CommPlusDriver/ClientApi/Browser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ private void AddFlatSubnodes(Node node, string names, string accessIds, uint Opt
Softdatatype = node.Softdatatype,
SymbolCrc = S7CommPlusSymbolCrc.ComputeFromSegments(nextCrcPath),
SymbolCrcPath = nextCrcPath,
// For array elements the Vte comes from the parent array base element, so its
// HMI attributes still apply. Default to true when unknown so nothing is dropped.
HmiVisible = node.Vte?.GetAttributeFlagHmiVisible() ?? true,
HmiAccessible = node.Vte?.GetAttributeFlagHmiAccessible() ?? true,
};
// If an Array element of basic datatype, the Vte is here from the parent array base element and offsets not valid here.
if (node.NodeType == eNodeType.Array)
Expand Down Expand Up @@ -732,6 +736,8 @@ public class VarInfo
public int OptBitoffset; // Optimized access: Bit-Offset where the value is located when reading a complete DB content.
public UInt32 NonOptAddress; // NonOptimized access: Byte-Offset where the value is located when reading a complete DB content.
public int NonOptBitoffset; // NonOptimized access: Bit-Offset where the value is located when reading a complete DB content.
public bool HmiVisible = true; // TIA "Visible in HMI engineering" attribute.
public bool HmiAccessible = true; // TIA "Accessible from HMI/OPC UA/Web server" attribute.
internal List<S7CommPlusSymbolCrc.PathSegment> SymbolCrcPath;
}

Expand Down
1 change: 1 addition & 0 deletions src/S7CommPlusDriver/IS7CommPlusSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ internal interface IS7CommPlusSession
int CreateTisWatchSubscription(S7CommPlusTisWatchRequest request, out uint subscriptionObjectId);
int WaitForTisWatchNotifications(uint subscriptionObjectId, int timeoutMilliseconds, out List<S7CommPlusTisWatchNotification> notifications);
string LastTisWatchDiagnostic { get; }
string LastAlarmSubscriptionDiagnostic { get; }
int DeleteTisWatchSubscription(uint subscriptionObjectId);
}
}
40 changes: 32 additions & 8 deletions src/S7CommPlusDriver/S7CommPlusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public Task<IReadOnlyList<VarInfo>> BrowseAsync(CancellationToken cancellationTo
var error = session.BrowseVariables(out var vars);
ThrowIfError("Browse", error);
return (IReadOnlyList<VarInfo>)(vars ?? new List<VarInfo>());
}, cancellationToken);
}, _options.BrowseTimeout, cancellationToken);
}

public Task<IReadOnlyList<S7CommPlusBlockInfo>> BrowseBlocksAsync(CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -541,7 +541,7 @@ public async Task<S7CommPlusAlarmSubscription> SubscribeAlarmsAsync(IEnumerable<
() => _session.CreateAlarmSubscription(languageIdsUint, subscriptionOptions.InitialCreditLimit, out subscriptionObjectId),
_options.RequestTimeout,
cancellationToken).ConfigureAwait(false);
ThrowIfError("CreateAlarmSubscription", error);
ThrowIfAlarmSubscriptionError("CreateAlarmSubscription", error);

subscription.Start(token => RunAlarmSubscriptionLoopAsync(subscription, subscriptionOptions, subscriptionObjectId, token));
return subscription;
Expand Down Expand Up @@ -736,12 +736,17 @@ public async ValueTask DisposeAsync()

private Task<T> ExecuteReadOperationAsync<T>(string operation, Func<IS7CommPlusSession, T> operationFunc, CancellationToken cancellationToken)
{
return ExecuteOperationAsync(operation, allowReconnect: true, operationFunc, cancellationToken);
return ExecuteReadOperationAsync(operation, operationFunc, _options.RequestTimeout, cancellationToken);
}

private Task<T> ExecuteReadOperationAsync<T>(string operation, Func<IS7CommPlusSession, T> operationFunc, TimeSpan timeout, CancellationToken cancellationToken)
{
return ExecuteOperationAsync(operation, allowReconnect: true, operationFunc, timeout, cancellationToken);
}

private Task<T> ExecuteSessionOperationAsync<T>(string operation, Func<IS7CommPlusSession, T> operationFunc, CancellationToken cancellationToken)
{
return ExecuteOperationAsync(operation, allowReconnect: false, operationFunc, cancellationToken);
return ExecuteOperationAsync(operation, allowReconnect: false, operationFunc, _options.RequestTimeout, cancellationToken);
}

private async Task SetCpuOperatingStateAsync(string operation, int operatingStateRequest, CancellationToken cancellationToken)
Expand All @@ -760,10 +765,10 @@ private Task<T> ExecuteWriteOperationAsync<T>(string operation, Func<IS7CommPlus
{
throw new S7CommPlusWriteDisabledException(Endpoint);
}
return ExecuteOperationAsync(operation, allowReconnect: false, operationFunc, cancellationToken);
return ExecuteOperationAsync(operation, allowReconnect: false, operationFunc, _options.RequestTimeout, cancellationToken);
}

private async Task<T> ExecuteOperationAsync<T>(string operation, bool allowReconnect, Func<IS7CommPlusSession, T> operationFunc, CancellationToken cancellationToken)
private async Task<T> ExecuteOperationAsync<T>(string operation, bool allowReconnect, Func<IS7CommPlusSession, T> operationFunc, TimeSpan timeout, CancellationToken cancellationToken)
{
ThrowIfDisposed();
await _operationGate.WaitAsync(cancellationToken).ConfigureAwait(false);
Expand All @@ -772,14 +777,14 @@ private async Task<T> ExecuteOperationAsync<T>(string operation, bool allowRecon
await EnsureConnectedCoreAsync(cancellationToken).ConfigureAwait(false);
try
{
return await RunWithTimeoutAsync(operation, () => operationFunc(_session), _options.RequestTimeout, cancellationToken).ConfigureAwait(false);
return await RunWithTimeoutAsync(operation, () => operationFunc(_session), timeout, cancellationToken).ConfigureAwait(false);
}
catch (S7CommPlusException ex) when (allowReconnect && _options.AutoReconnect && ex.IsTransient)
{
RaiseCommunicationError(ex);
_options.Logger.LogWarning(ex, "Transient {Operation} failure for {Endpoint}; reconnecting and retrying once.", operation, Endpoint);
await ReconnectCoreAsync(cancellationToken).ConfigureAwait(false);
return await RunWithTimeoutAsync(operation, () => operationFunc(_session), _options.RequestTimeout, cancellationToken).ConfigureAwait(false);
return await RunWithTimeoutAsync(operation, () => operationFunc(_session), timeout, cancellationToken).ConfigureAwait(false);
}
}
catch (S7CommPlusException ex)
Expand Down Expand Up @@ -1077,6 +1082,25 @@ private S7CommPlusException CreateTisWatchException(string operation, int errorC
return CreateException(effectiveOperation, errorCode);
}

private void ThrowIfAlarmSubscriptionError(string operation, int errorCode)
{
if (errorCode == 0)
{
return;
}

throw CreateAlarmSubscriptionException(operation, errorCode);
}

private S7CommPlusException CreateAlarmSubscriptionException(string operation, int errorCode)
{
var diagnostic = _session?.LastAlarmSubscriptionDiagnostic;
var effectiveOperation = string.IsNullOrWhiteSpace(diagnostic)
? operation
: $"{operation}: {diagnostic}";
return CreateException(effectiveOperation, errorCode);
}

private async Task TryDeleteSubscriptionAsync(string operation, S7CommPlusSubscription subscription, S7CommPlusSubscriptionOptions subscriptionOptions, Func<int> deleteFunc)
{
if (!subscriptionOptions.DeleteOnStop || _session == null)
Expand Down
3 changes: 3 additions & 0 deletions src/S7CommPlusDriver/S7CommPlusClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class S7CommPlusClientOptions
public TimeSpan ConnectTimeout { get; set; } = S7CommPlusDefaults.ConnectTimeout;
public TimeSpan RequestTimeout { get; set; } = S7CommPlusDefaults.RequestTimeout;
public TimeSpan DisconnectTimeout { get; set; } = S7CommPlusDefaults.DisconnectTimeout;
public TimeSpan BrowseTimeout { get; set; } = S7CommPlusDefaults.BrowseTimeout;
public bool AutoReconnect { get; set; } = true;
public bool WriteEnabled { get; set; } = false;
public S7CommPlusSecurityMode SecurityMode { get; set; } = S7CommPlusSecurityMode.Tls;
Expand All @@ -28,6 +29,7 @@ public sealed class S7CommPlusClientOptions
internal int ConnectTimeoutMilliseconds => ToPositiveMilliseconds(ConnectTimeout, nameof(ConnectTimeout));
internal int RequestTimeoutMilliseconds => ToPositiveMilliseconds(RequestTimeout, nameof(RequestTimeout));
internal int DisconnectTimeoutMilliseconds => ToPositiveMilliseconds(DisconnectTimeout, nameof(DisconnectTimeout));
internal int BrowseTimeoutMilliseconds => ToPositiveMilliseconds(BrowseTimeout, nameof(BrowseTimeout));
internal byte[] RemoteTsapBytes => Encoding.ASCII.GetBytes(RemoteTsap ?? string.Empty);

internal S7CommPlusClientOptions Clone()
Expand Down Expand Up @@ -80,6 +82,7 @@ internal void Validate()
_ = ConnectTimeoutMilliseconds;
_ = RequestTimeoutMilliseconds;
_ = DisconnectTimeoutMilliseconds;
_ = BrowseTimeoutMilliseconds;
Logger ??= NullLogger.Instance;
}

Expand Down
1 change: 1 addition & 0 deletions src/S7CommPlusDriver/S7CommPlusDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public static class S7CommPlusDefaults
public static readonly TimeSpan ConnectTimeout = TimeSpan.FromSeconds(5);
public static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(5);
public static readonly TimeSpan DisconnectTimeout = TimeSpan.FromSeconds(2);
public static readonly TimeSpan BrowseTimeout = TimeSpan.FromSeconds(120);
}
}
2 changes: 2 additions & 0 deletions src/S7CommPlusDriver/S7CommPlusProtocolSession.Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ int IS7CommPlusSession.WaitForTisWatchNotifications(uint subscriptionObjectId, i

string IS7CommPlusSession.LastTisWatchDiagnostic => TisWatchSubscriptions.LastDiagnostic;

string IS7CommPlusSession.LastAlarmSubscriptionDiagnostic => AlarmSubscriptions.LastDiagnostic;

int IS7CommPlusSession.DeleteTisWatchSubscription(uint subscriptionObjectId)
{
return TisWatchSubscriptions.Delete(subscriptionObjectId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ internal sealed class S7CommPlusAlarmSubscriptionService
private readonly IS7CommPlusProtocolSession _session;
private readonly S7CommPlusProtocolRequests _requests;

public string LastDiagnostic { get; private set; } = "";

public S7CommPlusAlarmSubscriptionService(IS7CommPlusProtocolSession session)
{
_session = session;
Expand Down Expand Up @@ -54,6 +56,7 @@ public int Create(uint[] languageIds)
public int Create(uint[] languageIds, short initialCreditLimit, out uint subscriptionObjectId)
{
subscriptionObjectId = 0;
LastDiagnostic = "";
int res;
languageIds ??= Array.Empty<uint>();
var state = new AlarmSubscriptionState { NextCreditLimit = initialCreditLimit };
Expand Down Expand Up @@ -116,7 +119,8 @@ public int Create(uint[] languageIds, short initialCreditLimit, out uint subscri
{
// If creating a subscription fails, the object is still created and should be deleted.
// At least deleting it, gives no error.
System.Diagnostics.Trace.WriteLine(String.Format("AlarmSubscription - Create: Failed with Returnvalue = 0x{0:X8}", createObjRes.ReturnValue));
LastDiagnostic = String.Format("Create failed with Returnvalue = 0x{0:X8}", createObjRes.ReturnValue);
System.Diagnostics.Trace.WriteLine("AlarmSubscription - " + LastDiagnostic);
res = S7Consts.errCliInvalidParams;
}

Expand Down
Loading