You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2026/08/16 13:42:21 UTC

(plc4x) 04/04: docs: Update the feature matrix of PLC4X' drivers.

This is an automated email from the ASF dual-hosted git repository.

chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit eacd01dc299b9fc3f2d1b19fe23b374445df5b55
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sun Aug 16 15:40:36 2026 +0200

    docs: Update the feature matrix of PLC4X' drivers.
---
 .../modules/users/pages/protocols/ctrlx.adoc       |  30 +-
 .../modules/users/pages/protocols/index.adoc       | 367 ++++++++++-----------
 2 files changed, 200 insertions(+), 197 deletions(-)

diff --git a/website/asciidoc/modules/users/pages/protocols/ctrlx.adoc b/website/asciidoc/modules/users/pages/protocols/ctrlx.adoc
index f65ff4e551..ec21e90cf7 100644
--- a/website/asciidoc/modules/users/pages/protocols/ctrlx.adoc
+++ b/website/asciidoc/modules/users/pages/protocols/ctrlx.adoc
@@ -19,9 +19,10 @@
 
 = CtrlX
 
-WARNING: This driver is unfinished and not usable yet. Only browsing and pinging work at all; there
-is no tag address syntax, so reading and writing are not available. This page describes the current
-state for anyone continuing the work - it is not linked from the navigation.
+WARNING: This driver is unfinished and not usable yet. Discovery and pinging are the only things
+that work; there is no tag address syntax, so reading and writing are not available, and the browse
+implementation does not work yet either. This page describes the current state for anyone
+continuing the work - it is not linked from the navigation.
 
 The CtrlX driver talks to Bosch Rexroth ctrlX CORE devices through their REST/Data-Layer API over
 HTTPS, rather than over an industrial fieldbus protocol.
@@ -32,17 +33,25 @@ HTTPS, rather than over an industrial fieldbus protocol.
 |===
 |Operation |Description
 
-|`browse`
-|Enumerates the device's Data Layer nodes. This is the driver's main capability.
-
 |`ping`
 |Checks that the device is reachable and the credentials are accepted.
 
+|`discover`
+|Locates ctrlX CORE devices on the local network.
+
+|`browse`
+|*Does not work yet.* The connection carries an implementation that is meant to enumerate the
+device's Data Layer nodes, and it is the furthest along of the unfinished operations, but it does
+not produce usable results.
+
 |`read` / `write` / `subscribe`
-|*Not implemented.* The connection reports these as supported in its metadata, but the
-corresponding request builders return `null`, so attempting one fails. Use `browse` for now.
+|*Not implemented.* The corresponding request builders return `null`, so attempting one fails.
 |===
 
+The connection reports all four of these as unsupported in its metadata, so a caller that checks
+`getMetadata()` before deciding what to do gets an honest answer rather than being sent into a
+request that cannot succeed.
+
 == Connection String
 
 ----
@@ -69,8 +78,11 @@ PlcConnection connection = new DefaultPlcDriverManager()
 
 == Browsing
 
+NOTE: Browsing does not work yet. What follows describes how the existing implementation is meant
+to be used, for whoever picks the work up.
+
 Browse queries are glob patterns matched against the Data Layer node paths, not tag addresses.
-`**` matches everything and is the simplest way to see what a device exposes:
+`**` matches everything and is intended as the simplest way to see what a device exposes:
 
 [source,java]
 ----
diff --git a/website/asciidoc/modules/users/pages/protocols/index.adoc b/website/asciidoc/modules/users/pages/protocols/index.adoc
index 5db9eaefa4..91221da6fb 100644
--- a/website/asciidoc/modules/users/pages/protocols/index.adoc
+++ b/website/asciidoc/modules/users/pages/protocols/index.adoc
@@ -18,7 +18,9 @@
 
 = Current language support for protocols
 
-
+The tables below list the drivers that actually ship with each language implementation.
+A protocol only appears as supported where a driver exists and is registered with that
+implementation's driver manager - a protocol specification on its own is not enough.
 
 |===
 |Protocol | C | C# | Go | Java | Python
@@ -44,17 +46,24 @@
 |icon:exclamation[role="yellow"]
 |icon:times[role="red"]
 
-|CBus
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|CAN (raw)
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:exclamation[role="yellow"]
+|icon:times[role="red"]
 
 |CANopen
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:times[role="red"]
+
+|CBus
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
 |icon:exclamation[role="yellow"]
 |icon:times[role="red"]
 
@@ -62,7 +71,7 @@
 |icon:times[role="red"]
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:times[role="red"]
+|icon:exclamation[role="yellow"]
 |icon:times[role="red"]
 
 |DF1
@@ -75,7 +84,7 @@
 |EtherNet/IP
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
 |icon:check[role="green"]
 |icon:times[role="red"]
 
@@ -89,8 +98,8 @@
 |Firmata
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:question[role="red"]
-|icon:check[role="green"]
+|icon:times[role="red"]
+|icon:exclamation[role="yellow"]
 |icon:times[role="red"]
 
 |IEC-60870
@@ -102,7 +111,7 @@
 
 |KNXnet/IP
 |icon:times[role="red"]
-|icon:times[role="red"]
+|icon:exclamation[role="yellow"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:times[role="red"]
@@ -117,7 +126,7 @@
 |OPC-UA
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
 |icon:check[role="green"]
 |icon:times[role="red"]
 
@@ -129,7 +138,7 @@
 |icon:times[role="red"]
 
 |PLC4X (Proxy-Protocol)
-|icon:times[role="red"]
+|icon:check[role="green"]
 |icon:times[role="red"]
 |icon:times[role="red"]
 |icon:check[role="green"]
@@ -145,14 +154,14 @@
 |S7
 |icon:check[role="green"]
 |icon:times[role="red"]
-|icon:exclamation[role="yellow"]
+|icon:check[role="green"]
 |icon:check[role="green"]
 |icon:times[role="red"]
 
 |Simulated
+|icon:check[role="green"]
 |icon:times[role="red"]
-|icon:times[role="red"]
-|icon:times[role="red"]
+|icon:check[role="green"]
 |icon:check[role="green"]
 |icon:times[role="red"]
 
@@ -160,7 +169,7 @@
 |icon:times[role="red"]
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:exclamation[role="yellow"]
+|icon:check[role="green"]
 |icon:times[role="red"]
 
 |UMAS
@@ -175,248 +184,230 @@
 |===
 |Legend:
 
-- icon:check[role="green"] Implemented and fully supported
-- icon:exclamation[role="yellow"] Work in progress
-- icon:check[role="red"] Not implemented yet
-- icon:question[role="red"] Unsure
+- icon:check[role="green"] Implemented and usable
+- icon:exclamation[role="yellow"] Partially implemented - see the notes below
+- icon:times[role="red"] Not implemented
 
 |===
 
+Notes on the partially implemented drivers:
+
+* *AB-Ethernet* (Java) reads and offers polled subscriptions; there is no write support.
+* *BACnet/IP* passively receives broadcast traffic and exposes it as subscriptions. It does not read or write properties.
+* *CAN (raw)* (Java) writes and subscribes; there is no read support.
+* *CBus* (Java) is a skeleton that connects but implements no operations. The Go driver is the complete one.
+* *ctrlX* (Java) discovers devices and answers pings. Its read, write and subscribe builders are not implemented, and although the connection carries browse code, browsing does not work yet.
+* *Firmata* (Java) writes and subscribes; there is no read support.
+* *KNXnet/IP* (C#) is the only driver in plc4net and has not kept pace with the other implementations.
+* *Open-Protocol* (Java) is a skeleton that connects but implements no operations.
+* *Profinet* (Java) browses, discovers and subscribes to cyclic data; it has no read or write support. Both the `profinet` and the newer `profinet-ng` driver behave this way.
+
+*DF1* has a protocol specification in the repository, and plc4go additionally ships the generated
+message model for it, but no language implementation has a driver: there is nothing that can open a
+DF1 connection. DF1 command messages also appear inside the AB-Ethernet model, which is where that
+protocol is actually used today.
+
 == Features
-:icons: font
-The following table contains a list of operations and the protocols that support them:
+
+The table below lists which operations each driver actually implements. It describes *plc4j*,
+because that is the most complete implementation; the other languages support a subset. An
+operation is listed as supported where the driver implements it - drivers report their own
+metadata inconsistently, so this table follows the code rather than the metadata.
 
 |===
-|Protocol |Auto-Discover |Browse |Read Single Address Value |Read Multiple Address Values |Write Single Address Value |Write Multiple Address Value|Subscribe to Value changes |Subscribe to PLC Events/Alarms |Publish Values
+|Protocol |Discovery |Browse |Read |Write |Subscribe |Ping
 
 |AB-Ethernet
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
 |icon:check[role="green"]
-|icon:check[role="red"]
-|icon:check[role="red"]
-|icon:check[role="red"]
-|icon:check[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:exclamation[role="yellow"]
+|icon:times[role="red"]
 
 |ADS /AMS
-|icon:question[role="red"]
-|icon:question[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
 
 |BACnet/IP
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
-|CBus
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|CAN (raw)
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
 |CANopen
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
-|DF1
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|CBus
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+
+|ctrlX
+|icon:check[role="green"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
 
 |EtherNet/IP
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:exclamation[role="yellow"]
+|icon:times[role="red"]
 
 |EtherNet/IP - Logix
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:exclamation[role="yellow"]
+|icon:times[role="red"]
 
 |Firmata
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
 |IEC-60870
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
 |KNXnet/IP
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
 
 |Modbus (TCP/RTU/ASCII)
-|icon:question[role="red"]
-|icon:question[role="red"]
 |icon:check[role="green"]
+|icon:times[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
+|icon:exclamation[role="yellow"]
 |icon:check[role="green"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
 
 |OPC-UA
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:check[role="green"]
+|icon:times[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
 
 |Open-Protocol (Torque-Tools)
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
 
 |PLC4X (Proxy-Protocol)
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:times[role="red"]
+|icon:times[role="red"]
 
 |Profinet
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:times[role="red"]
 
 |S7
-|icon:question[role="red"]
-|icon:question[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
-|icon:exclamation[role="yellow"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
 
 |Simulated
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-
-|SLMP (MELSEC)
 |icon:times[role="red"]
 |icon:times[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+
+|SLMP (MELSEC)
 |icon:times[role="red"]
 |icon:times[role="red"]
-|icon:times[role="red"]
-|icon:times[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:exclamation[role="yellow"]
 |icon:times[role="red"]
 
 |UMAS
-|icon:question[role="red"]
-|icon:check[role="green"]
+|icon:times[role="red"]
 |icon:check[role="green"]
 |icon:check[role="green"]
 |icon:check[role="green"]
+|icon:exclamation[role="yellow"]
 |icon:check[role="green"]
-|icon:question[role="red"]
-|icon:question[role="red"]
-|icon:question[role="red"]
 
 |===
 
 |===
-
 |Legend:
 
-- icon:check[role="green"] Implemented and fully supported
-- icon:exclamation[role="yellow"] Implemented and supported by simulation
-- icon:check[role="red"] Not implemented yet
-- icon:question[role="red"] Unsure
-|===
\ No newline at end of file
+- icon:check[role="green"] Implemented by the driver
+- icon:exclamation[role="yellow"] Emulated: the protocol has no native support, so PLC4X provides it
+- icon:times[role="red"] Not implemented
+
+|===
+
+Protocols such as Modbus have no notion of a subscription - a client has to poll. Drivers for those
+protocols extend `PollingSubscriptionConnectionBase`, which turns a subscription request into a
+polling loop and emits change events from it, so application code can use the same subscription API
+everywhere. This is what the yellow subscription entries above mean; the traffic on the wire is
+still a sequence of reads. AB-Ethernet, EtherNet/IP (including Logix), Modbus, SLMP and UMAS work
+this way.
+
+The Logix driver reuses the EtherNet/IP connection, so it supports the same operations, but it does
+not expose device discovery. S7 discovery uses PROFINET DCP and needs the optional pcap4j runtime
+(and libpcap on the host) to be installed.
+
+A read or write request always carries a set of tags, so there is no separate "single value" and
+"multiple values" support: a driver that can read can read any number of tags in one request. How
+efficiently it does so differs - some drivers split a request into several PLC requests and merge
+the responses.