@@ -86,6 +86,11 @@ public static class S7DriverFactoryExtensions
|
||||
LocalTsap = dto.LocalTsap,
|
||||
RemoteTsap = dto.RemoteTsap,
|
||||
ScanGroupIntervals = scanGroupMap,
|
||||
// PR-S7-D2 — UDT layout declarations referenced by tags whose UdtName is set.
|
||||
// Empty list when the config doesn't declare any UDTs (the typical scalar-only case).
|
||||
Udts = dto.Udts is { Count: > 0 }
|
||||
? [.. dto.Udts.Select(u => BuildUdt(u, driverInstanceId))]
|
||||
: [],
|
||||
};
|
||||
|
||||
return new S7Driver(options, driverInstanceId);
|
||||
@@ -95,16 +100,49 @@ public static class S7DriverFactoryExtensions
|
||||
new(
|
||||
Name: t.Name ?? throw new InvalidOperationException(
|
||||
$"S7 config for '{driverInstanceId}' has a tag missing Name"),
|
||||
// PR-S7-D2 — UDT-typed tags use the UDT name as their type rather than a primitive
|
||||
// S7 data type; Address is still required (the parent base address that the
|
||||
// fan-out adds member offsets to). Address may legitimately be DBn.DBX0.0 for an
|
||||
// entire-DB UDT pointer; the parser accepts that and the fan-out walks from there.
|
||||
Address: t.Address ?? throw new InvalidOperationException(
|
||||
$"S7 tag '{t.Name}' in '{driverInstanceId}' missing Address"),
|
||||
DataType: ParseEnum<S7DataType>(t.DataType, driverInstanceId, "DataType",
|
||||
tagName: t.Name),
|
||||
DataType: string.IsNullOrWhiteSpace(t.UdtName)
|
||||
? ParseEnum<S7DataType>(t.DataType, driverInstanceId, "DataType", tagName: t.Name)
|
||||
: ParseEnum<S7DataType>(t.DataType, driverInstanceId, "DataType", tagName: t.Name,
|
||||
fallback: S7DataType.Byte),
|
||||
Writable: t.Writable ?? true,
|
||||
StringLength: t.StringLength ?? 254,
|
||||
WriteIdempotent: t.WriteIdempotent ?? false,
|
||||
ScanGroup: string.IsNullOrWhiteSpace(t.ScanGroup) ? null : t.ScanGroup,
|
||||
DeadbandAbsolute: t.DeadbandAbsolute,
|
||||
DeadbandPercent: t.DeadbandPercent);
|
||||
DeadbandPercent: t.DeadbandPercent,
|
||||
UdtName: string.IsNullOrWhiteSpace(t.UdtName) ? null : t.UdtName);
|
||||
|
||||
private static S7UdtDefinition BuildUdt(S7UdtDto u, string driverInstanceId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(u.Name))
|
||||
throw new InvalidOperationException(
|
||||
$"S7 config for '{driverInstanceId}' has a UDT entry missing Name");
|
||||
var members = (u.Members ?? new List<S7UdtMemberDto>()).Select(m => BuildUdtMember(m, u.Name!, driverInstanceId)).ToList();
|
||||
return new S7UdtDefinition(u.Name!, members, u.SizeBytes ?? 0);
|
||||
}
|
||||
|
||||
private static S7UdtMember BuildUdtMember(S7UdtMemberDto m, string udtName, string driverInstanceId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(m.Name))
|
||||
throw new InvalidOperationException(
|
||||
$"S7 UDT '{udtName}' in '{driverInstanceId}' has a member missing Name");
|
||||
var dataType = string.IsNullOrWhiteSpace(m.UdtName)
|
||||
? ParseEnum<S7DataType>(m.DataType, driverInstanceId, $"UDT '{udtName}' member '{m.Name}' DataType")
|
||||
: ParseEnum<S7DataType>(m.DataType, driverInstanceId, $"UDT '{udtName}' member '{m.Name}' DataType",
|
||||
fallback: S7DataType.Byte);
|
||||
return new S7UdtMember(
|
||||
Name: m.Name!,
|
||||
Offset: m.Offset ?? 0,
|
||||
DataType: dataType,
|
||||
ArrayDim: m.ArrayDim,
|
||||
UdtName: string.IsNullOrWhiteSpace(m.UdtName) ? null : m.UdtName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D1 / #299 — append TIA Portal "Show all tags" CSV rows to
|
||||
@@ -225,6 +263,7 @@ public static class S7DriverFactoryExtensions
|
||||
LocalTsap = options.LocalTsap,
|
||||
RemoteTsap = options.RemoteTsap,
|
||||
ScanGroupIntervals = options.ScanGroupIntervals,
|
||||
Udts = options.Udts,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -285,6 +324,14 @@ public static class S7DriverFactoryExtensions
|
||||
/// <c>docs/v2/s7.md</c> "Per-tag scan groups" section.
|
||||
/// </summary>
|
||||
public Dictionary<string, int>? ScanGroupIntervalsMs { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D2 — UDT / STRUCT layout declarations. Tags whose
|
||||
/// <see cref="S7TagDto.UdtName"/> matches a UDT here get fanned out into
|
||||
/// scalar leaf member tags at <c>S7Driver.InitializeAsync</c> time.
|
||||
/// See <c>docs/v2/s7.md</c> "UDT / STRUCT support" section.
|
||||
/// </summary>
|
||||
public List<S7UdtDto>? Udts { get; init; }
|
||||
}
|
||||
|
||||
internal sealed class S7TagDto
|
||||
@@ -320,6 +367,39 @@ public static class S7DriverFactoryExtensions
|
||||
/// set the filters are OR'd — publish if EITHER threshold triggers.
|
||||
/// </summary>
|
||||
public double? DeadbandPercent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D2 — when set, the tag is a UDT / STRUCT-typed pointer. The driver
|
||||
/// looks up the named UDT in <see cref="S7DriverConfigDto.Udts"/> and fans the
|
||||
/// tag out into scalar leaf tags at <c>InitializeAsync</c> time. The primitive
|
||||
/// <see cref="DataType"/> field is ignored when <c>UdtName</c> is set; the
|
||||
/// leaves take their data types from the UDT member declarations.
|
||||
/// </summary>
|
||||
public string? UdtName { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D2 — JSON wire form for <see cref="S7UdtDefinition"/>. See
|
||||
/// <c>docs/v2/s7.md</c> "UDT / STRUCT support" for the round-trip example.
|
||||
/// </summary>
|
||||
internal sealed class S7UdtDto
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public List<S7UdtMemberDto>? Members { get; init; }
|
||||
public int? SizeBytes { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D2 — JSON wire form for <see cref="S7UdtMember"/>. <c>UdtName</c> is set
|
||||
/// for nested-UDT members; <c>DataType</c> is set for primitive members.
|
||||
/// </summary>
|
||||
internal sealed class S7UdtMemberDto
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
public int? Offset { get; init; }
|
||||
public string? DataType { get; init; }
|
||||
public int? ArrayDim { get; init; }
|
||||
public string? UdtName { get; init; }
|
||||
}
|
||||
|
||||
internal sealed class S7ProbeDto
|
||||
|
||||
Reference in New Issue
Block a user