fix(code-review): resolve Batch 2 open findings (AbCip, AbLegacy, Galaxy, FOCAS)
- Driver.AbCip.Contracts-001: parse 'writable' from TagConfig JSON (default true) instead of hardcoding - Driver.AbCip.Contracts-002/-003: Dt type comment; drop dead [Display]/[Range] annotations - Driver.AbCip.Contracts-004: dedicated AbCipEquipmentTagParser test class (+15) - Driver.AbCip-017: document Tick severity Low-fallback on Bad severity read - Driver.AbLegacy.Contracts-002/-003/-004: isArray-scalar remarks (+tests), MaxTagBytes/ForFamily docs - Driver.Galaxy.Browser-003 + Driver.Galaxy.Contracts-003: extract ResolveApiKey -> GalaxySecretRef (dedup) - Driver.Galaxy-019: cache buffered-interval only on Ok + ILogger warnings + ClassifyIntervalReply (+tests) - Driver.FOCAS.Contracts-002: thread WriteIdempotent through DiscoverAsync (+test)
This commit is contained in:
@@ -25,7 +25,9 @@ public enum AbCipDataType
|
||||
Real, // 32-bit IEEE-754
|
||||
LReal, // 64-bit IEEE-754
|
||||
String, // Logix STRING (DINT Length + SINT[82] DATA — flattened to .NET string by libplctag)
|
||||
Dt, // Date/Time — Logix DT == DINT representing seconds-since-epoch per Rockwell conventions
|
||||
Dt, // Logix DATE (0xCD — 4-byte unsigned days since 1984-01-01) or DATE_AND_TIME / DT
|
||||
// (0xCF — 8-byte unsigned microseconds since 1970-01-01). The driver reads 4 bytes
|
||||
// via GetInt32; DATE decodes correctly, DATE_AND_TIME is truncated to the low 4 bytes.
|
||||
/// <summary>
|
||||
/// UDT / Predefined Structure (Timer / Counter / Control / Message / Axis). Shape is
|
||||
/// resolved at discovery time; reads + writes fan out to member Variables unless the
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
/// <summary>
|
||||
@@ -81,8 +79,7 @@ public sealed class AbCipDriverOptions
|
||||
/// Timeout for the AdminUI Test Connect probe, in seconds. The AdminUI clamps to a
|
||||
/// 60s server-side maximum; this default is what the form pre-fills for new instances.
|
||||
/// </summary>
|
||||
[Display(Name = "Probe timeout (seconds)", Description = "Connection test timeout. Default 5s.", GroupName = "Diagnostics")]
|
||||
[Range(1, 60)]
|
||||
/// <remarks>Valid range: 1–60 seconds; the AdminUI clamps to 60s server-side.</remarks>
|
||||
public int ProbeTimeoutSeconds { get; init; } = 5;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ public static class AbCipEquipmentTagParser
|
||||
/// <param name="def">The transient definition when parsing succeeds.</param>
|
||||
/// <returns><see langword="true"/> when <paramref name="reference"/> is an AbCip TagConfig object.</returns>
|
||||
/// <remarks>
|
||||
/// The produced <see cref="AbCipTagDefinition.Writable"/> is always <c>true</c>: the
|
||||
/// TagConfig JSON format for equipment tags does not carry a writability field, so the
|
||||
/// PLC's ExternalAccess attribute is the effective write gate. Operators who need a
|
||||
/// read-only OPC UA surface must rely on the PLC's ExternalAccess rejecting the write.
|
||||
/// <see cref="AbCipTagDefinition.Writable"/> is read from the optional <c>"writable"</c>
|
||||
/// boolean field in the TagConfig JSON; it defaults to <c>true</c> when the field is absent,
|
||||
/// matching the record's documented default and the behaviour of pre-declared tags. Operators
|
||||
/// who need a read-only OPC UA surface can author <c>"writable":false</c> in the TagConfig;
|
||||
/// the PLC's ExternalAccess attribute remains the effective write gate at the wire level.
|
||||
/// </remarks>
|
||||
public static bool TryParse(string reference, out AbCipTagDefinition def)
|
||||
{
|
||||
@@ -36,6 +37,11 @@ public static class AbCipEquipmentTagParser
|
||||
if (string.IsNullOrWhiteSpace(tagPath)) return false;
|
||||
|
||||
var deviceHostAddress = ReadString(root, "deviceHostAddress");
|
||||
// A "dataType":"Structure" input is accepted and produces a Structure-typed definition
|
||||
// with Members:null. The driver treats this as a black-box dotted-path read: libplctag
|
||||
// resolves the full tag path (e.g. "Motor.Speed") without enumerating UDT members.
|
||||
// The address space emits a placeholder String variable; UDT member declarations are
|
||||
// not supported in the equipment-tag flow.
|
||||
var dataType = ReadEnum(root, "dataType", AbCipDataType.DInt);
|
||||
// Review I-1 — an equipment tag is an ARRAY ⟺ isArray:true AND arrayLength >= 1. A
|
||||
// 1-element array (isArray:true, arrayLength:1) is a VALID 1-element array — the
|
||||
@@ -43,9 +49,12 @@ public static class AbCipEquipmentTagParser
|
||||
// scalar. ElementCount can't carry the signal (a scalar and a 1-element array both
|
||||
// have a count of 1), so the explicit IsArray flag does.
|
||||
var (isArray, elementCount) = ReadArrayShape(root);
|
||||
// "writable" defaults to true when absent — matches AbCipTagDefinition.Writable default.
|
||||
var writable = !root.TryGetProperty("writable", out var writableEl)
|
||||
|| writableEl.ValueKind != JsonValueKind.False;
|
||||
def = new AbCipTagDefinition(
|
||||
Name: reference, DeviceHostAddress: deviceHostAddress, TagPath: tagPath,
|
||||
DataType: dataType, Writable: true, ElementCount: elementCount, IsArray: isArray);
|
||||
DataType: dataType, Writable: writable, ElementCount: elementCount, IsArray: isArray);
|
||||
return true;
|
||||
}
|
||||
catch (JsonException) { return false; }
|
||||
|
||||
Reference in New Issue
Block a user