============================================================== Apache PLC4X 1.0.0 ============================================================== New Features ------------ - Java Configurations of drivers now support a "FILE" type of configuration parameter. - Subscription of change-of-state values now supports providing a min time interval to prevent excessive notifications. - Added a new PlcCertificateAuthentication to the API module. - Initial version of a new Java UMAS driver. - Initial version of a new Java SLMP (Mitsubishi MELSEC) driver: read and write access to word devices (D/W/R) using binary 3E frames over TCP (including Batch Write). - The 'plc4x' proxy driver now supports TLS as a transport and requires mandatory username/password authentication (configured via the new "username" and "password" connection parameters). - The Go serial transport now supports the full set of serial options in the connection string: data-bits, stop-bits, parity, flow-control, dtr, rts, read-timeout and write-timeout. - The Go serial transport supports sharing one physical serial port between multiple connections ("reuse-port", e.g. multi-slave Modbus RTU) with broadcast reads and serialized writes, plus inter-frame write pacing ("interframe-delay") on both shared and dedicated ports. - The Java serial transport's shared-port mode ("reuse-port") now uses a single broadcast reader per physical port, fixing responses being split between connections, and "interframe-delay" write pacing works on both shared and dedicated ports (gap measured from the last write or received data). - The Java Modbus RTU codec now frames responses by function code with CRC validation and byte-wise resynchronization: batched deliveries (e.g. on shared serial ports) yield every frame instead of only the first, and partial or corrupted frames no longer discard buffered data. - Java Modbus serial connections (RTU/ASCII) now serialize their requests per connection (single outstanding transaction, matching the protocol), fixing concurrent same-unit requests receiving each other's responses; unknown Modbus exception codes map to REMOTE_ERROR instead of failing; shared serial ports dispatch each connection's callbacks on their own thread, so one blocked callback no longer stalls the whole port. Responses are additionally validated against the pending request's function code (late responses from timed-out requests are discarded instead of completing the wrong caller), and the request timeout now covers the full time from submission, including queueing. - Drivers that don't natively support subscriptions (Modbus, EtherNet/IP, AB-ETH, SLMP, UMAS) now provide subscriptions through a polling-based emulation layer, supporting CYCLIC and CHANGE_OF_STATE subscriptions. - Added a new remote-data-fetching component (event-pump) replacing the old scraper. - Re-implemented the connection-cache with more reliable resource handling and transparent re-subscription after a connection was lost and re-established. - New TCP transport implementation using per-connection virtual-thread blocking I/O (replacing the NIO selector), scaling better on Java 21. - OPC-UA: Added reading and writing of structured values (PlcStruct) and corrected array handling. - OPC-UA: Tag data types are now derived from the server's type model instead of being guessed from the input data. - OPC-UA: Added browse support, resolving server-side types and access rights. - Simulated driver: Added STRING support. - CANopen: Added NMT command support. - Go: Added a production-grade BACnet/IP driver (segmentation, write priority, directed/multi-target WhoIs, routed addressing, array/bit-string property decoding). - Go: The connection-cache now supports a configurable max idle time, and connections carrying subscriptions are exempt from the idle TTL. - The Object-PLC-Mapping (OPM) module was ported to SPI3. - PlcBrowseItem now reports which subscription types each item supports via a new getSupportedSubscriptionTypes() method, so browse results carry subscription capability information. - OPC-UA: Improved Siemens S7-1500 support, including reading and writing of (almost) all variant types. - Updated the bundled KNX manufacturer data and the BACnet/KNX vendor IDs for broader device recognition. - Go: Connections can now be invalidated (Invalidate()) to mark themselves irrecoverably failed for lease management, and transport errors are now classified and propagated through codecs/transports (TransportErrorKind). - Performance: Sped up byte-aligned integer read/write in the Java byte-based SPI buffers. - EtherNet/IP: The CIP bit-string types (BYTE, WORD, DWORD, LWORD) and unsigned integer types (USINT, UINT, UDINT, ULINT) can now be read and written, in both the Java and the Go drivers. They were accepted by the address parser but not decoded, so reading such a tag returned INTERNAL_ERROR. All eight are unsigned over their full range: a DWORD reads as 0 to 4294967295 and an LWORD as 0 to 18446744073709551615. Their signed counterparts are unchanged - a DINT of 0xFFFFFFFF still reads as -1. - Modbus: STRING and WSTRING values can now be read and written, in PLC4J, PLC4Go and PLC4C. The length of one string is written in parentheses the way the S7 driver spells it, so "holding-register:1[0..2]:STRING(20)" is three 20-character strings. - OPC-UA: A new "subscription-queue-size" parameter (default 1) keeps the values a server queues between publishes. With a depth above one, change-of-state items are sampled at the server's fastest rate and every queued value is delivered instead of only the last. At the default nothing changes, and event and cyclic items keep a queue of one either way. - OPC-UA: A new "min-channel-lifetime-ms" parameter (default 5000) bounds a channel lifetime the server revises downwards. Channel renewals run on one executor shared by every OPC UA connection in the JVM, so a single server answering with a very short - or zero - lifetime used to set the pace for all of them. - OPC-UA: Added authentication with an X509 user certificate (GH-1845). - EtherNet/IP: The driver falls back to "Get Attribute Single" where a device does not answer "Get Attribute All", so the Connection Manager and the Message Router are detected on devices that only support the single-attribute form. - S7: A connection reports what the device says about itself. "readDeviceIdentification()" reads the module type, order number, serial number, firmware version and protection level out of the SZL lists, following a list the CPU splits across several PDUs. - The event-pump accepts a trigger interval in milliseconds ("intervalMillis" / "initialDelayMillis") beside the existing whole-second form. Giving the same setting in both units fails at startup rather than silently picking one. - Go: PLC4Go gained five drivers - AB-Ethernet, Firmata, IEC 60870-5-104, SLMP (MELSEC) and UMAS - taking it from nine drivers to fourteen. AB-Ethernet and Firmata are as partial as they are in Java (one does not write, the other does not read), IEC 60870-5-104 subscribes and nothing else because the protocol is push driven, and SLMP addresses the word devices D, W and R. - Go: The EtherNet/IP driver was brought up to the Java driver's level: all three read and write paths (sequential, message-router and connected), the plc4j connect handshake, UDP broadcast discovery (ListIdentity) over per-interface sockets, a "logix" driver alias forcing little-endian encapsulation, and the "bigEndian", "forceUnconnectedOperation", "communicationPath" and "connectionSerialNumber" options. - Go: The S7 driver gained browse (static areas and DB block enumeration), alarm and cyclic subscriptions with alarm query and push dispatch, a real round-trip ping, and parsing of S5TIME, variable-length strings and alarm tag addresses. - Go: Modbus RTU and Modbus ASCII have codecs of their own, including the RTU CRC and the ASCII LRC, and the tag, value and configuration gaps to the Java driver are closed. - Go: The KNXnet/IP driver writes group addresses, and its subscriptions work. - Go: A polling-subscription base is part of the default connection set, so a driver whose protocol has no subscriptions can offer them the way the Java drivers do. - Go: PlcDATE and PlcTIME_OF_DAY expose their components rather than only the whole value. - Go: Every timeout is named (utils.WithNamedTimeout), so an expiry says which timeout it was. - The API's "Option" type reports whether a configuration option carries a secret ("isSecret()"), which is what redaction now asks instead of guessing from the parameter's name. It is a default method returning false, so existing implementations keep compiling. Incompatible changes -------------------- - Configuration parameters now use one vocabulary across PLC4J and PLC4Go. A duration in milliseconds ends in "-ms", TLS settings live under "tls.", and a parameter aimed at a transport no longer repeats that transport's code. Old names are removed rather than deprecated: supplying one is reported as an unknown parameter, naming the replacement, and the setting does not apply. The full table is below. Durations: request-timeout -> request-timeout-ms timeout-request (ads) -> request-timeout-ms connect-timeout -> connect-timeout-ms read-timeout -> read-timeout-ms write-timeout -> write-timeout-ms session-timeout -> session-timeout-ms channel-lifetime -> channel-lifetime-ms min-channel-lifetime -> min-channel-lifetime-ms ha-heartbeat-interval -> ha-heartbeat-interval-ms ha-failover-timeout -> ha-failover-timeout-ms Establishing a socket and completing a protocol handshake are two settings, not one, so they now have two names. "connect-timeout-ms" is the socket connect; the COTP handshake and the OPC UA negotiation steps are "handshake-timeout-ms": cotp.cotp-connection-timeout -> cotp.handshake-timeout-ms negotiation-timeout (opcua) -> handshake-timeout-ms Transport parameters no longer repeat their transport's code, which the prefix already supplies: tcp.tcp-no-delay -> tcp.no-delay cotp.cotp-tpdu-size -> cotp.tpdu-size tls.tls-version -> tls.version TLS settings are addressed under "tls.": tls.verify-ssl -> tls.verify key-store-file (opcua) -> tls.keystore key-store-password -> tls.keystore-password key-store-type -> tls.keystore-type trust-store-file -> tls.trust-store trust-store-password -> tls.trust-store-password trust-store-type -> tls.trust-store-type The trust store drops "-file" for the same reason the key store does: every one of these names a store, so saying so adds nothing. The TLS transport already spelled them "tls.trust-store-file"; that becomes "tls.trust-store" too, so the opcua and ctrlx drivers, which declare their own, now agree with it. A name a protocol specification fixes keeps its own spelling and units: SLMP's "monitoring-timer" is a field of the 3E request frame in the protocol's own units, not a value in milliseconds, so it is unchanged and carries a comment at its declaration saying why. - The OPC UA driver's "insecure-certificate-verification" became "tls.verify", with the opposite sense. A connection that set "insecure-certificate-verification=true" must now set "tls.verify=false". This one is not just a rename: if it is missed, the new default applies, which is to verify the server certificate. That fails loudly against a server whose certificate does not validate rather than connecting insecurely, but it is a behaviour change and not a silent one. - An unrecognised connection-string parameter is now reported in PLC4Go as well as PLC4J, naming the parameter and, where it can, the nearest known one. It remains a warning: a stray parameter does not fail a connection that would otherwise work. PLC4Go's OPC UA driver previously *refused* the connection on an unknown option; it now warns like every other driver, so a connection string accepted by PLC4J is no longer rejected there. In PLC4Go this covers the drivers that parse their configuration in one place: ab-eth, bacnet-ip, c-bus, EtherNet/IP, firmata, IEC 60870-5-104, Modbus, OPC UA, S7, SLMP and UMAS. The ADS, KNXnet/IP and simulated drivers read their options where they are used rather than parsing a configuration, so there is no point at which the leftovers are known; they are unchanged and still report nothing. The report also knows which transport the connection actually uses, so a parameter that belongs to a different transport - "serial.baud-rate" on a TCP connection - is called out as misdirected instead of being silently excused as "some transport's". A suggestion is offered only among the names the consumer that reported actually read, so a parameter belonging to a transport is named as unknown with nothing to suggest. PLC4J does better here: it draws the known names from the driver, the transport, the audit log and the connection-control options, and matches on the last segment, so a missing prefix is recognised for what it is. - Configuration values carrying secrets are marked at their declaration - "@Secret" in PLC4J, a `secret:"true"` struct tag in PLC4Go - and render as "" wherever a configuration is rendered. This replaces guessing from parameter names, which could only ever be one parameter behind: a pre-shared key was logged in clear until its name was added to the list by hand. A name-based check remains for parameters no configuration declares, since a credential passed under an unknown name is still a credential. - PLC4Go's S7 driver reads the rack and slot as "cotp.local-rack", "cotp.local-slot", "cotp.remote-rack" and "cotp.remote-slot". It read them unprefixed, while PLC4J declares them on the COTP transport's configuration and every S7 example in the documentation spells them with the prefix - so the documented connection string set nothing in PLC4Go and said so nowhere. The unprefixed names are now reported as unknown. - Fixed PLC4Go logging connection strings verbatim. A password in a Go connection string reached the log in clear at debug level, at twenty call sites across the driver manager and the connection cache. They are redacted now, along with credentials in a URI's userinfo. The parsed URL and the connection container render redacted too - both reached the same log lines by another route, so a redacted field sat beside the credential it was hiding. - PLC4Go addresses a transport's connection-string options under the transport's own code, as PLC4J does and as the documentation has always said: "tcp.connect-timeout-ms", "serial.baud-rate", "udp.so-reuse", "pcap.speed-factor". They were read unprefixed, so every documented transport setting was ignored in PLC4Go and left at its default. The unprefixed names are now reported as unknown rather than silently doing nothing. Options a driver injects into the map itself ("defaultTcpPort") are not addressed by anyone and keep their bare names. - PLC4Go's OPC UA driver reads the parameter names PLC4J declares and the documentation lists - "tls.keystore", "tls.keystore-password", "security-policy", "allow-unverified-security-policies" - rather than names derived from its own Go struct fields ("keyStoreFile", "securityPolicy"). The documented connection string reached it as a set of unknown options and was ignored. - A secret marking in PLC4Go applies whatever the field's type is. The generator honoured "secret:\"true\"" only where it rendered a string, so the tag on any other kind of field was accepted and silently did nothing. The OPC UA key pair now carries the marking in both the configuration and the secure channel. - Redaction decides from the parameter name the driver will read, not the name as written: "?%70assword=hunter2" is the password parameter once the query is decoded, and was previously logged in clear. A connection string nested inside another (the PLC4X proxy driver's "remote-connection-string") is redacted as a connection string in its own right, so its credentials no longer travel through the outer one - while which PLC the proxy talks to stays visible. - A BACnet/IP connection reported each unknown option once rather than twice. Its options are parsed both by the driver, for the discovery timeout, and by the connection; both reported, so one mistake read as two. - The connection-creating methods of the API moved from "PlcConnectionManager" to a new "PlcConnectionFactory" interface, which the "PlcDriverManager" hands out via "getConnectionFactory()" (formerly "getConnectionManager()"). "PlcConnectionManager" now extends "PlcConnectionFactory" and adds the "close()" method, and is only implemented by managers that keep the connections they hand out, such as the connection cache. - The connection cache was renamed from "CachedPlcConnectionManager" to "PlcConnectionCache", matching the name the concept already has in PLC4Go. Its builder method "withConnectionManager()" became "withConnectionFactory()", and "PlcConnectionManagerClosedException" became "PlcConnectionCacheClosedException". The Maven artifactId ("plc4j-tools-connection-cache") and the package are unchanged. - All drivers were migrated to a new shared SPI ("SPI3"): dependency-free Read/Write buffers, an updated code-generation framework, a pluggable-transport system and a layered protocol-driver model. - Drivers now reject connection strings using an unsupported transport with an exception. The check can be force-disabled via a configuration parameter. - Several Maven artifactIds changed (tools, transports, scraper); see the "Changed Maven Coordinates" section below for the full mapping. Consumers must update their coordinates. - The PlcBrowseItem interface gained a getSupportedSubscriptionTypes() method that custom implementations must now provide. - Dropped support for Java 11, new baseline Java version is Java 21. - Migrated the build to Apache Maven 4. - The Go serial transport's default baud-rate changed from 115200 to 9600 (aligning with common serial defaults and the Java transport). Specify baud-rate explicitly if you relied on the previous default. - Go serial reads/writes without an explicit context deadline are now bounded by the new read-timeout/write-timeout options (default 1000 ms; set to 0 for the previous blocking behavior), and invalid serial option values now fail connection creation instead of being silently ignored. - The Java serial transport removed the unused options "break-enabled", "receive-buffer-size" and "send-buffer-size", removed the combined "RTS_CTS_XON_XOFF" flow-control mode, and now rejects invalid parity/flow-control values instead of silently falling back to defaults. Option values are case-insensitive and accept "-" or "_" as separator (canonical forms: none, odd, even, mark, space; none, rts-cts, xon-xoff). - Acquiring a shared Java serial port ("reuse-port") with a configuration differing from the first connection's now fails with an error instead of silently reusing the first configuration. - The 'plc4x' proxy driver now defaults to the TLS transport instead of plaintext TCP. Existing plaintext connections must switch to an explicit transport prefix (e.g. "plc4x:tcp://..."). When using TLS against a server with a self-signed certificate, set "tls.verify-ssl=false" (or pin the certificate). - The 'plc4x' proxy driver now requires username/password authentication on connect; connecting without credentials, or with invalid ones, is rejected with an ACCESS_DENIED handshake. - The PLC4J-API module however is intentionally held at Java 17 to allow alternate driver implementations to support Java 17. - Updated the signature of the PlcBrowseRequestInterceptor to also accept a queryName, query and item instead of just an item. - The ConnectionStateListener interface was updated to no longer have a connected() and disconnected() method, but use a onConnectionStateChanged method instead that accepts PlcConnectionStateChangedEvent events which have many more state change options beyond a simple connected and disconnected event. - The OPC UA driver's "security-policy" now defaults to Basic256Sha256 instead of NONE. NONE means the channel is neither signed nor encrypted, so anything on the network path can read and alter what is exchanged, and the server is not authenticated at all. A protected channel needs the server's certificate to be known before the channel is opened. The discovery phase that would otherwise fetch it runs unprotected by necessity, and a certificate learned from the peer it is meant to authenticate establishes nothing - so the driver no longer proceeds from discovery onto a channel weaker than the one configured. It used to do exactly that, silently: a connection asking for Basic256Sha256 got a session with neither signing nor encryption and no indication of it. Together this means a connection that names no certificate now fails where it previously came up unprotected. Name one with "server-certificate-file", or a trust store with "tls.trust-store"; or set "discovery=false" if the endpoint needs no discovery; or ask for "security-policy=NONE" to accept an unprotected channel as before. Note that a protected channel also needs a client key pair: supply one with "key-store-file", or the driver generates a throwaway self-signed certificate, which a server that authenticates its clients will not accept. - The OPC UA driver refuses to send a username and password over a channel that neither signs nor encrypts, because the password is then readable by anything on the path and stays useful long after it is read. The new "allow-insecure-credentials" parameter sends them anyway, with a warning. - The OPC UA driver now requires an endpoint to match both the requested security policy and the requested message security mode, and selects the strongest endpoint that matches rather than the weakest. It previously accepted an endpoint matching either one and then chose the lowest security level on offer, so a server publishing a wide-open endpoint beside a protected one was usually reached over the wide-open one. Where two endpoints are equally strong, one whose user token policy protects the token is preferred. - The ctrlX driver no longer trusts the Bosch factory default certificate that ships inside the driver jar, and no longer accepts a certificate for any host regardless of the name it was issued for. It also asks for a TLS context rather than the legacy "SSL" one. That certificate identifies nobody - anything presenting it and its key was trusted - and because it was the only trust anchor, a device carrying a properly issued certificate could not be reached at all. The credentials for the connection travel over that channel. Connections to a device still on its factory certificate will now fail. The new "allow-factory-default-certificate" parameter restores the old behaviour, with a warning; alternatively "server-certificate-file" names a single PEM certificate to trust, or "tls.trust-store" (with "tls.trust-store-password" and "tls.trust-store-type") a key store of them, matching the names used by the OPC UA driver and the TLS transport. "ignore-common-name" is also available if the certificate is trusted but names a different host. - The TLS transport now checks that the server's certificate was issued for the host it connected to. The "ignore-common-name" parameter was declared but never consulted, so this check did not happen at all: with "verify-ssl" on, any certificate from a trusted issuer was accepted for any host, which is what a machine in the middle needs. Setting "ignore-common-name=true" restores the old behaviour and logs a warning saying so. A connection to a device whose certificate names something other than the address it is reached at will now fail where it previously succeeded. Two new parameters make the check usable where a device carries its own certificate: "tls.trust-store" (with "tls.trust-store-password" and "tls.trust-store-type") names the certificates to trust instead of the public authorities the JVM ships with. Previously the only way past a private CA was "verify-ssl=false", which turns off both the chain check and this one. - The IEC 60870-5-104 driver now derives its S-format acknowledgements from the send sequence number of the frames it received, counted modulo 2^15 and encoded in the upper fifteen bits of the control field, as the standard requires. It previously sent the received frame's receive sequence number plus one, which is the station reporting how much of our traffic it had taken in - a different number, and one that said nothing about how far we had read. This changes what the driver puts on the wire in response to received telemetry, so a station that checks acknowledgements will see different (correct) values, and one that had adapted to the old behaviour may need attention. The frame format itself is unchanged. - Tag addresses naming an implausible number of elements are now rejected as invalid addresses rather than acted on. An element count is a request to allocate, and it was taken at face value: in the s7 driver a count is now measured against the 2097151 bytes an S7 address can reach (for the string forms, against what one string of the declared length costs, which is the same arithmetic the optimizer does in an int and where an unbounded count overflowed); in the ads driver an index group, index offset and element count must each fit the four bytes ADS carries them in; in the firmata driver a digital tag must stay within the 256 pins the protocol can name, having previously turned its count into that many set bits at parse time. In all three, a count too wide to be a number used to escape as a NumberFormatException instead of the PlcInvalidTagException the tag parsers promise. - The OPC UA driver bounds a browse, which previously walked whatever tree the server described for as long as it described one. "browse-max-references-per-node" (default 65536) limits the references collected for one node and is now also asked of the server, "browse-max-total-nodes" (default 1000000) limits how many nodes one browse expands, and "browse-max-depth" (default 64) limits how deep it recurses. Set any of them to 0 for no limit. Reaching one warns and returns what was found rather than failing, so an address space within these sizes is unaffected. - The ctrlX driver bounds a browse the same way, with "browse-max-total-nodes" (default 1000000) and "browse-max-depth" (default 64). Its browse also now always completes its future: a node answering with no child list used to throw inside the executor's task, where nothing caught it and the caller was left waiting on a future that was never completed. Such a node is now read as the leaf it says it is. - The simulated driver bounds how much data one tag may ask it to make up. The count in the address was multiplied by the size of one element in an int to size the array it fills, so a large enough count asked for a negative array rather than a large one, and anything below that got what it asked for - three hundred million doubles being 2.4 GB. The product is now measured against a budget of 16 MiB per tag. The Go driver carries that count as a uint16, where a count above it used to be truncated to its low two bytes rather than refused - a request for 70000 elements handing back a tag of 4464, and one for 65536 handing back a tag of none. Both are now invalid addresses, as is a count of zero, which the Java driver already refused. - The modbus, profinet and profinet-ng tag parsers now report a count, address or slot too wide to be a number as an invalid tag. All three already bounded these values, but the checks ran after the number was read, so anything too wide to read left as a NumberFormatException instead. The digit widths are capped in the address patterns, at what each field can hold. - Every generated parser now refuses a message that nests its types deeper than 1024 levels, in both the Java and the Go bindings. Several types contain themselves - BACnet constructed data holds further constructed data, an OPC UA variant of type 24 holds further variants - so the depth of the value tree is the sender's to choose and one level costs a single byte on the wire. Deep enough, that ran the parser out of stack: in Java a StackOverflowError, which is neither a parse failure the driver can report nor an error the receive path contains, so a frame that should have cost one frame ended the connection; in Go a goroutine out of stack takes the process with it rather than the request. Set PLC4X_MAX_NESTING_DEPTH for a device whose messages genuinely nest deeper - it means the same thing in both bindings, and a value that is not a positive number leaves the default in place with a warning. The deepest message in the project's own testsuites nests 36 levels, so this bounds only what no real device sends. Note for Go consumers that the default rose from 255 to 1024 in the process, so one setting of the variable now means one depth whichever binding reads it. - plc4go now requires Go 1.27. The uuid package it used to take from github.com/google/uuid now comes from the standard library, which drops that dependency outright - it is gone from go.mod and go.sum - at the cost of the version floor. - EtherNet/IP: Two CIP data type codes were wrong and are corrected. LWORD moves from 0x00D3 to 0x00D4 and STRINGI from 0x00DD to 0x00DE. Each had been sharing its value with another type (DWORD and ENGUNIT respectively), and a duplicate key is silently dropped from the generated lookup tables, so LWORD and STRINGI could not be resolved by name or by value at all. Anyone who hardcoded the old LWORD value was addressing a DWORD. - EtherNet/IP: A string write now emits the structure the read path parses - a 2-byte structure handle, a 4-byte length and then the characters - so what the driver writes reads back as the same value. Previously it wrote a bare length followed by the characters, which no read could decode. The length is now the number of UTF-8 bytes rather than of characters; the two differ for any non-ASCII text, which used to read back truncated. Text that does not fit the type's fixed payload is reported instead of overflowing. Because CIPDataTypeCode.STRING declares a size of 0, the serializer emits no payload for it at all, so a write addressed as ":STRING" is now rejected rather than silently sent empty - write strings as ":STRUCTURED". - Go: Several values now serialize under their own names and in their canonical forms, which changes the output anything parsing it will see. PlcDWORD, PlcSINT, PlcULINT and PlcWSTRING were serialized as PlcDINT, PlcINT, PlcUINT and PlcSTRING; PlcTIME and PlcLTIME render ISO-8601 with hours/minutes/seconds and a sub-second fraction instead of truncating to whole seconds; PlcDATE_AND_TIME renders the UTC wall time in ISO-8601 rather than Go's local-zone default; and PlcStruct keeps a deterministic member order. String-ish values now carry encoding="UTF-8". - Java: The unsigned bit-string values WORD, DWORD and LWORD now serialize as dataType="uint" rather than through the signed writers, PlcBYTE serializes as a bit string, and PlcTIME renders as an ISO-8601 string like PlcLTIME. This aligns the Java and Go renderings of the same value. - EtherNet/IP: EipTag is now immutable, matching every other driver's tag in both bindings - it was the only tag class in plc4j that exposed setters. setType(...) and setElementNb(...) are gone; give the type and the element count to the constructor instead. An element count below one is normalised to one rather than kept, so a tag built as ":INT:0", or through the (tag, type) constructor which used to leave the count at zero, now reads one element instead of none. - All Java drivers now select array elements with one shared notation, written before the data type: `[n]` for a single element, `[lo..hi]` for an inclusive range, an optional `;base` for an array the PLC declares as starting somewhere other than zero, and one bracket per dimension. The dimensions of one array may also be written comma-separated inside a single bracket - `[1..2,3..4]` is the same as `[1..2][3..4]` - which is the form Allen-Bradley and others use; addresses are always rendered back in the one-bracket-per-dimension form. See the "Addressing arrays" page. This replaces four incompatible spellings. `[4]` meant "four elements" in seven tag classes and "the fifth element" in two; it now means one element everywhere, and a count is written as a range. Addresses in the old form no longer parse, and the error names the address to write instead - so an upgrade reports the change rather than quietly returning different data. The affected forms, by driver: S7 %DB42:28.0:BYTE[4] -> %DB42:28.0[0..3]:BYTE S7 (string) %DB1:0:STRING(20)[4] -> %DB1:0[0..3]:STRING(20) Modbus holding-register:1:INT[4] -> holding-register:1[0..3]:INT SLMP D100:INT[4] -> D100[0..3]:INT ADS (direct) 0x4020/0:DINT[4] -> 0x4020/0[0..3]:DINT EtherNet/IP myArray[0]:DINT:4 -> myArray[0..3]:DINT Profinet tag:INT[4] -> tag[0..3]:INT Profinet-NG 1.2.INPUT.0:INT[4] -> 1.2.INPUT.0[0..3]:INT Simulated RANDOM/foo:INT[4] -> RANDOM/foo[0..3]:INT OPC-UA addresses are unchanged - its implementation is the one the shared notation was extracted from - and ADS and UMAS symbolic addresses keep their existing form while gaining ranges. - Firmata is the one driver whose addresses change meaning silently. They carry no data type (`3[4]`), so the brackets did not move and there is nothing to reject: `3[4]` used to read four pins starting at pin 3 and now reads one pin, the fifth. Rewrite these as `3[0..3]`. - An address that selects nothing now asks for the whole value rather than a single element. For a scalar that is unchanged; for an array it is every element, on the drivers that can determine the extent from the device (OPC-UA, ADS, UMAS). The others read one element as before, because their addresses are memory offsets with no declared array at them. - A single index and a one-element range are no longer the same thing. `myTag[4]` selects one element and yields a scalar, while `myTag[4..4]` yields a list of one. `PlcTag.getArrayInfo()` reports the shape of the value received - empty for a scalar, one entry per dimension for an array - so a consumer can tell the two apart without knowing the protocol. - `ArrayInfo` gains `getBase()` and `isRange()`, both as default methods, so existing implementations keep compiling. Its javadoc described `[6]` as a six-element array, which was never what the drivers did and is not what the notation means. - EtherNet/IP rejects an array index above 255 while parsing the address; a CIP MemberID carries a `uint 8`. A range may run past it, since the request carries a start and a count, but it cannot begin there. - ADS and UMAS verify a `;base` written in the address against the bounds the device declares, and report a disagreement. The device is authoritative; a base that differs means the address was written against a different layout, which would otherwise read silently shifted data. - ADS rejects an address that names a member of an array without saying which element - `MAIN.g_arr.member` on an array `g_arr`. It previously resolved against the first element and reported the result as though it were the whole path. - Selecting array elements over UMAS is reported as UNSUPPORTED rather than returning the whole variable. The driver has no per-element arithmetic yet; the address parses, and the refusal is explicit. - Fixed `getArrayInfo()` reporting one element too many on the ADS direct and Firmata drivers, whose inclusive bounds were built from the element count rather than the last index. - Fixed a direct ADS array selection transferring every element it asked for and decoding only the first, in both PLC4J and PLC4Go. The size of the request was multiplied by the element count while the decoder was given no shape, so `0x4020/0[0..3]:DINT` returned one value for four elements' worth of bytes - a well-formed answer to a question nobody asked. - Fixed a symbolic ADS selection being ignored in PLC4Go. `MAIN.arr[1..4]` resolved like `MAIN.arr`: the whole array, from its original offset. The selection now moves the read to the first selected element and transfers only what it spans, across as many dimensions as the address names (`MAIN.grid[3,1..3]`), and a selection outside what the device declares is refused rather than approximated. - Fixed the shape of a partly selected multi-dimensional ADS array in PLC4J. `MAIN.grid[1..2]` on an `ARRAY [0..9,0..4]` reported two elements rather than two rows of five: the dimensions the selection did not name were dropped from the shape while their bytes were still transferred. They are selected whole, and are part of the value. - A dimension of an ADS selection written as a bare index now collapses, where before every named dimension added a level of list. `grid[3,1..3]` is a list of three, not a list of one list of three, and `grid[3,2]` is a scalar. This is the same rule the notation states for a single dimension. - Fixed SLMP reporting a one-element range as a scalar in PLC4J. `D100[4..4]` now returns a list of one, as `D100[4]` returns a scalar and as PLC4Go's SLMP driver already did. Its shape came from the element count, which cannot express the difference. - PLC4Go now uses the same array notation as PLC4J, so one address means one thing in either language. The grammar, the rules and the rendering are the ones described above; the two share a specification rather than code, and the Go parser is tested against the Java cases directly. The forms that changed, by driver: S7 %M100:INT[10] -> %M100[0..9]:INT S7 (string) %DB69.DBX68:WSTRING[3] -> %DB69.DBX68[0..2]:WSTRING Modbus holding-register:1:INT[4] -> holding-register:1[0..3]:INT SLMP D100:INT[4] -> D100[0..3]:INT EtherNet/IP %rate:DINT:4 -> %rate[0..3]:DINT Simulated RANDOM/foo:INT[4] -> RANDOM/foo[0..3]:INT KNXnet/IP 1.2.3#4B1C:UINT[4] -> 1.2.3#4B1C[0..3]:UINT KNXnet/IP 1.2.3#11/1/1[4] -> 1.2.3#11/1/1[0..3] Addresses in the old form no longer parse, and the error names the address to write instead - with two exceptions, below, where the address parses either way and only its meaning moves. - Two Go drivers change the meaning of addresses that still parse, so there is nothing to reject and nothing to warn about at runtime: * ADS `[n]` was a *count* of n elements and is now the element at index n. `MAIN.g_arr[3]` read three elements and now reads one. Rewrite as `MAIN.g_arr[0..2]`. This also means Go and Java ADS now agree about the same address; they did not before. * Firmata `[n]` was a run of n pins and is now the pin at index n, exactly as in PLC4J. `digital:2[3]` read three pins from pin 2 and now reads pin 5. Rewrite as `digital:2[0..2]`. - ADS also drops the `[a:b]` start-and-count form, which had no counterpart in PLC4J. `MAIN.g_arr[2:4]` is written `MAIN.g_arr[2..5]`. - A count of zero no longer has a spelling. Several Go drivers accepted `[0]` and rejected it as "quantity must be greater than zero"; a range is written with the indices it covers, so there is no way to ask for none, and `[0]` now selects the first element. - `ArrayInfo` bounds are inclusive in PLC4Go, as they are in PLC4J: `GetSize()` returns `UpperBound - LowerBound + 1`. They were exclusive, documented as a deliberate divergence, so `[0..7]` reported eight elements in Java and seven in Go - the same disagreement about the same address that this change exists to remove. Code reading `GetUpperBound()` directly must be revisited. - `ArrayInfo` gains `GetBase()` and `IsRange()`. Go has no default methods, so any implementation outside PLC4Go must add them. - Addresses that a driver rendered back are now spelled the way its parser reads them. Several never round-tripped: BACnet/IP rendered `:` where the syntax wants `,`, gave every property a leading `:`, and printed the address of the pointer holding an array index rather than the index; KNXnet/IP device addresses rendered `/` where the syntax wants `.`; the ADS direct form printed its index group as decimal digits behind an `0x` prefix, so 16416 came back as `0x16416` - a different address; and the S7 tag rendered as "0:INT[8]", naming neither the memory area nor the offset it read. - Fixed the Go BACnet/IP driver asking for one element fewer than requested when a read carried an element count, which followed from the bounds becoming inclusive. - C-Bus addresses are unchanged. Its brackets carry the arguments of a CAL command (`recall=[param, count]`), not a selection appended to an address. - KNXnet/IP group addresses are unchanged. Their brackets hold a set of group addresses to match (`[1-3,5]`), not an array selection. Only the two device address forms, which carry a real element count, moved to the new notation. - BACnet/IP addresses are unchanged. Its bracket is a property array index, which already meant what the notation says an index means. - A connection reports the operations its driver actually implements. ConnectionBase answered "true" to isReadSupported(), isWriteSupported(), isSubscribeSupported() and isBrowseSupported() for every driver built on it, whatever that driver implemented, so the metadata a tool uses to decide what to offer was not worth reading. In PLC4Go the EtherNet/IP and Modbus connections left ProvidesSubscribing and ProvidesBrowsing at their zero value, reporting "false" by accident rather than by decision. Both now state what they support, so code branching on these flags will see different - and correct - answers. - S7: The day-of-week nibble of a DATE_AND_TIME is numbered the way an S7 numbers it, counting from Sunday as 1 to Saturday as 7. Both bindings filled it from their date library, which counts from Monday, so every DATE_AND_TIME written to a PLC carried a day of week one short. Parsing rotates back, so the value still round-trips through PlcDATE_AND_TIME, whose getter keeps the ISO-8601 numbering that KNX DPT 19.001 needs. Only IEC61131_DATE_AND_TIME is affected; the DTL variant already carried the Siemens numbering. - Go: PlcDATE_AND_TIME's GetDayOfWeek() returns the numbering PLC4J returns - 1 for Monday through 7 for Sunday - rather than Go's time.Weekday, which counts Sunday as 0. A zero there means "no day given" in KNX DPT 19.001 and is simply invalid for S7. - Go: A request that runs out of time is reported as a timeout rather than as an INTERNAL_ERROR. This covers both the driver's own request timeout and a deadline the caller set on the context it passed in - the idiomatic way to call this - so code telling a timeout from a real failure to know whether retrying makes sense will now see the timeout it was looking for. Changed Maven Coordinates ------------------------- The Maven groupId of all modules is unchanged ("org.apache.plc4x"). The following artifactIds changed; consumers must update their dependency coordinates accordingly: - The "tools" modules were renamed to the "plc4j-tools-*" pattern: plc4j-capture-replay -> plc4j-tools-capture-replay plc4j-connection-cache -> plc4j-tools-connection-cache plc4j-opm -> plc4j-tools-opm - The transport modules were renamed from the singular "plc4j-transport-*" to the plural "plc4j-transports-*": plc4j-transport-can -> plc4j-transports-can plc4j-transport-pcap-replay -> plc4j-transports-pcap-replay plc4j-transport-raw-socket -> plc4j-transports-raw-socket plc4j-transport-serial -> plc4j-transports-serial plc4j-transport-tcp -> plc4j-transports-tcp plc4j-transport-test -> plc4j-transports-test plc4j-transport-udp -> plc4j-transports-udp plc4j-transport-socketcan -> plc4j-transports-can-socketcan plc4j-transport-virtualcan -> plc4j-transports-can-virtualcan - The scraper was replaced by the new event-pump component: plc4j-scraper -> plc4j-tools-event-pump - Removed modules (no direct replacement): plc4j-scraper-ng (experimental, dropped) plc4j-transport-pcap-shared (obsolete) Note: this release also adds a number of new SPI3 modules (e.g. the "plc4j-spi-*" buffers/config/drivers/values split, the new "plc4j-transports-api"/"-cotp"/"-tls" transports, the "plc4j-utils-audit-log*" and "plc4j-utils-subscription-emulation" utilities). These are new artifacts, not renames. Bug Fixes --------- - Fixed the Java S7 driver's tags reporting no address at all: "getAddressString()" returned null, so anything carrying a tag as a string - a log line, a browse result, a serialized request - got nothing from an S7 tag. It now spells the address the way the parser reads it back, including the declared length of a fixed-length string and the counter number of a COUNTER address, which is stored split across the byte and bit offsets. - The Open Protocol driver's tag class now reports that it has no tag addressing yet instead of returning null. "OpenProtocolTag.of()" handed a null tag to callers of "prepareTag()", so the failure surfaced later as a NullPointerException; it now throws PlcInvalidTagException, matching the driver's tag handler, which already rejected every address. - Fixed the Go S7 driver reading a fixed-length string from the wrong data block. The long-form address ("%DB69.DBX68:STRING(10)") built its tag with a hard-coded block number of zero, so it read DB0 and reported the result as though it had come from DB69. The short form ("%DB69:68:STRING(10)") and every non-string address were unaffected, as is PLC4J, which parses the block number for all of them. - Fixed serialization in the 'plc4x' proxy driver's message codec, which did not configure the buffer integer/string encodings under SPI3 and failed to serialize any message. - OPC-UA: Fixed several issues: a hang during discovery / encrypted-policy negotiation, a divide-by-zero when the server provided no certificate, and hardened parsing of corrupt or malicious responses that could previously cause an OutOfMemoryError. - ADS: The connect handshake now honors the configured AMS ports instead of hardcoding RUNTIME_SYSTEM_01/851. - ADS: Fixed an invalid size calculation in AdsDataTypeArrayInfo. - ADS: Fixed serialization of STRING/WSTRING values. - S7: Fixed duplicate TSAP information at the COTP and S7 level. - Connection-cache: Fixed a deadlock when obtaining a connection, plus a race condition and idle-timer/cleanup issues. - The base driver now redacts password information from console logs. - TCP transport: Close the SocketChannel on a failed bind / socket-option setup. - Request objects were made more null-safe (#2280). - OPC-UA: All consumers registered on a shared subscription now receive notifications (previously only one consumer was registered). - AB-ETH: Fixed reading a tag after the SPI3 refactoring. - The socket is now disconnected when the handshake fails instead of being left hanging (#2290). - Go Modbus: Hardened frame parsing against truncated/extended frames, trailing CRCs from misbehaving gateways and TCP keep-alive padding, with stream resynchronization on desync. - Go: Numerous stability and resource-leak fixes (connection cache no longer hands out dead connections, goroutine and codec-worker leaks on Modbus reconnect, robust Modbus receive with desync/resync, TCP/UDP transport deadline and reset races, codec disconnect deadlock). - Go: Generated code ignored the string encoding declared in the mspec and read and wrote every string as UTF-8. A WSTRING, which ADS declares as UTF-16LE, stopped at the first NUL byte, so "wolf" decoded as "w". The generated code now carries the real encodings (UTF-16LE, UTF-16BE, ASCII, ISO-8859-1, Windows-1252), and the byte-based write buffer passes the single-byte encodings through instead of zero-filling anything it did not recognise. Reading a string likewise honors the requested encoding, decoding UTF-16 per code unit rather than per byte. - Java: The XML buffer could not read back everything its own writer produced. A field discriminating on a typed enum was written under the enum's name but read under the field's, and a text node larger than the parser's chunk size - the ADS symbol and data-type tables run to 70-80k characters - failed with "Expected end element" because the reader was not coalescing. - ADS (Go): Several fixes. The connection accepts the same kebab-case parameters as the Java driver (source-ams-net-id and friends), and a missing targetAmsNetId is now reported as such rather than as sourceAmsNetId. The device-info request uses the configured AMS ports instead of a hardcoded 851/800. Multi-tag subscriptions run in request order rather than in map order, honor the requested interval as the notification cycle time, and no longer panic when a data type is missing from the table. The data type table is keyed by the name symbols actually reference. - ADS (Go): Direct-address reads and writes all failed with "invalid tag item type" - the request paths expected a pointer where the tag handler produced a value - and never filled in the tag's data type. Hex address parts with an odd number of digits (0x8) were rejected, though the Java driver accepts them. - EtherNet/IP: A reply carrying fewer bytes than a single-element tag declares no longer throws out of the response handler; it is reported as INTERNAL_ERROR for that tag, which is what a truncated multi-element reply already did. - Modbus (Java): Several fixes to the read optimizer. The unit-id was dropped while a request was being optimized, so an optimized read went out with the default unit-id instead of the one the tag named (#2686); a read of coils returned only the first value (#2060); a non-BOOL tag pointed at coils is reported instead of being misread; and the trailing register pad was sized from a string length of one, so an odd number of STRING or WSTRING values picked up a pad byte the registers did not need. - EtherNet/IP: Fixed reading arrays, which generally did not work (#1008). A response is no longer handed to a request it does not belong to, and a tag address that cannot be parsed is reported for that tag rather than failing the request. - Tag addresses that cannot be parsed are reported per tag in the EtherNet/IP, Modbus, OPC UA, S7 and simulated drivers, as the API promises. One unparseable address used to fail the whole request, including the tags that were fine. - S7: A controller refusing a request because PUT/GET communication is disabled is reported as ACCESS_DENIED. Only two of the three header forms were mapped, so the 0x83/0x04 an S7-300 sends read as INTERNAL_ERROR and a refused write could not be told from a failed one (GH-599). Also fixed an asymmetry between the tags a request accepts and the tags it hands back (#2388), and a timestamp for the year 2000, which parsed but could not be serialized again. - SPI: A request waiting for a permit no longer blocks the thread it was submitted on. A driver chaining requests runs the follow-up on whichever thread completed the previous one, typically the connection's receive thread, which then parked waiting for a permit that only it could have freed - the connection recovered when an unrelated request timed out. Negotiated max-amq is often 1 to 3 on an S7-300, which makes this easy to reach. Requests are queued and started in submission order as permits free up. - SPI: An unchecked exception out of a generated parser is reported as the parse failure it is instead of ending the thread that owns the channel, which left the transport claiming to be open with nobody reading it. - A message that stops short is refused rather than half-believed, in both the Java and the Go bindings: a manual array whose reader cannot make progress ends instead of looping (a firmata sysex message ending mid-string was an endless supply of items), an optional field the message announces has to actually be present, a BACnet tag header length is derived only from fields that were read, an S7 payload is read only when its parameter was, and the cast of a parsed complex field is checked. plc4c and plc4py carry the same nesting-depth bound as Java and Go. - OPC-UA: The self-signed certificate the driver generates when no key store is configured - the one most servers see on a first connect - is now one a modern server accepts: signed with SHA-256 rather than SHA1withRSA, a positive serial of sixteen octets rather than forty random bytes, marked as an end entity rather than as a certificate authority, and carrying a subject key identifier. - OPC-UA: The client identity is the first key store entry that holds a private key, not whatever alias comes first. The tutorial's own set-up has "ca" sorting before "client", so the driver could hand the server the CA entry, or carry on with a null private key; the server just closed the connection. A store with no private key, an entry that cannot be read (which is what a wrong key-store password looks like) and a non-RSA key each now fail naming the entry and the reason. - OPC-UA: The certificate chain is sent in the asymmetric security header, not the client certificate alone, so a server that trusts the issuing CA rather than the certificate itself can build a path to its trust anchor. The thumbprint still covers the client certificate, as the specification requires. - OPC-UA: A username token is encrypted with the algorithm the server's user token policy names, instead of always RSA-OAEP, so username and password authentication works against a server asking for RSA-PKCS1.5 (#2154). - OPC-UA: A subscription hands out one PlcSubscriptionHandle rather than an identical one per tag (#1896) - corrected for every driver that supports subscriptions - and tags registered with addCyclicField(...) produce events again, through the same cyclic-subscription emulation the other drivers use, since OPC UA itself has no cyclic subscriptions (#1102). - OPC-UA: The stream a key store is read from is closed, as is the reader a BACnet EDE file is parsed from. - ADS: With "load-symbol-and-data-type-tables=false" a symbolic address is refused with a message saying the tables were not loaded, rather than failing as an unknown symbol or, when browsing, as nothing at all. Reading and writing are limited to direct addresses in that mode; subscriptions are unaffected, since they resolve symbol handles on the device (#1626). - OPM: The PlcEntityManager caches the proxy classes it generates rather than generating a new one on every connect, which used to grow the metaspace of an application connecting repeatedly (#1935), and List and array fields are mapped instead of mishandled (#1947). - NiFi: The connection-string validator closes the connection it opens to test the string. NiFi validates on every configuration change and while the dialog is open, so each round left a connection behind - for OPC UA a secure channel and a session the device holds until they time out, which on hardware with a small connection limit locks everyone else out. It also catches an unchecked rejection, which is how some drivers report a bad connection string. - KNXnet/IP: A browse answers the query it was asked rather than every query in the request, and reading a knxproj cleans up what it unpacked. - Go: A future publishes its error before the flag that releases whoever is waiting on it, a blocking subscription consumer no longer wedges the poller for everyone else, the codec survives a reconnect and a late expectation, and the KNXnet/IP discoverer no longer leaks a goroutine and a socket per discovery. ============================================================== Apache PLC4X 0.13.1 ============================================================== New Features ------------ - Extended the PlcRawByteArray to provide access to a List of USINT objects. Incompatible changes -------------------- Bug Fixes --------- - When reading an array of bits, the old s7 driver seems to hang. - The s7 driver causes issues when writing arrays of bits. - The block optimizer used in s7-light causes errors, if a tag references the same byte multiple times. - When using the new block-optimizer in the s7-light driver, when reading multiple BOOL values located in the same byte produces errors ============================================================== Apache PLC4X 0.13.0 ============================================================== New Features ------------ - The CachedPlcConnectionManager now has a maxIdleTimeout time which defaults to 5 minutes. If a connection is not being used for that amount of time, the connection is closed and removed from the cache. - The CachedPlcConnectionManager now has a close method, which shuts down all connections. - The CachedPlcConnection now implements the EventPlcConnection interface which forwards listener registrations to the connection. - The S7 driver is now able to automatically split up large array requests into multiple ones and transparently merge them back together. It is now possible to read arrays of almost unlimited size. - Added an Optimizer to the Modbus driver, that improves read performance of multi-item read requests by more than 10 times. - Added an optimizer to the Modbus protocol, that allows reading multiple fields in one request. - Added support for Modbus encodings of BIG_ENDIAN_WORD_SWAP and LITTLE_ENDIAN_WORD_SWAP. - Modbus tags allow specifying the unit-id in order to address multiple devices using one serial modbus connection. - Added a new optimizer to the S7 protocol, that ready chunks of data instead of individual fields, which allows reading a lot more fields in one request. - Added a new variant of the S7 driver, called s7-light, which doesn't have support for subscriptions, but is less likely to cause connection problems. - Added auto-discovery to the KNX Driver in PLC4J. - Added auto-discovery to EIP in PLC4J. - Added auto-discovery to S7 in PLC4J. - Improved some things in the SPI, that caused issues with drivers under heavy load. - The Modbus driver uses the "Single Register Request" if a tag fits into one register. This can help communicating with devices that don't support "Multi Register Requests". Incompatible changes -------------------- - When reading byte arrays with the s7 driver, now the more efficient PlcRawByteArray type is used, that gives users direct access to the bytes returned from the PLC instead of a list of PlcValues. - The builders for read-, write- ans subscription.requests now process tags and values on a per-field level. If one field has an invalid address it will now only fail the one item related to that. Same applies to values. Only the tag who's value was invalid will be considered failed and no longer an exception should be thrown. - Subscription-requests now allow registering a handler for all fields in the subscription. - The addPreRegisteredConsumer method was removed and versions of the "addXYZ" methods were added, that allow providing individual consumers for each tag. Bug Fixes --------- ============================================================== Apache PLC4X 0.12.0 ============================================================== New Features ------------ - API: Made several bits of information available via the API allowing tools to provide more content assist when dealing with PLC4X connections. - S7: The S7 driver now supports reading of STRING and WSTRING data-types without providing a maximum length. - Build: Worked on making PLC4X provide reproducible builds. - Added "Ping" functionality to: ADS, EIP, KNX, Mock, Modbus and Simulated drivers. - The OPC-UA Java driver now support certificate-based authentication and encryption. Incompatible changes -------------------- - Java 8 is no longer officially supported and Java 11 is the new base-line. - Renamed the PlcDriverManager method `listDrivers` to `getProtocolCodes` - Renamed the PlcDriverMetadata method `canDiscover` to `isDiscoverySupported` - Renamed the PlcConnectionMetadata methods `canRead`, `canWrite` `canSubscribe` and `canBrowse` to `isReadSupported`, `isWriteSupported`, `isSubscribeSupported` and `isBrowseSupported` - The configuration syntax for configuring transport-related config options in the connection-string was updated to be now prefixed with the transport name the option belongs to. Bug Fixes --------- - S7: Several bugs and issues regarding supporting various duration, date and time data-types. - S7: Implemented the missing 64bit (L-) types. - KNX: Fixed an issue with decoding 16 bit floating point numbers. - NiFi-Integration: The NiFi integration module was greatly improved. - Core: Fixed several leaks of open threads. ============================================================== Apache PLC4X 0.11.0 ============================================================== New Features ------------ - IEC-60870-5-104 driver - Completely rewritten EIP driver that should now support Allen-Bradley controllers - Completely rewritten the ADS driver that now supports Auto-Discovery, Browse, UDOs and auto-configuration of remote AMS routes - Support for S7 200 subscriptions - Added a docker-compose setup in a preparation for reproducible builds - Added SBOM generation - Improved Apache NiFi support - Added support for the latest ETS version in KNX - Started implementing the ping() method for some drivers - Greatly updated Apache NiFi integration Incompatible changes -------------------- - Java 1.8 is no longer supported and Java 11 is now the new baseline version we support. - We've updated the APIs of both PLC4J and PLC4Go to be more in sync. We also refined some of the terminology. - We've also re-written the `connection-cache`, which now replaces both the old `connection-pool` and the old `connection-cache`. - The UI module has been removed as it relied on JavaFX, which is no longer bundled with the JDK and therefore the LGPL license renders is dad for Apache projects. - The Apache Camel integration was moved over to the Apache Camel project. - The prototype-driver for PROFINET was completely updated - Due to the extreme refactoring of S7, ADS and EIP, the Go versions of these drivers are currently not going to work as well as before (We're going to address these issues in the next phase after the release) - Changed the return type of the PLC4J Ping method to return more information on if the ping was successful Bug Fixes --------- Fixed issues with memory leaks in the ConnectionManager Fixed multiple issues reported for the handling of data-types in S7, Modbus and ADS protocols when reading and writing. ============================================================== Apache PLC4X 0.10.0 ============================================================== A lot of the work in this version went into refactoring and cleaning up our code generation. The code generation itself is now a lot cleaner and simpler as well as the code generated for Java. We also added a number of new field-types to allow implementing more sophisticated protocols. PLC4C now should also support all of the constructs mspec has to offer. New Features ------------ - Implemented a `PLC4X-Server` and `PLC4X-Driver` that allows using the server as a proxy for communicating with PLCs. - The Modbus driver is now also available in the variants: "modbus-rtu" and "modbus-ascii" (Both using Serial communication, which however can be tunneled through a "tcp" and "udp" transport) - The KNX driver in Java now supports reading "knxproj" files exported from the new ETS version 6. Incompatible changes -------------------- - The name of the Modbus TCP driver was changed from "modbus" to "modbus-tcp". - Removed the Apache Edgent (incubating) integration and examples related, as Edgent is abandoned and there were CVEs reported, which will not be fixed. - We have replaced the BitString types with BYTE, WORD, DWORD, and LWORD which generally match their unsigned integer counterparts. So we are no longer returning lists of boolean values for any of these types. Bug Fixes --------- - Fixed a big bug in the KNX Datapoint decoding, which caused byte-aligned data types to parse with an offset of 8 bit. (This bug affected both the Java and the Go driver) ============================================================== Apache PLC4X 0.9.0 ============================================================== New Features ------------ - The OPC UA driver has been replaced with a native driver. Previously Eclipse Milo was being used. - Permit customized package names for code generation - Added an initial draft of a Discover and Browse API to PLC4J - PLC4Go now supports many more drivers - PLC4Go received a huge internal refactoring and cleanup - Major cleanup of PLC4C - S7 Driver now supports event and alarm handling on some S7 models Incompatible changes -------------------- Bug Fixes --------- PLC4X-200 OPC-UA Driver not connecting if params string is not provided PLC4X-201 OPC-UA PlcList underlying type not compatible with Eclipse Milo PLC4X-202 OPC-UA Driver cannot write Unsigned Types PLC4X-276 [S7] The most of the supported types don't work correctly PLC4X-278 Double Reading Error PLC4X-279 nioEventLoopGroup thread proliferation PLC4X-280 ADS route request swapped positions of route name and address PLC4X-291 DefaultPlcSubscriptionField cannot be cast to class OpcuaField PLC4X-298 [S7] When writing REAL values the Write operation fails with an internal error PLC4X-299 Modbus - Kafka Connect Configuration PLC4X-312 CAN NOT READ STRING FROM S7 PLC PLC4X-314 CAN NOT WRITING MANY DATA TO S7 ONE TIME ============================================================== Apache PLC4X 0.8.0 ============================================================== This is an ordinary PLC4X release, containing changes that accumulated over time. It doesn't have an explicit focus on a particular topic. New Features ------------ - The KNXnet/IP Driver now supports writing of values. - The Modbus driver now supports more common notations of Modbus addresses using a pure-numeric notation. - The ADS, KNX, Modbus, S7 and simulated drivers have been updated to support the IEC 61131-3 data-types. - We are now including PLC4Go as PLC4X implementation in the programming language Go(lang) - Integration with the Milo OPC UA Server is now available. - Kafka Connect workers have been updated source and sink connectors are now included. Incompatible changes -------------------- - The syntax of the S7 addresses changed slightly allowing to provide a string length. Without this, a STRING datatype will read 254 characters, by adding the size in round brackets to the type name will use the specified number. Examples: Read one String which is max 10 chars long: %DB2:30:STRING(10) Read an array of 3 Strings where each is max 10 chars long: %DB2:30:STRING(10)[3] - The PLCValue types have been refactored to align with the types defined in IEC 61131-3 (https://en.wikipedia.org/wiki/IEC_61131-3) directly using the older Java types (PlcBoolean) is no longer possible. Bug Fixes --------- A lot of testing was done regarding the IEC 61131-3 data-types. This resulted in numerous bugfixes in many protocols. PLC4X-132 [S7] Communication to S7 PLC dies in some situations PLC4X-206 When writing short values exceptions are thrown while preparing the write request. PLC4X-207 No registered handler found for message TPKTPacket[], using default decode method - Communication with S7 and Modbus device hangs PLC4X-209 [S7] When writing INT and DINT values the Write operation fails with an internal error PLC4X-210 [KNX] When running a KNX Tunneling Subscription for a longer time there are packets that kill the connection PLC4X-211 PlcValues seem to always return "true" on the isXYZ" checks. PLC4X-212 When writing multiple values in one request the item status is not correctly set PLC4X-213 [Modbus] The Modbus driver doesn't handle error responses gracefully PLC4X-214 [Modbus] Holding register addresses have an offset of 1 (Not reading the correct address) PLC4X-215 Drivers using the BaseOptimizer (SingleFieldOptimizer) don't handle error responses gracefully PLC4X-218 [Scraper] After stopping the scraper still the statistics are logged and the application doesn't terminate PLC4X-239 Read DTL (Date and Time) PLC4X-240 Protocol error in reading string PLC4X-246 S7 driver hangs on read PLC4X-245 [Modbus] Apache NiFi processor throws java.io.IOException after a while PLC4X-255 Kafka Connector Source Task doesn't block within poll() resulting in high CPU usage. PLC4X-261 Pooled connection manager returns a connection that isn't connected in some situations. PLC4X-272 When splitting up large requests, too big sub-requests are generated (S7) PLC4X-256 ReadBuffer truncate last byte of even small payloads PLC4X-262 Error in reading Array PLC4X-270 Ads driver does not accept double-digit array indexes ============================================================== Apache PLC4X 0.7.0 ============================================================== This version is the first after a major refactoring of the driver core. All previous driver versions are now considered deprecated and have been replaced by versions using the new driver structure and generated driver codebase. New Features ------------ - Drivers now support structured types using PlcValues - The EIP (EtherNet/IP) driver no longer requires an external library and is implemented fully in the PLC4X project - The Modbus driver no longer requires an external library and is implemented fully in the PLC4X project - The new S7 Driver supports writing multiple entries in one request (The API allowed this from the beginning now not every item is wrapped in a single request. It should bring significant performance gains when writing multiple values) - S7 Driver now supports String datatypes. - OSGi : Implementation of Drivers/Transports as OSGi services to be able to use them in an OSGi container. - New Firmata protocol driver Incompatible changes -------------------- - Due to the refactoring of the driver core there might be issues running drivers built against older core versions. - This version doesn't provide a Beckhoff AMS/ADS driver as this driver is still being ported to the new mspec format. - All drivers connection strings now follow the same pattern: {protocol-code:(transport-code:)?//{transport-config}(?{params})? Please check the drivers documentation on our website: https://plc4x.apache.org/users/protocols/s7.html - The karaf-feature modules are removed as the drivers now all provide both a feature.xml as well as a `kar` bundled archive Bug Fixes --------- PLC4X-174 UDP Transport does not accept ports containing 0 PLC4X-134 S7 is terminating the connection during handshake PLC4X-192 Support for conversion of complex connection string parameters ============================================================== Apache PLC4X 0.6.0 ============================================================== This is the last release of PLC4X with the "handwritten" drivers. This Minor release will thus receive updates and fixes until most users have switched to 0.7 and above (with generated drivers). If you are using the S7 Driver you should update to this Version as the critical (memory leak) bug PLC4X-163 is fixed. New Features ------------ - PLC4X-168 A shorter S7 Field Syntax is Introduced. This release contains no further features and mostly stabilization. Incompatible changes -------------------- - Moved the C++, C# and Python drivers into the `sandbox` Bug Fixes --------- - Fixed Promise Chain for InternalPlcWriteRequest - PLC4X-45 Add float support to Modbus Protocol - PLC4X-164 Fix wrong NOT FOUND exception in OPC UA Driver - PLC4X-166 Fixed Download Page - PLC4X-163 Fixed Netty ByteBuf Leaks for S7 Driver - PLC4X-158 Added Warning if no Pooled Driver is used for Scraper ============================================================== Apache PLC4X 0.5.0 ============================================================== This is the first release containing our new generated drivers (AB-ETH) New Features ------------ - Implemented a new Apache Kafka Connect integration module - Implemented a new Apache NiFi integration module - Implemented a new Logstash integration module - Implemented a driver for the AB-ETH protocol - Implemented Apache Karaf features for S7 OSGI drivers - PLC4X-121 Develop Code Generation to allow Generated Drivers in multiple Languages Sandbox (Beta-Features) - Implemented a new BACnet/IP passive mode driver - Implemented a new Serial DF1 driver Incompatible changes -------------------- Bug Fixes --------- - PLC4X-104 S7 Driver Datatype TIME_OF_DAY causes ArrayOutOfBoundException - PLC4X-134 S7 is terminating the connection during handshake - PLC4X-139 PLC4X leaks sockets in case of connection problems - PLC4X-141 String with real length of greater 127 throw an exception - PLC4X-144 When requesting invalid addresses, the DefaultS7MessageProcessor produces errors ============================================================== Apache PLC4X 0.4.0 ============================================================== This is the first release of Apache PLC4X as top-level project. New Features ------------ - The PlcConnection now supports a `ping` method to allow checking if an existing connection is still alive. - Support of the OPC-UA protocol with the `opc-ua-driver`. - Other Languages Support: -- Added first versions of a C# .Net PLC4X API (`plc4net`) -- Added first versions of a Python PLC4X API (`plc4py`) - Added an Interop server which allows to relay requests from other languages to a Java Server Incompatible changes -------------------- - ElasticSearch example was updated to use ElasticSearch 7.0.1, this might cause problems with older Kibana versions. Bug Fixes --------- ============================================================== Apache PLC4X (incubating) 0.3.1 ============================================================== This is a bugfix-release, that fixes some problems with S7 driver. Bug Fixes --------- - The S7 driver didn't correctly handle "fill-bytes" in multi-item read-responses and multi-item write-requests - PLC4X-83: fixed NPE when reading odd-length array of one-byte base types - PLC4X-82: renamed flags "F" to Siemens Standard "M" (Marker) - PLC4X-84: Fixed a bug in the DefaultS7MessageProcessor which didn't correctly merge together split up items ============================================================== Apache PLC4X (incubating) 0.3.0 ============================================================== This is the third official release of Apache PLC4X. Some new features have been added (e.g. plc-scraper) multiple new integrations are included (apache-karaf, apache-calcite) and a lot of (technical) refactoring has been done to prepare future work on adapters in different languages. New Features ------------ - Object PLC Mapping (OPM) now has a Alias Registry to allow variable substitution at runtime and write support - New module `plc-scraper` for applications that have to scrape a lot of sps fields with high frequency - New integration `apache-karaf` to enable plc4j in a karaf runtime environment Incompatible changes -------------------- - The 'plc4j-core' module has been merged into 'plc4j-api'. So there is no 'plc4j-core' module anymore. Just remove that dependency. - The driver artifact names have changed so if you were using a `plc4j-protocol-{name}` you now need to change this to `plc4j-driver-{name}` Bug Fixes --------- PLC4X-75 Fixing dependency to the wrap url-handler PLC4X-76 When receiving responses with more than 512 byte, the IsoOnTcp protocol doesn't work PLC4X-77 When the last item in a request is a DINT, the DefaultS7MessageProcessor dies PLC4X-78 Write operations seem to fail - Fixed a Bug where S7 was not able to read arrays. ============================================================== Apache PLC4X (incubating) 0.2.0 ============================================================== This is the second official release of Apache PLC4X. Especially have we addressed all issues reported during our first release, that were of non-technical nature. These were tracked in: PLC4X-60 Fix findings by the last release New Features ------------ A new connection-pool was added, which allows automatic pooling and reuse of PLC connections. A new OPM module was added, which allows JPA like read- communication using POJOs, very similar to JPA. A stub of a new driver for the Emerson DeltaV protocol has been added, but is not yet a fully functional PLC4X driver. This is also a first test of our new `passive- mode-driver` concept. Incompatible changes -------------------- We have refactored the API in order to eliminate the need of passing `x-requests` to `x-methods` and added an `execute` method to each request type. This greatly simplifies the client code. However this requires refactoring of applications using the direct PLC4X API. Miscellaneous changes --------------------- We have increased the test coverage greatly and fixed a lot of little errors we found on the way. Known Issues ------------ Bug Fixes --------- PLC4X-56 [S7] S7Field does not recognize addresses with numElements present PLC4X-57 [S7] Response for address with numElements contains only first item PLC4X-61 Installation fails plc4j-protocoll-ethernetip needs license PLC4X-62 Modbus results deliver null-Value due to missing implementation of getShort, getLong ... ============================================================== Apache PLC4X (incubating) 0.1.0 ============================================================== This is the first official release of Apache PLC4X. It contains drivers for the following protocols: - Siemens S7comm (0x32) - Beckhoff ADS - Modbus - EtherNet/IP However the Siemens driver definitely is the most mature driver, the rest should be treated experimental. New Features ------------ PLC4X-29 [S7] Implement PDU Fragmentation PLC4X-39 Extend the Edgent integration with the new Subscription features of PLC4X Incompatible changes -------------------- - NONE - Miscellaneous changes --------------------- - NONE - Known Issues ------------ - NONE - Most drivers should be treated experimental and are not near production ready. The S7 driver is probably the furthest implemented and tested driver and hereby can be considered to be the most mature. Bug Fixes --------- PLC4X-20 Jacoco doesn't seem to be working at all PLC4X-21 Code coverage doesn't seem to work PLC4X-47 S7 driver silently ignores surplus ReadRequestItems PLC4X-48 S7 driver fails to parse response with multiple items