# 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.