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
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# Next-driver research — index & consolidated roadmap
|
||||
|
||||
> **Overall program design:** [`docs/plans/2026-07-15-driver-expansion-program-design.md`](../../plans/2026-07-15-driver-expansion-program-design.md)
|
||||
> is the authoritative umbrella — shared architecture, cross-cutting rules, the browse-tier
|
||||
> decision, the dependency graph, and the wave build order. Start there; this file is the
|
||||
> research/design index it points back to.
|
||||
|
||||
Research sweep run 2026-07-15 (8 parallel agents). Each per-driver report covers
|
||||
protocol + .NET library options (with license analysis), capability mapping to the
|
||||
Equipment-kind driver seams, `TagConfig` JSON shape, a **browseability verdict +
|
||||
`IDriverBrowser`/`IBrowseSession` design where browsable**, test-fixture strategy,
|
||||
and effort/phasing. This index synthesizes them.
|
||||
|
||||
Scope decided with the user (2026-07-15): 7 new drivers + a browse-support audit of
|
||||
the existing driver fleet. See `[[project_next_driver_roadmap]]` memory.
|
||||
|
||||
## Reports
|
||||
|
||||
| Report | Driver |
|
||||
|---|---|
|
||||
| [`mtconnect-agent.md`](mtconnect-agent.md) | MTConnect (Agent-first) |
|
||||
| [`mqtt-sparkplug.md`](mqtt-sparkplug.md) | MQTT / Sparkplug B |
|
||||
| [`melsec-slmp.md`](melsec-slmp.md) | Mitsubishi MELSEC SLMP / MC Protocol |
|
||||
| [`omron.md`](omron.md) | Omron (CIP + FINS) |
|
||||
| [`bacnet-ip.md`](bacnet-ip.md) | BACnet/IP |
|
||||
| [`sql-poll.md`](sql-poll.md) | SQL poll |
|
||||
| [`modbus-rtu.md`](modbus-rtu.md) | Modbus RTU (extend existing Modbus) |
|
||||
| [`00-existing-driver-browse-audit.md`](00-existing-driver-browse-audit.md) | Browse audit of the 6 shipped browser-less drivers |
|
||||
|
||||
## Design docs (executable — built from the reports 2026-07-15)
|
||||
|
||||
Each non-deferred driver now has a build-ready design under `docs/plans/`:
|
||||
|
||||
| Driver | Design doc | Browse integration |
|
||||
|---|---|---|
|
||||
| Universal browser (Wave 0) | [`2026-07-15-universal-discovery-browser-design.md`](../../plans/2026-07-15-universal-discovery-browser-design.md) | — (the mechanism itself) |
|
||||
| MTConnect Agent | [`2026-07-15-mtconnect-driver-design.md`](../../plans/2026-07-15-mtconnect-driver-design.md) | **Universal** (`SupportsOnlineDiscovery`) |
|
||||
| BACnet/IP | [`2026-07-15-bacnet-ip-driver-design.md`](../../plans/2026-07-15-bacnet-ip-driver-design.md) | **Universal** (small sites); bespoke-lazy P-later |
|
||||
| MQTT/Sparkplug B | [`2026-07-15-mqtt-sparkplug-driver-design.md`](../../plans/2026-07-15-mqtt-sparkplug-driver-design.md) | **Bespoke** observation browser |
|
||||
| SQL poll | [`2026-07-15-sql-poll-driver-design.md`](../../plans/2026-07-15-sql-poll-driver-design.md) | **Bespoke** schema browser |
|
||||
| Omron | [`2026-07-15-omron-driver-design.md`](../../plans/2026-07-15-omron-driver-design.md) | None — offline Sysmac tag-export import |
|
||||
| Modbus RTU | [`2026-07-15-modbus-rtu-driver-design.md`](../../plans/2026-07-15-modbus-rtu-driver-design.md) | None (flat registers) — extends existing Modbus |
|
||||
|
||||
Browse split confirmed by the designs: **universal** covers MTConnect + BACnet (from `DiscoverAsync`);
|
||||
**bespoke** required for MQTT (passive observation window) and SQL (schema walk ≠ discovery);
|
||||
**Omron/Modbus-RTU** don't browse. All designs consume the universal browser's P1 addition of
|
||||
`ITagDiscovery.SupportsOnlineDiscovery` — build the universal browser first.
|
||||
|
||||
## New drivers — at a glance
|
||||
|
||||
| Driver | Library (license) | Read/Write | Browsable | Write in v1 | Effort |
|
||||
|---|---|---|---|---|---|
|
||||
| **MTConnect Agent** | TrakHound MTConnect.NET (MIT) | Read-only | **Yes** — `/probe` device model | No (telemetry std) | S–M (~1–1.5 wk) |
|
||||
| **MQTT / Sparkplug B** | MQTTnet v5 (MIT) + SparkplugNet (MIT, net10 risk) or hand-rolled Tahu | Read + subscribe | **Yes** — birth certs / topic tree (passive, time-bounded) | No | M |
|
||||
| **MELSEC SLMP** _(deferred)_ | Hand-roll 3E-binary framer (HslCommunication is a commercial-license blocker) | Read/Write | No — flat device memory | Yes | M (addressing) |
|
||||
| **Omron** | libplctag.NET (MPL-2.0) for CIP + hand-rolled FINS | Read/Write | CIP conditional (net-new) / FINS no | Yes | M–L (no free sim) |
|
||||
| **BACnet/IP** | System.IO.BACnet / ela-compil (MIT, net10 TFM) | Read + COV subscribe | **Yes** — Who-Is + object-list | No (write P3) | M–L |
|
||||
| **SQL poll** | Microsoft.Data.SqlClient (already in-repo) | Read-only | **Yes** — INFORMATION_SCHEMA | No (write later) | S–M |
|
||||
| **Modbus RTU** | Extend existing Modbus (new `IModbusTransport`) | Read/Write | No — flat registers | Yes | **S (lowest)** |
|
||||
|
||||
Notes:
|
||||
- **All fit the existing all-.NET-10 Equipment-kind model** — no COM gateway.
|
||||
- **MELSEC**: `HslCommunication` is a hard commercial-license blocker; the clean-license
|
||||
alternatives (McpX/MIT, McProtocol/LGPL) are too immature → hand-roll, patterned on S7.
|
||||
Repo already has `MelsecAddress`/`MelsecFamily` (from the Modbus-path work) to port.
|
||||
- **Omron CIP** reuses ~70–80% of AbCip's libplctag body, **but** libplctag's `@tags`
|
||||
walker returns `ErrorUnsupported` on Omron NJ/NX — CIP browse is net-new Omron work
|
||||
gated on the Sysmac "Network Publish" attribute, not free reuse.
|
||||
- **MQTT/Sparkplug** & **BACnet** discovery is **passive/time-bounded** (listen/broadcast
|
||||
over a window), unlike a synchronous OPC UA browse — the browse session handles this
|
||||
with an observation window (+ Sparkplug rebirth NCMD to force near-synchronous enum).
|
||||
- Every new driver needs a typed tag editor (`TagConfigEditorMap`+`TagConfigValidator`)
|
||||
and must apply `JsonStringEnumConverter` on enum config fields (the known
|
||||
`[[project_driver_enum_serialization_bug]]` trap).
|
||||
|
||||
## Existing-driver browse audit — verdicts
|
||||
|
||||
| Driver | Browsable? | Mechanism | Action |
|
||||
|---|---|---|---|
|
||||
| **AbCip** (ControlLogix EtherNet/IP) | **Yes** | CIP Symbol Object 0x6B + Template 0x6C — decode stack already ships | **Add browser** (~2–3 d) |
|
||||
| **TwinCAT** (Beckhoff ADS) | **Yes** | ADS symbol upload (`SymbolLoaderFactory`) — enumerator already ships | **Add browser** (~3–4 d) |
|
||||
| **FOCAS** (Fanuc CNC) | Borderline | Curated, not free-form (axes/spindles + macro/param/PMC ranges) | Curated browser, **deferred** (~3–5 d) |
|
||||
| **AbLegacy** (PCCC) | No | Numeric addresses (`N7:0`), no symbolic catalog | Skip (documented) |
|
||||
| **S7** (S7comm) | No | Symbols live in the TIA project, not the CPU | Skip (use OpcUaClient for optimized DBs) |
|
||||
| **Modbus** (TCP/RTU) | No | Flat register space, no discovery | Skip (documented) |
|
||||
|
||||
**Key finding:** AbCip & TwinCAT already contain complete, unit-tested symbol-enumeration
|
||||
logic buried in the runtime driver's `DiscoverAsync` (gated by `EnableControllerBrowse` /
|
||||
Flat-mode) and simply not surfaced as the interactive `IDriverBrowser` the AdminUI picker
|
||||
consumes. Their browsers are a **wrapping job over existing code**, not new protocol work —
|
||||
the razor picker bodies already exist as static manual-entry stubs.
|
||||
|
||||
**Shareable code:** the CIP browse core (0x6B/0x6C decoders + system-tag filter + UDT
|
||||
layout) is protocol-CIP, not Rockwell-specific — extract a shared `Cip.Core` lib **only
|
||||
if/when** Omron CIP browse lands (don't pre-abstract). Both AbCip & TwinCAT already expose
|
||||
their enumerator behind an interface = the ready-made reuse seam.
|
||||
|
||||
## Unified browse-support picture
|
||||
|
||||
**Browsers to build (net + existing), by protocol richness:**
|
||||
- Synchronous, model-rich: **AbCip**, **TwinCAT**, **MTConnect** (`/probe`), **SQL** (schema), **BACnet** (object-list), **Omron-CIP**.
|
||||
- Passive/time-bounded: **MQTT/Sparkplug** (observation window / rebirth).
|
||||
- Curated/fixed surface: **FOCAS** (deferred).
|
||||
|
||||
**Not browsable — documented, decision recorded so it isn't revisited:**
|
||||
MELSEC SLMP · Modbus TCP · Modbus RTU · S7 · AbLegacy · Omron-FINS (all flat address spaces / no on-wire symbol table).
|
||||
|
||||
## Recommended build order (value × effort)
|
||||
|
||||
**Wave 0 — universal Discover-backed browser (the foundational browse piece):**
|
||||
1. **Universal `DiscoveryDriverBrowser`** — ONE generic `IDriverBrowser` that runs any
|
||||
discovery-capable driver's `ITagDiscovery.DiscoverAsync` against a capturing
|
||||
`IAddressSpaceBuilder` and serves the captured tree back through the picker. Lights up
|
||||
AbCip, TwinCAT, FOCAS, MTConnect, BACnet (small sites), authored-MQTT, and every future
|
||||
discovery driver's picker with **zero per-driver browser code**. Gated on a new
|
||||
online-discovery capability flag so flat-address drivers stay manual-entry. Design:
|
||||
[`docs/plans/2026-07-15-universal-discovery-browser-design.md`](../../plans/2026-07-15-universal-discovery-browser-design.md).
|
||||
2. **AbCip / TwinCAT** — covered *immediately* by the universal browser (their enumeration
|
||||
already lives in `DiscoverAsync`). Graduate each to a **bespoke lazy `IBrowseSession`**
|
||||
only if a real controller's symbol set is too large for the universal browser's eager
|
||||
one-shot discovery (UDT drill-down / per-click expand). Not up-front work anymore.
|
||||
|
||||
**Wave 1 — low-effort, high-leverage new drivers:**
|
||||
3. **Modbus RTU** — lowest-effort new capability; extends the existing driver via one new `IModbusTransport` (lead with RTU-over-TCP for the containerized server).
|
||||
4. **SQL poll** — zero new NuGet deps (SqlClient already in-repo), broad MES/ERP glue value, browsable.
|
||||
|
||||
**Wave 2 — strategic new drivers:**
|
||||
5. **MTConnect Agent** — MIT library, clean browse, complements FOCAS with vendor-neutral machine-tool telemetry.
|
||||
6. **MQTT / Sparkplug B** — UNS-strategic; plain-MQTT first to stand up the skeleton + validate MQTTnet/net10, then Sparkplug birth-driven discovery.
|
||||
|
||||
**Wave 3 — heavier / test-gated:**
|
||||
7. **BACnet/IP** — opens facilities/HVAC/energy; COV + discovery + BBMD are the meaty parts (live-gate the broadcast reachability).
|
||||
8. **Omron** — CIP-first (libplctag) then FINS; last of the active set because there's **no free NJ/NX CIP simulator**, so real-wire correctness is a live-hardware `LiveIntegration` gate.
|
||||
|
||||
**Deferred (research complete, not scheduled):**
|
||||
- **MELSEC SLMP** — deferred (2026-07-15). The mature library is a commercial-license
|
||||
blocker so it's a full hand-rolled 3E-binary framer with the hardest addressing model
|
||||
on the roadmap (device-code × bit/word × hex/octal/decimal × word order); revisit when
|
||||
a Mitsubishi-shop customer need makes it worth the build. Report stays valid as the
|
||||
starting point.
|
||||
|
||||
FOCAS browser slots opportunistically whenever the CNC surface is being touched.
|
||||
|
||||
## Per-driver add pattern (reference)
|
||||
|
||||
`*.Contracts` project + driver impl (Connect/Discover/Read/Subscribe[/Write]) + factory +
|
||||
`DriverType` string + typed tag editor (`TagConfigEditorMap`+`TagConfigValidator`) +
|
||||
optional `*.Browser` project (register one line at
|
||||
`EndpointRouteBuilderExtensions` AddAdminUI DI) + docker fixture (`project=lmxopcua`
|
||||
label). Watch the enum-serialization trap and add a per-query/-op timeout deadline
|
||||
(the R2-01 frozen-peer lesson) on every network call.
|
||||
Reference in New Issue
Block a user