docs(phase4c): cross-driver 1-D array support + isArray/arrayLength keys + coverage matrix
This commit is contained in:
@@ -97,6 +97,28 @@ the projection semantics don't exactly mirror Rockwell FT A&E.
|
||||
- **Integration tests** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests/` run against the `ab_server` Docker fixture. See [AbServer-Test-Fixture.md](AbServer-Test-Fixture.md) for the coverage map and the `AB_SERVER_ENDPOINT` wiring.
|
||||
- **Manual client** — [Driver.AbCip.Cli.md](../Driver.AbCip.Cli.md).
|
||||
|
||||
## 1-D array support
|
||||
|
||||
An AB CIP tag becomes a **1-D OPC UA array node** when its `TagConfig` JSON carries
|
||||
`"isArray": true` and `"arrayLength": N` (N ≥ 1). The canonical rule:
|
||||
`isArray: true` + `arrayLength >= 1` → array; `isArray: false` (any length) → scalar.
|
||||
|
||||
**Read mechanism** — the driver delegates to **libplctag's native array read**. The tag's
|
||||
`TagPath` is passed to libplctag as a `[N]`-subscripted symbol (or the tag is created with
|
||||
an element count of N so libplctag fetches the full block in one EIP/CIP request). Both
|
||||
atomic types (`DINT[N]`, `REAL[N]`, …) and UDT member arrays are supported.
|
||||
|
||||
**Unit test coverage** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests/` covers
|
||||
array reads via the fake tag runtime for atomic and UDT member cases. The `ab_server`
|
||||
integration fixture is down during normal dev (Docker host fixture currently offline).
|
||||
|
||||
**Live-verify** — integration-fixture-gated (requires `ab_server` Docker fixture on `10.100.0.35:44818`).
|
||||
|
||||
**Deferrals** — array *writes*, multi-dimensional arrays, per-element historization. Safety-partition array tags (`SafetyTag: true`) are excluded (GuardLogix write constraints extend to array writes).
|
||||
|
||||
See [Uns.md §Array tags](../Uns.md#array-tags-1-d) for the cross-driver coverage matrix
|
||||
and the UI authoring flow.
|
||||
|
||||
## Operational Notes
|
||||
|
||||
- **Native heap is invisible to the GC.** `GetMemoryFootprint()` reports CLR allocations only; libplctag's native `Tag` heap does not show up there. Watch whole-process RSS, and use `ReinitializeAsync` (tears down + re-creates every device's libplctag handles) as the remediation for native-heap growth.
|
||||
|
||||
@@ -93,6 +93,33 @@ reproduced in [docs/v2/driver-specs.md §4](../v2/driver-specs.md).
|
||||
- **Integration tests** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/` run against the AB Legacy Docker fixture. See [AbLegacy-Test-Fixture.md](AbLegacy-Test-Fixture.md) for the coverage map.
|
||||
- **Manual client** — [Driver.AbLegacy.Cli.md](../Driver.AbLegacy.Cli.md).
|
||||
|
||||
## 1-D array support
|
||||
|
||||
An AB Legacy tag becomes a **1-D OPC UA array node** when its `TagConfig` JSON carries
|
||||
`"isArray": true` and `"arrayLength": N` (N ≥ 1, capped at 256). The canonical rule:
|
||||
`isArray: true` + `arrayLength >= 1` → array; `isArray: false` (any length) → scalar.
|
||||
|
||||
**Read mechanism** — the driver issues a **PCCC multi-element file read** via libplctag.
|
||||
The tag's file address (e.g. `N7:0`) is extended by `N` element count so libplctag fetches
|
||||
`N` consecutive PCCC file elements in one EIP/PCCC request. The response is decoded into
|
||||
N values of the declared `AbLegacyDataType`. Maximum element count is 256 (PCCC payload
|
||||
limit).
|
||||
|
||||
This closes the previously-noted limitation ("single-element addressing today") for the
|
||||
array read path. Array *writes* remain a follow-up.
|
||||
|
||||
**Unit test coverage** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/` covers
|
||||
the multi-element read path via the fake tag runtime. The AB Legacy integration fixture is
|
||||
down during normal dev.
|
||||
|
||||
**Live-verify** — integration-fixture-gated (requires the AB Legacy Docker fixture).
|
||||
|
||||
**Deferrals** — array *writes*, multi-dimensional arrays, per-element historization.
|
||||
`arrayLength > 256` is rejected at init with an explicit error (PCCC payload cap).
|
||||
|
||||
See [Uns.md §Array tags](../Uns.md#array-tags-1-d) for the cross-driver coverage matrix
|
||||
and the UI authoring flow.
|
||||
|
||||
## Operational Notes
|
||||
|
||||
- **Native heap is invisible to the GC.** As with AB CIP, `GetMemoryFootprint()` reports CLR allocations only; watch whole-process RSS and use `ReinitializeAsync` to recycle libplctag handles.
|
||||
|
||||
@@ -115,6 +115,34 @@ is reproduced in [docs/v2/driver-specs.md §2](../v2/driver-specs.md).
|
||||
|
||||
The canonical stored/dispatched `DriverType` value is **`"Modbus"`** — this is what the runtime factory key, docker-dev seed, AdminUI editor-map, tag-config validator, and probe all use. The AdminUI displays the friendly label **"Modbus TCP"** and the new-driver route slug is `modbustcp`, but neither the slug nor the label is stored in the database. Any pre-existing `DriverInstance` rows that carry the legacy value `"ModbusTcp"` must be updated to `"Modbus"` to receive typed-editor dispatch and factory instantiation.
|
||||
|
||||
## 1-D array support
|
||||
|
||||
A Modbus tag becomes a **1-D OPC UA array node** when its `TagConfig` JSON carries
|
||||
`"isArray": true` and `"arrayLength": N` (N ≥ 1). The canonical rule:
|
||||
`isArray: true` + `arrayLength >= 1` → array; `isArray: false` (any length) → scalar.
|
||||
|
||||
**Read mechanism** — the driver reads a contiguous block of `N × (registers per element)`
|
||||
holding/input registers in a single FC03/FC04 PDU, then splits the response into N
|
||||
decoded values. Three element-type modes are supported:
|
||||
|
||||
| Mode | How N elements are read |
|
||||
|---|---|
|
||||
| Numeric (Bool, Int16, UInt16, Int32, UInt32, Float32, Float64, Int64, UInt64) | N × element-width registers per PDU; coalescing rules apply as for scalar reads |
|
||||
| String (`DataType: STR<len>`) | N × ceil(len/2) registers per PDU; each element decoded as a fixed-length ASCII string |
|
||||
| BitInRegister | N bits packed in one register (or straddling registers); bit index advances per element |
|
||||
|
||||
**Unit test coverage** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests/` covers
|
||||
numeric, String, and BitInRegister array reads.
|
||||
|
||||
**Live-verify** — Mac-verifiable against the simulator at `10.100.0.35:5020` (no fixture
|
||||
bring-up required; the sim is always-on on the shared Docker host).
|
||||
|
||||
**Deferrals** — array *writes* (FC16 multi-register write for an array value) are a named
|
||||
follow-up; multi-dimensional arrays (`arrayLength` is always 1-D); per-element historization.
|
||||
|
||||
See [Uns.md §Array tags](../Uns.md#array-tags-1-d) for the cross-driver coverage matrix
|
||||
and the UI authoring flow.
|
||||
|
||||
## Operational Notes
|
||||
|
||||
- **Wrong-endian readings are silently plausible.** A byte-order misconfiguration produces a wrong number, not a Bad quality code — surface byte-order mismatches as data-validation alerts, not status codes (see [docs/v2/driver-specs.md §2](../v2/driver-specs.md)).
|
||||
|
||||
@@ -140,6 +140,35 @@ Portal under *Protection & Security* for the CPU.
|
||||
- **CLI** — [Driver.S7.Cli.md](../Driver.S7.Cli.md) documents the standalone
|
||||
read/write/probe CLI for manual checks against a real or simulated CPU.
|
||||
|
||||
## 1-D array support
|
||||
|
||||
An S7 tag becomes a **1-D OPC UA array node** when its `TagConfig` JSON carries
|
||||
`"isArray": true` and `"arrayLength": N` (N ≥ 1). The canonical rule:
|
||||
`isArray: true` + `arrayLength >= 1` → array; `isArray: false` (any length) → scalar.
|
||||
|
||||
**Read mechanism** — the driver issues a single `ReadBytesAsync` call over the contiguous
|
||||
memory span starting at the declared address for `N × (bytes per element)` bytes, then
|
||||
loops over the response buffer decoding each element individually using the same
|
||||
reinterpret/box logic as scalar reads. This keeps wire round-trips at 1 per array tag
|
||||
regardless of N.
|
||||
|
||||
**Supported element types** — any `S7DataType` that has a scalar decode path today
|
||||
(`Bool`, `Byte`, `Int16`, `UInt16`, `Int32`, `UInt32`, `Float32`). The `ReadBytesAsync`
|
||||
network half is a thin `S7.Net` call; the decode half is fully unit-tested.
|
||||
|
||||
**Unit test coverage** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.Tests/` covers
|
||||
the contiguous-block read and per-element decode loop. Integration fixture is down during
|
||||
normal dev (the S7 sim is on the shared Docker host but currently offline).
|
||||
|
||||
**Live-verify** — integration-fixture-gated (not Mac-verifiable without the S7 sim up).
|
||||
|
||||
**Deferrals** — array *writes*, multi-dimensional arrays, per-element historization. The
|
||||
`Timer` / `Counter` address types that are rejected at init for scalars are also excluded
|
||||
for arrays.
|
||||
|
||||
See [Uns.md §Array tags](../Uns.md#array-tags-1-d) for the cross-driver coverage matrix
|
||||
and the UI authoring flow.
|
||||
|
||||
## Further reading
|
||||
|
||||
- [`docs/v2/driver-specs.md §5`](../v2/driver-specs.md) — full per-field spec,
|
||||
|
||||
@@ -121,6 +121,31 @@ writes use the driver-wide `Timeout`.
|
||||
- **CLI** — [Driver.TwinCAT.Cli.md](../Driver.TwinCAT.Cli.md) documents the
|
||||
standalone read/write/browse/probe CLI for manual checks.
|
||||
|
||||
## 1-D array support
|
||||
|
||||
A TwinCAT tag becomes a **1-D OPC UA array node** when its `TagConfig` JSON carries
|
||||
`"isArray": true` and `"arrayLength": N` (N ≥ 1). The canonical rule:
|
||||
`isArray: true` + `arrayLength >= 1` → array; `isArray: false` (any length) → scalar.
|
||||
|
||||
**Read mechanism** — the driver performs an **ADS native array symbol read** against the
|
||||
declared `SymbolPath`. ADS returns the full array value buffer for a symbol that maps to a
|
||||
TwinCAT array type (e.g. `ARRAY [0..9] OF REAL`); the driver reads `N` elements from the
|
||||
response. When `UseNativeNotifications` is enabled, ADS also pushes array-value changes in
|
||||
a single notification payload — no per-element polling.
|
||||
|
||||
**Unit test coverage** — `tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/` covers
|
||||
the array symbol read path via the fake ADS client factory. The TwinCAT integration
|
||||
fixture is down during normal dev.
|
||||
|
||||
**Live-verify** — integration-fixture-gated (requires the TwinCAT Docker fixture / AMS router).
|
||||
|
||||
**Deferrals** — array *writes* (`ADS WriteValueAsync` for an array), multi-dimensional
|
||||
arrays, per-element historization. `IRediscoverable` still fires and rebuilds array nodes
|
||||
on PLC re-download (unchanged semantics from scalar nodes).
|
||||
|
||||
See [Uns.md §Array tags](../Uns.md#array-tags-1-d) for the cross-driver coverage matrix
|
||||
and the UI authoring flow.
|
||||
|
||||
## Further reading
|
||||
|
||||
- [`docs/v2/driver-specs.md §6`](../v2/driver-specs.md) — full per-field spec and
|
||||
|
||||
Reference in New Issue
Block a user