fix(abcip): explicit IsArray flag so 1-element arrays read as arrays (review I-1)
This commit is contained in:
@@ -553,10 +553,11 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
|
||||
var tagPath = AbCipTagPath.TryParse(def.TagPath);
|
||||
var bitIndex = tagPath?.BitIndex;
|
||||
// Phase 4c — a 1-D array tag decodes the whole buffer into an element-typed CLR
|
||||
// array (int[]/float[]/bool[]/string[]…); scalar tags keep the single-value path.
|
||||
var value = def.ElementCount > 1
|
||||
? runtime.DecodeArray(def.DataType, def.ElementCount)
|
||||
// Review I-1 — an array tag (the EXPLICIT IsArray flag) decodes the whole buffer into an
|
||||
// element-typed CLR array (int[]/float[]/bool[]/string[]…), INCLUDING a 1-element array
|
||||
// (ElementCount 1). Scalar tags keep the single-value path.
|
||||
var value = IsArrayTag(def)
|
||||
? runtime.DecodeArray(def.DataType, Math.Max(1, def.ElementCount))
|
||||
: runtime.DecodeValue(def.DataType, bitIndex);
|
||||
results[fb.OriginalIndex] = new DataValueSnapshot(value, AbCipStatusMapper.Good, now, now);
|
||||
_health = new DriverHealth(DriverState.Healthy, now, null);
|
||||
@@ -854,11 +855,12 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
?? throw new InvalidOperationException(
|
||||
$"AbCip tag '{def.Name}' has malformed TagPath '{def.TagPath}'.");
|
||||
|
||||
// Phase 4c — a 1-D array tag (ElementCount > 1) sets libplctag's elem_count so the read
|
||||
// pulls every element in one CIP transaction; the read path then boxes them into a
|
||||
// typed CLR array. Scalar tags pass the default count of 1, unchanged.
|
||||
// Review I-1 — an array tag (the EXPLICIT IsArray flag, incl. a 1-element array) sets
|
||||
// libplctag's elem_count so the read pulls every element in one CIP transaction; the read
|
||||
// path then boxes them into a typed CLR array. Scalar tags pass count 1 + IsArray false.
|
||||
var runtime = _tagFactory.Create(
|
||||
device.BuildCreateParams(parsed.ToLibplctagName(), _options.Timeout, def.ElementCount));
|
||||
device.BuildCreateParams(
|
||||
parsed.ToLibplctagName(), _options.Timeout, def.ElementCount, IsArrayTag(def)));
|
||||
try
|
||||
{
|
||||
await runtime.InitializeAsync(ct).ConfigureAwait(false);
|
||||
@@ -950,11 +952,15 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
foreach (var member in tag.Members)
|
||||
{
|
||||
var memberFullName = $"{tag.Name}.{member.Name}";
|
||||
// Review I-1 — array-ness is the EXPLICIT IsArray flag (a 1-element array is
|
||||
// still an array); a legacy member with ElementCount > 1 but the flag unset
|
||||
// remains an array for back-compat.
|
||||
var memberIsArray = member.IsArray || member.ElementCount > 1;
|
||||
udtFolder.Variable(member.Name, member.Name, new DriverAttributeInfo(
|
||||
FullName: memberFullName,
|
||||
DriverDataType: member.DataType.ToDriverDataType(),
|
||||
IsArray: member.ElementCount > 1,
|
||||
ArrayDim: member.ElementCount > 1 ? (uint)member.ElementCount : null,
|
||||
IsArray: memberIsArray,
|
||||
ArrayDim: memberIsArray ? (uint)Math.Max(1, member.ElementCount) : null,
|
||||
SecurityClass: member.Writable
|
||||
? SecurityClassification.Operate
|
||||
: SecurityClassification.ViewOnly,
|
||||
@@ -988,11 +994,14 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
var fullName = discovered.ProgramScope is null
|
||||
? discovered.Name
|
||||
: $"Program:{discovered.ProgramScope}.{discovered.Name}";
|
||||
// Review I-1 — a discovered array of length 1 is still an array; honour the
|
||||
// explicit IsArray flag (legacy ElementCount > 1 still surfaces as an array).
|
||||
var discoveredIsArray = discovered.IsArray || discovered.ElementCount > 1;
|
||||
discoveredFolder.Variable(fullName, discovered.Name, new DriverAttributeInfo(
|
||||
FullName: fullName,
|
||||
DriverDataType: discovered.DataType.ToDriverDataType(),
|
||||
IsArray: discovered.ElementCount > 1,
|
||||
ArrayDim: discovered.ElementCount > 1 ? (uint)discovered.ElementCount : null,
|
||||
IsArray: discoveredIsArray,
|
||||
ArrayDim: discoveredIsArray ? (uint)Math.Max(1, discovered.ElementCount) : null,
|
||||
SecurityClass: discovered.ReadOnly
|
||||
? SecurityClassification.ViewOnly
|
||||
: SecurityClassification.Operate,
|
||||
@@ -1004,11 +1013,15 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
}
|
||||
}
|
||||
|
||||
// Review I-1 — array-ness is the EXPLICIT IsArray flag (a 1-element array is still an array);
|
||||
// a legacy definition carrying only ElementCount > 1 stays an array for back-compat.
|
||||
private static bool IsArrayTag(AbCipTagDefinition tag) => tag.IsArray || tag.ElementCount > 1;
|
||||
|
||||
private static DriverAttributeInfo ToAttributeInfo(AbCipTagDefinition tag) => new(
|
||||
FullName: tag.Name,
|
||||
DriverDataType: tag.DataType.ToDriverDataType(),
|
||||
IsArray: tag.ElementCount > 1,
|
||||
ArrayDim: tag.ElementCount > 1 ? (uint)tag.ElementCount : null,
|
||||
IsArray: IsArrayTag(tag),
|
||||
ArrayDim: IsArrayTag(tag) ? (uint)Math.Max(1, tag.ElementCount) : null,
|
||||
SecurityClass: (tag.Writable && !tag.SafetyTag)
|
||||
? SecurityClassification.Operate
|
||||
: SecurityClassification.ViewOnly,
|
||||
@@ -1112,8 +1125,11 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
/// <param name="timeout">The timeout for tag operations.</param>
|
||||
/// <param name="elementCount">libplctag <c>elem_count</c> — 1 for a scalar tag, the array
|
||||
/// length for a 1-D array tag (Phase 4c). Coerced to a minimum of 1.</param>
|
||||
/// <param name="isArray">Review I-1 — the EXPLICIT array signal threaded through so a
|
||||
/// 1-element array (<paramref name="elementCount"/> 1) is still read as an array.</param>
|
||||
/// <returns>The computed tag creation parameters.</returns>
|
||||
public AbCipTagCreateParams BuildCreateParams(string tagName, TimeSpan timeout, int elementCount = 1) => new(
|
||||
public AbCipTagCreateParams BuildCreateParams(
|
||||
string tagName, TimeSpan timeout, int elementCount = 1, bool isArray = false) => new(
|
||||
Gateway: ParsedAddress.Gateway,
|
||||
Port: ParsedAddress.Port,
|
||||
CipPath: ParsedAddress.CipPath,
|
||||
@@ -1122,7 +1138,8 @@ public sealed class AbCipDriver : IDriver, IReadable, IWritable, ITagDiscovery,
|
||||
Timeout: timeout,
|
||||
AllowPacking: Options.AllowPacking ?? Profile.SupportsRequestPacking,
|
||||
ConnectionSize: Options.ConnectionSize ?? Profile.DefaultConnectionSize,
|
||||
ElementCount: elementCount < 1 ? 1 : elementCount);
|
||||
ElementCount: elementCount < 1 ? 1 : elementCount,
|
||||
IsArray: isArray);
|
||||
|
||||
/// <summary>Disposes all runtime tag handles and clears the caches.</summary>
|
||||
public void DisposeHandles()
|
||||
|
||||
Reference in New Issue
Block a user