Auto: s7-c3 — per-tag scan group / publish rate

Closes #296
This commit is contained in:
Joseph Doherty
2026-04-26 01:03:00 -04:00
parent ca3d4bf581
commit 162c82b8d9
6 changed files with 736 additions and 26 deletions

View File

@@ -34,6 +34,22 @@ public static class S7DriverFactoryExtensions
throw new InvalidOperationException(
$"S7 driver config for '{driverInstanceId}' missing required Host");
// PR-S7-C3 — translate ScanGroupIntervalsMs (string -> int ms) into the runtime
// string -> TimeSpan map. Skip any entry with a non-positive value rather than
// throwing, so a config typo (e.g. 0 ms) degrades to "fall back to default
// publishing interval" instead of breaking the whole driver init.
IReadOnlyDictionary<string, TimeSpan>? scanGroupMap = null;
if (dto.ScanGroupIntervalsMs is { Count: > 0 })
{
var built = new Dictionary<string, TimeSpan>(StringComparer.OrdinalIgnoreCase);
foreach (var kvp in dto.ScanGroupIntervalsMs)
{
if (string.IsNullOrWhiteSpace(kvp.Key) || kvp.Value <= 0) continue;
built[kvp.Key] = TimeSpan.FromMilliseconds(kvp.Value);
}
if (built.Count > 0) scanGroupMap = built;
}
var options = new S7DriverOptions
{
Host = dto.Host!,
@@ -57,6 +73,7 @@ public static class S7DriverFactoryExtensions
fallback: TsapMode.Auto),
LocalTsap = dto.LocalTsap,
RemoteTsap = dto.RemoteTsap,
ScanGroupIntervals = scanGroupMap,
};
return new S7Driver(options, driverInstanceId);
@@ -72,7 +89,8 @@ public static class S7DriverFactoryExtensions
tagName: t.Name),
Writable: t.Writable ?? true,
StringLength: t.StringLength ?? 254,
WriteIdempotent: t.WriteIdempotent ?? false);
WriteIdempotent: t.WriteIdempotent ?? false,
ScanGroup: string.IsNullOrWhiteSpace(t.ScanGroup) ? null : t.ScanGroup);
private static T ParseEnum<T>(string? raw, string driverInstanceId, string field,
string? tagName = null, T? fallback = null) where T : struct, Enum
@@ -122,6 +140,15 @@ public static class S7DriverFactoryExtensions
/// <summary>Optional 16-bit remote TSAP override. Required (with <see cref="LocalTsap"/>) when <c>TsapMode = Other</c>.</summary>
public ushort? RemoteTsap { get; init; }
/// <summary>
/// PR-S7-C3 — optional scan-group → publishing-interval (ms) map. Tags carrying
/// a matching <see cref="S7TagDto.ScanGroup"/> string poll at the configured
/// rate; tags with no group, or with a group not present here, fall back to
/// the subscription default. Group names are matched case-insensitively. See
/// <c>docs/v2/s7.md</c> "Per-tag scan groups" section.
/// </summary>
public Dictionary<string, int>? ScanGroupIntervalsMs { get; init; }
}
internal sealed class S7TagDto
@@ -132,6 +159,14 @@ public static class S7DriverFactoryExtensions
public bool? Writable { get; init; }
public int? StringLength { get; init; }
public bool? WriteIdempotent { get; init; }
/// <summary>
/// PR-S7-C3 — optional scan-group identifier. Resolved against
/// <see cref="S7DriverConfigDto.ScanGroupIntervalsMs"/> at subscribe time.
/// Null / empty = no group (legacy behaviour, falls back to subscription
/// default publishing interval).
/// </summary>
public string? ScanGroup { get; init; }
}
internal sealed class S7ProbeDto