feat(s7): 1-D array block read + decode loop + IsArray discovery
This commit is contained in:
@@ -104,13 +104,22 @@ public sealed class S7ProbeOptions
|
||||
/// value can be written again without side-effects. Unsafe: M (merker) bits or Q (output)
|
||||
/// coils that drive edge-triggered routines in the PLC program.
|
||||
/// </param>
|
||||
/// <param name="ArrayCount">
|
||||
/// Element count when the tag is a 1-D array; <c>null</c> (or <c><= 1</c>) for a scalar.
|
||||
/// For an equipment tag this is threaded from the <c>TagConfig</c> JSON's <c>arrayLength</c>
|
||||
/// (honoured only when <c>isArray</c> is true) by <see cref="S7EquipmentTagParser"/>. When
|
||||
/// set, the driver issues a single contiguous block read of
|
||||
/// <c>ArrayCount × element-bytes</c> from the tag's start address and decodes each element
|
||||
/// into an element-typed CLR array (<c>short[]</c> / <c>int[]</c> / <c>float[]</c> / etc.).
|
||||
/// </param>
|
||||
public sealed record S7TagDefinition(
|
||||
string Name,
|
||||
string Address,
|
||||
S7DataType DataType,
|
||||
bool Writable = true,
|
||||
int StringLength = 254,
|
||||
bool WriteIdempotent = false);
|
||||
bool WriteIdempotent = false,
|
||||
int? ArrayCount = null);
|
||||
|
||||
public enum S7DataType
|
||||
{
|
||||
|
||||
@@ -36,12 +36,18 @@ public static class S7EquipmentTagParser
|
||||
// Range-guard rather than truncate: an S7 string can't exceed 254 chars, and a
|
||||
// negative length is meaningless — reject so a malformed blob can't slip through.
|
||||
if (stringLength < 0 || stringLength > MaxStringLength) return false;
|
||||
// Array intent: the canonical sink-side parse (DeploymentArtifact.ExtractTagArray)
|
||||
// honours arrayLength ONLY when isArray is true AND the prop is a JSON number — mirror
|
||||
// that here so the driver's transient def agrees byte-for-byte with the materialised
|
||||
// OPC UA node's ValueRank/ArrayDimensions. Absent / isArray=false ⇒ null (scalar).
|
||||
var arrayCount = ReadArrayCount(root);
|
||||
def = new S7TagDefinition(
|
||||
Name: reference,
|
||||
Address: address,
|
||||
DataType: dataType,
|
||||
Writable: true, // node-level authz governs writes
|
||||
StringLength: stringLength == 0 ? MaxStringLength : stringLength);
|
||||
StringLength: stringLength == 0 ? MaxStringLength : stringLength,
|
||||
ArrayCount: arrayCount);
|
||||
return true;
|
||||
}
|
||||
catch (JsonException) { return false; }
|
||||
@@ -56,4 +62,26 @@ public static class S7EquipmentTagParser
|
||||
private static int ReadInt(JsonElement o, string name)
|
||||
=> o.TryGetProperty(name, out var e) && e.ValueKind == JsonValueKind.Number
|
||||
&& e.TryGetInt32(out var v) ? v : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the optional 1-D array element count from the TagConfig blob. Returns the
|
||||
/// <c>arrayLength</c> int ONLY when <c>isArray</c> is <c>true</c> AND <c>arrayLength</c>
|
||||
/// is a positive JSON integer; <c>null</c> otherwise (scalar). Mirrors the byte-parity
|
||||
/// contract of <c>DeploymentArtifact.ExtractTagArray</c> on the sink side.
|
||||
/// </summary>
|
||||
private static int? ReadArrayCount(JsonElement root)
|
||||
{
|
||||
var isArray = root.TryGetProperty("isArray", out var aEl)
|
||||
&& (aEl.ValueKind == JsonValueKind.True || aEl.ValueKind == JsonValueKind.False)
|
||||
&& aEl.GetBoolean();
|
||||
if (!isArray) return null;
|
||||
if (root.TryGetProperty("arrayLength", out var lEl)
|
||||
&& lEl.ValueKind == JsonValueKind.Number
|
||||
&& lEl.TryGetInt32(out var len)
|
||||
&& len > 0)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user