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

AB-Ethernet

ADS /AMS

BACnet/IP

CAN (raw)

CANopen

CBus

ctrlX

DF1

EtherNet/IP

EtherNet/IP - Logix

Firmata

IEC-60870

KNXnet/IP

Modbus (TCP/RTU/ASCII)

OPC-UA

Open-Protocol (Torque-Tools)

PLC4X (Proxy-Protocol)

Profinet

S7

Simulated

SLMP (MELSEC)

UMAS

Legend:

- Implemented and usable - Partially implemented - see the notes below - Not implemented

Notes on the partially implemented drivers:

  • AB-Ethernet reads and offers polled subscriptions in both Java and Go; neither writes.

  • BACnet/IP (Java) passively receives broadcast traffic and exposes it as subscriptions; it does not read or write properties. The Go driver is the complete one: it reads and writes properties, discovers devices and subscribes to COV notifications.

  • 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) answers pings; that is the only operation it completes. Discovery is offered by the driver, but CtrlXPlcDiscoverer.discoverWithHandler is an unimplemented TODO that returns null instead of a future, so a discovery request fails rather than finding anything. Its read, write and subscribe builders are not implemented either, and although the connection carries browse code, browsing does not work yet.

  • Firmata writes and subscribes in both Java and Go; neither reads. A board is driven and monitored, never polled.

  • IEC 60870-5-104 subscribes only, in both Java and Go, because the protocol is push driven: the RTU sends unsolicited ASDUs once the session is started, so there is nothing to read or write. The Go driver keeps the IEC quality descriptors alongside each value, so a reading the RTU marked invalid, blocked, substituted or not-topical does not arrive looking like a good one.

  • KNXnet/IP (C#) is the only driver in plc4net and has not kept pace with the other implementations.

  • OPC-UA (Go) reads, writes and subscribes over an unencrypted channel, but that is where it ends: only securityPolicy=None actually works, browsing is not implemented, and messages are not chunked, so a request or response larger than a single chunk fails. The Java driver implements the six security policies, browsing and chunking.

  • Open-Protocol (Java) is a skeleton that connects but implements no operations.

  • Profinet (Java) discovers devices and browses the submodules of a connected device; neither of the two Java drivers has read or write support. Only the newer profinet-ng driver is part of plc4j-driver-all; the older profinet driver is still in the code base but is not bundled. In profinet-ng a subscription request completes the PROFINET connect handshake, but the subscription response future is deliberately left incomplete and onRegisterConsumer throws UnsupportedOperationException, so no cyclic data ever reaches an application. The unbundled profinet driver does implement that path - it completes the subscription response, registers consumers per subscription handle and dispatches a PlcSubscriptionEvent for every incoming cyclic frame - so the subscribe entry below, which describes what ships, does not apply to it.

  • SLMP addresses the word devices D, W and R only, in both Java and Go. That is the scope the driver was written to rather than a port gap - the bit devices and the wider MELSEC command set are not implemented in either language.

  • UMAS (Go) refuses DATE and TIME_OF_DAY tags rather than answering them: the Go data item parser has no case for those field names yet, so the bytes would parse to no value. Every other data type reads and writes. Note also that UMAS ships no test data in any language, so both drivers are verified against each other rather than against a captured exchange.

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

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 Discovery Browse Read Write Subscribe Ping

AB-Ethernet

ADS /AMS

BACnet/IP

CAN (raw)

CANopen

CBus

ctrlX

EtherNet/IP

EtherNet/IP - Logix

Firmata

IEC-60870

KNXnet/IP

Modbus TCP

Modbus RTU / ASCII

OPC-UA

Open-Protocol (Torque-Tools)

PLC4X (Proxy-Protocol)

Profinet (profinet-ng)

S7

Simulated

SLMP (MELSEC)

UMAS

Legend:

- Implemented by the driver - Emulated: the protocol has no native support, so PLC4X provides it - 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. Modbus discovery is likewise a TCP-only feature: only ModbusTcpDriver offers a discovery request builder, so the serial RTU and ASCII flavors cannot discover devices. 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.