b95b99ba8e80e059c75119609c8b1a382a7e4bd2
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b95b99ba8e |
fix(drivers): correct 16 wrong OPC UA status-code constants + guard them by reflection (#497)
Every value verified against Opc.Ua.StatusCodes in the pinned SDK (1.5.378.106) by reflection, not by copying siblings. All are client-visible: OPC UA clients branch on status. The three named in #497: - Historian.Gateway SampleMapper "BadNoData" 0x800E0000 -> 0x809B0000 (0x800E0000 is BadServerHalted) - Galaxy "BadTimeout" 0x800B0000 -> 0x800A0000 (0x800B0000 is BadServiceUnsupported) - TwinCAT BadTypeMismatch 0x80730000 -> 0x80740000 (0x80730000 is BadWriteNotSupported) BadTypeMismatch was wrong in three MORE drivers the issue did not name — FOCAS, AbLegacy and AbCip carried the same 0x80730000. Every call site is a FormatException/InvalidCastException conversion failure, so the name was right and the value was wrong in all four. Adding the reflection guard then surfaced nine further defects offline tests had never checked: - Galaxy GoodLocalOverride 0x00D80000 -> 0x00960000 (not a UA code at all) - Galaxy UncertainLastUsableValue 0x40A40000 -> 0x40900000 - Galaxy UncertainSensorNotAccurate 0x408D0000 -> 0x40930000 - Galaxy UncertainEngineeringUnitsExceeded 0x408E0000 -> 0x40940000 - Galaxy UncertainSubNormal 0x408F0000 -> 0x40950000 - TwinCAT BadOutOfService 0x80BE0000 -> 0x808D0000 (was BadProtocolVersionUnsupported) - TwinCAT BadInvalidState 0x80350000 -> 0x80AF0000 (was BadAttributeIdInvalid) - AbCip/AbLegacy GoodMoreData 0x00A70000 -> 0x00A60000 (was GoodCommunicationEvent) - Historian.Gateway GatewayQualityMapper Good_LocalOverride 0x00D80000 -> 0x00960000 Galaxy's whole Uncertain block read as though the OPC DA quality byte could be shifted into the UA substatus position; it cannot — the substatuses are an unrelated enumeration. GatewayQualityMapper already held the correct table, which is what the Galaxy values are now reconciled against. Guard: StatusCodeParityTests (Core.Abstractions.Tests, which already project- references every driver) reflects over every `const uint` in the deployed ZB.MOM.WW.OtOpcUa.Driver.*.dll whose name reads as a status code, and asserts it equals Opc.Ua.StatusCodes.<name>. Discovery is by convention, so a new driver assembly referenced by that project is covered with no edit here. It went red on all nine defects above before the fixes and now checks 109 constants green. Because reflection can only see a NAMED constant, two inline literals were hoisted so the guard can reach them: Galaxy's BadTimeout/Bad into StatusCodeMap, and GatewayQualityMapper's 15-entry table into a new HistorianStatusCodes. An inline `0x800B0000u, // BadTimeout` at a call site is exactly how the Galaxy defect survived. The drivers stay SDK-free by design; only the test project references Opc.Ua.Core, as the oracle. Also corrected: tests that pinned the wrong values (Galaxy StatusCodeMapTests, SampleMapperTests, GatewayQualityMapperTests — all written from the same bad source), a mislabelled comment in DriverInstanceActorTests, and stale constants in two design docs, one of them the unexecuted MTConnect driver design that would have propagated BadNoData's wrong value into a new driver. The CLI's SnapshotFormatter value->name table was checked against the SDK and is correct; no change needed. |
||
|
|
fd0bec4ffe |
docs(driver-expansion): resolve all open design concerns from the review pass
Every concern the 7-agent review parked is now decided and integrated: - universal browser: in-flight capture coalescing keyed (driverType, config-hash) + global cap of 4 concurrent captures; CanBrowse catches a throwing TryCreate and defensively shuts down the throwaway instance; cleanup ShutdownAsync bounded at 10s (R2-01); picker Refresh = close + re-capture. Coalesced sessions share an immutable tree, so DisposeAsync drops the session's reference, not the tree. - mtconnect: UNAVAILABLE pinned to BadNoCommunication (fleet's BadCommunicationError stays reserved for the driver's own transport failures); TIME_SERIES sampleCount flows into ArrayDim; Subscribe timeout bounds only the stream-start handshake; library version/TFM folded into the license checklist. - mqtt: browse rebirth is an explicit DriverOperator-gated "Request rebirth" button (RequestRebirthAsync(scope)) - never fired by open/root/expand; hand-rolled reconnect loop committed for P1 (MQTTnet v5 dropped ManagedMqttClient); Wave-2-start library re-verification checkbox; implement from the Sparkplug v3.0 spec text. - bacnet: P1 opens with a first-spike checklist (package TFM, BBMD/ segmented-RPM/COV API smoke, unicast-I-Am fixture behavior); AdminUI-node browse registers a second foreign device - BBMD FD-table sizing note. - sql-poll: split-node browse needs env parity for Sql__ConnectionStrings__ refs on admin nodes (actionable error + session-only pasted literal); one-row-per-key query contract (last-wins + rate-limited warning); absent key -> BadNoData; operationTimeout > commandTimeout authoring rule; Browser->Driver.Sql SqlClient transitive on AdminUI accepted on record. - omron: FINS framer gated on W227 + live golden vectors; CIP string layout is the first P1 live-gate item; AbCip harness static-init anti-pattern note; writable-defaults-true operator warning. - modbus-rtu: first P1 step confirms pymodbus exposes framer=rtu on a TCP server (custom-script fallback otherwise). - program doc: new cross-cutting rule - driver ctors must be connection-free (the universal browser's CanBrowse throwaway instances depend on it). |
||
|
|
8fc147d8d4 |
docs: driver-expansion program — 8 research reports + 7 design docs, parallel-reviewed
Adds the driver-expansion program design (umbrella: universal Discover-backed browser + MTConnect, MQTT/Sparkplug B, BACnet/IP, SQL poll, Omron, Modbus RTU; MELSEC deferred) plus the per-driver research reports. All docs went through a 7-agent parallel review against the codebase before this commit. Highlights fixed in review: - universal browser: FOCAS FixedTree fills post-connect -> UntilStable settle + FixedTree.Enabled patch; MQTT reconciled to bespoke (was contradicting the program doc's SupportsOnlineDiscovery=false verdict) - modbus-rtu: SerialPort.ReadTimeout doesn't bound async BaseStream reads -> linked-CTS per-op deadline (R2-01 class); BCL enum reuse would leak System.IO.Ports into Contracts - bacnet: DiscoveryRediscoverPolicy enum name; UDP 47808 contention; live suite rewritten around unicast Who-Is + BBMD (broadcast doesn't cross VMs) - sql-poll: real tier registration via DriverFactoryRegistry.Register; blackhole gate must not docker-pause the shared central SQL Server - mqtt: Sparkplug v3.0 STATE topic form; first-in-repo proto codegen noted - omron: host hardcodes isIdempotent:false today (retry seam unshipped); v1 scopes UDTs to dotted-leaf access - mtconnect: SecurityClassification.ViewOnly; factory ParseEnum<T> pattern - program doc: both valid enum-serialization patterns; IRediscoverable is change-signal-gated; RTU P2 adds System.IO.Ports; label is host-side |