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

(plc4x) branch develop updated: feat(plc4go/ads): enable the ADS driver testsuite, align value rendering

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 4de8bf1a45 feat(plc4go/ads): enable the ADS driver testsuite, align value rendering
4de8bf1a45 is described below

commit 4de8bf1a45d950a54e082a6b375b73f0f281a8d8
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Aug 26 17:47:35 2026 +0200

    feat(plc4go/ads): enable the ADS driver testsuite, align value rendering
    
    TestAdsDriver was skipped since the symbol-table commands were ported;
    the port is long done, but the driver, the Go testsuite runner, and the
    cross-language value rendering had all drifted. With this the shared
    protocols/ads DriverTestsuite.xml passes STRICTLY in both plc4j
    (AdsDriverIT, auto-migrate now off) and plc4go (t.Skip removed).
    
    ADS driver (Go):
    - accept the plc4j kebab-case connection parameters (source-ams-net-id,
      ...) as aliases of the camelCase ones, and fix the copy-paste check
      that reported a missing targetAmsNetId as sourceAmsNetId
    - implement SetAwaitSetupComplete/SetAwaitDisconnectComplete so the
      testsuite runner can feed the connect handshake itself (S7 pattern);
      clear() no longer wipes those configuration flags
    - the device-info request uses the configured AMS ports instead of the
      hard-coded target 851/source 800
    - the connect handshake reads online- before symbol-version and
      subscribes online- before offline-version, matching plc4j
    - multi-tag subscriptions execute sequentially in request order (the
      map iteration made the wire order random), honor the requested
      interval as the notification cycle time, no longer panic on a
      data-type-table miss or on the single-survivor shortcut after a
      failed resolution, and log failed symbolic resolutions
    - the data type table is keyed by the entry's main name - the name
      symbols reference - matching plc4j; value-type/string-length mapping
      reads the main name too (the secondary name is only set for aliases)
    - generated ads DataItem: WCHAR/WSTRING encode as UTF16LE per the mspec
      (the data-io codegen path loses stringEncoding - template follow-up),
      and the stray ')' in the write-side encodings is gone
    
    SPI (Go):
    - ReadBufferByteBased.ReadString honors the encoding reader-arg:
      UTF-16 strings decode per code unit instead of stopping at the first
      NUL byte of the first character
    - WriteBufferXmlBased renders float64 as the shortest round-trip
      decimal (like float32) instead of a fixed 32-digit expansion
    - PlcStruct keeps a deterministic member order (declaration order via
      NewPlcStructOrdered, sorted otherwise) for GetKeys/serialization
    - PlcTIME/PlcLTIME render ISO-8601 with the H/M/S decomposition and
      sub-second fraction instead of truncating to whole seconds;
      PlcDATE_AND_TIME renders the UTC wall time in ISO-8601 instead of
      Go's local-zone default format
    - the value handler parses temporal values from their ISO-8601 string
      forms (TIME/LTIME/DATE/TIME_OF_DAY/DATE_AND_TIME)
    - PlcDWORD/PlcSINT/PlcULINT/PlcWSTRING serialize under their own names
      (previously PlcDINT/PlcINT/PlcUINT/PlcSTRING); string-ish values
      carry encoding="UTF-8"; PlcWSTRING's bit length counts UTF-16 bytes
      including the BOM, matching plc4j
    
    Testsuite runners:
    - the Go runner compares only the values/responseCodes sections of api
      responses (matching the Java runner - the request serialization is
      implementation-specific), canonicalizes sibling order (response
      values are map-keyed), and supports struct-valued write requests
    - the Java runner's hand-built api-response rendering now matches the
      agreed conventions: BYTE as a byte bit-string (0x..), temporal and
      string values as dataType="string" with a text-derived bit length
    
    plc4j values: the unsigned bit-string types WORD/DWORD/LWORD serialize
    with the unsigned writers (dataType="uint"), PlcBYTE as a bit string,
    and PlcTIME as an ISO-8601 string like PlcLTIME.
    
    Testsuite XMLs (ads, modbus all-datatypes + manual-factory, canopen):
    unsigned integers carry dataType="uint", api-response BYTEs the 0x..
    byte form, the ads TIME its ISO-8601 form, and the ads struct members
    their declaration order (the old order was a 2020 HashMap artifact).
    plc4go/assets copies synced.
    
    Verified: full plc4go test sweep green; plc4j verify (incl. jacoco)
    green for spi values/fields/buffers-xml, test-utils, and the ads, s7,
    eip, slmp, modbus, canopen and iec-60870 drivers.
---
 .../testing/protocols/ads/DriverTestsuite.xml      | 194 ++++++++++-----------
 .../ManualFactoryModbusTCPDriverTest-testsuite.xml |   4 +-
 .../tcp/Modbus-all-datatypes-little-endian.xml     |  28 +--
 .../protocols/modbus/tcp/Modbus-all-datatypes.xml  |  28 +--
 plc4go/internal/ads/Connection.go                  |  71 +++++---
 plc4go/internal/ads/Driver.go                      |  24 ++-
 plc4go/internal/ads/DriverContext.go               |   9 +-
 plc4go/internal/ads/MessageTemplates.go            |   7 +-
 plc4go/internal/ads/Reader.go                      |   6 +-
 plc4go/internal/ads/Subscriber.go                  |  46 +++--
 plc4go/internal/ads/model/Configuration.go         |  31 ++--
 plc4go/protocols/ads/readwrite/model/DataItem.go   |  12 +-
 plc4go/spi/testutils/DriverTestRunner.go           |  79 ++++++++-
 plc4go/spi/utils/ReadBufferByteBased.go            |  38 +++-
 plc4go/spi/utils/WriteBufferXmlBased.go            |  11 +-
 plc4go/spi/values/PlcCHAR.go                       |   2 +-
 plc4go/spi/values/PlcDATE.go                       |   2 +-
 plc4go/spi/values/PlcDATE_AND_LTIME.go             |   2 +-
 plc4go/spi/values/PlcDATE_AND_TIME.go              |   6 +-
 plc4go/spi/values/PlcDWORD.go                      |   2 +-
 plc4go/spi/values/PlcLDATE.go                      |   2 +-
 plc4go/spi/values/PlcLDATE_AND_TIME.go             |   2 +-
 plc4go/spi/values/PlcLTIME.go                      |   4 +-
 plc4go/spi/values/PlcLTIME_OF_DAY.go               |   2 +-
 plc4go/spi/values/PlcSINT.go                       |   2 +-
 plc4go/spi/values/PlcSTRING.go                     |   2 +-
 plc4go/spi/values/PlcStruct.go                     |  48 ++++-
 plc4go/spi/values/PlcTIME.go                       |  75 +++++++-
 plc4go/spi/values/PlcTIME_OF_DAY.go                |   2 +-
 plc4go/spi/values/PlcULINT.go                      |   2 +-
 plc4go/spi/values/PlcValueHandler.go               |  33 +++-
 plc4go/spi/values/PlcWSTRING.go                    |   6 +-
 plc4go/tests/drivers/tests/ads_driver_test.go      |   1 -
 .../org/apache/plc4x/java/ads/AdsDriverIT.java     |   2 +-
 .../org/apache/plc4x/java/spi/values/PlcBYTE.java  |   3 +-
 .../org/apache/plc4x/java/spi/values/PlcDWORD.java |   2 +-
 .../org/apache/plc4x/java/spi/values/PlcLWORD.java |   2 +-
 .../org/apache/plc4x/java/spi/values/PlcTIME.java  |   5 +-
 .../org/apache/plc4x/java/spi/values/PlcWORD.java  |   2 +-
 .../internal/handlers/ApiResponseHandler.java      |  32 +++-
 .../resources/protocols/ads/DriverTestsuite.xml    | 194 ++++++++++-----------
 .../protocols/canopen/CANOpenDriverNMTIT.xml       |   2 +-
 .../protocols/canopen/CANOpenDriverSDOIT.xml       |   6 +-
 .../ManualFactoryModbusTCPDriverTest-testsuite.xml |   4 +-
 .../tcp/Modbus-all-datatypes-little-endian.xml     |  28 +--
 .../protocols/modbus/tcp/Modbus-all-datatypes.xml  |  28 +--
 46 files changed, 698 insertions(+), 395 deletions(-)

diff --git a/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml b/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
index 33d0248a5e..021ce08bfc 100644
--- a/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
+++ b/plc4go/assets/testing/protocols/ads/DriverTestsuite.xml
@@ -1206,72 +1206,72 @@
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
                   <PlcStruct>
-                    <hurz_STRING>
-                      <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
-                    </hurz_STRING>
-                    <hurz_LTIME>
-                      <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
-                    </hurz_LTIME>
+                    <hurz_BOOL>
+                      <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
+                    </hurz_BOOL>
+                    <hurz_BYTE>
+                      <PlcBYTE dataType="byte" bitLength="8">0x01</PlcBYTE>
+                    </hurz_BYTE>
+                    <hurz_WORD>
+                      <PlcWORD dataType="uint" bitLength="16">2</PlcWORD>
+                    </hurz_WORD>
+                    <hurz_DWORD>
+                      <PlcDWORD dataType="uint" bitLength="32">3</PlcDWORD>
+                    </hurz_DWORD>
                     <hurz_LWORD>
-                      <PlcLWORD dataType="int" bitLength="64">4</PlcLWORD>
+                      <PlcLWORD dataType="uint" bitLength="64">4</PlcLWORD>
                     </hurz_LWORD>
-                    <hurz_REAL>
-                      <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
-                    </hurz_REAL>
-                    <hurz_ULINT>
-                      <PlcULINT dataType="int" bitLength="64">12</PlcULINT>
-                    </hurz_ULINT>
-                    <hurz_WSTRING>
-                      <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
-                    </hurz_WSTRING>
-                    <hurz_LINT>
-                      <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
-                    </hurz_LINT>
-                    <hurz_DATE_AND_TIME>
-                      <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
-                    </hurz_DATE_AND_TIME>
-                    <hurz_UINT>
-                      <PlcUINT dataType="int" bitLength="16">8</PlcUINT>
-                    </hurz_UINT>
                     <hurz_SINT>
                       <PlcSINT dataType="int" bitLength="8">5</PlcSINT>
                     </hurz_SINT>
                     <hurz_USINT>
-                      <PlcUSINT dataType="int" bitLength="8">6</PlcUSINT>
+                      <PlcUSINT dataType="uint" bitLength="8">6</PlcUSINT>
                     </hurz_USINT>
-                    <hurz_LREAL>
-                      <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
-                    </hurz_LREAL>
-                    <hurz_TIME_OF_DAY>
-                      <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
-                    </hurz_TIME_OF_DAY>
-                    <hurz_BOOL>
-                      <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
-                    </hurz_BOOL>
+                    <hurz_INT>
+                      <PlcINT dataType="int" bitLength="16">7</PlcINT>
+                    </hurz_INT>
+                    <hurz_UINT>
+                      <PlcUINT dataType="uint" bitLength="16">8</PlcUINT>
+                    </hurz_UINT>
                     <hurz_DINT>
                       <PlcDINT dataType="int" bitLength="32">9</PlcDINT>
                     </hurz_DINT>
                     <hurz_UDINT>
-                      <PlcUDINT dataType="int" bitLength="32">10</PlcUDINT>
+                      <PlcUDINT dataType="uint" bitLength="32">10</PlcUDINT>
                     </hurz_UDINT>
-                    <hurz_BYTE>
-                      <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
-                    </hurz_BYTE>
+                    <hurz_LINT>
+                      <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
+                    </hurz_LINT>
+                    <hurz_ULINT>
+                      <PlcULINT dataType="uint" bitLength="64">12</PlcULINT>
+                    </hurz_ULINT>
+                    <hurz_REAL>
+                      <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
+                    </hurz_REAL>
+                    <hurz_LREAL>
+                      <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
+                    </hurz_LREAL>
                     <hurz_TIME>
-                      <PlcTIME dataType="int" bitLength="32">1234</PlcTIME>
+                      <PlcTIME dataType="string" bitLength="64" encoding="UTF-8">PT1.234S</PlcTIME>
                     </hurz_TIME>
-                    <hurz_DWORD>
-                      <PlcDWORD dataType="int" bitLength="32">3</PlcDWORD>
-                    </hurz_DWORD>
-                    <hurz_INT>
-                      <PlcINT dataType="int" bitLength="16">7</PlcINT>
-                    </hurz_INT>
-                    <hurz_WORD>
-                      <PlcWORD dataType="int" bitLength="16">2</PlcWORD>
-                    </hurz_WORD>
+                    <hurz_LTIME>
+                      <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
+                    </hurz_LTIME>
                     <hurz_DATE>
                       <PlcDATE dataType="string" bitLength="80" encoding="UTF-8">1978-03-28</PlcDATE>
                     </hurz_DATE>
+                    <hurz_TIME_OF_DAY>
+                      <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
+                    </hurz_TIME_OF_DAY>
+                    <hurz_DATE_AND_TIME>
+                      <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
+                    </hurz_DATE_AND_TIME>
+                    <hurz_STRING>
+                      <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
+                    </hurz_STRING>
+                    <hurz_WSTRING>
+                      <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
+                    </hurz_WSTRING>
                   </PlcStruct>
                 </value>
               </PlcResponseItem>
@@ -1305,72 +1305,72 @@
               <address>MAIN.hurz_Struct</address>
               <value>
                 <PlcStruct>
-                  <hurz_STRING>
-                    <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
-                  </hurz_STRING>
-                  <hurz_LTIME>
-                    <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
-                  </hurz_LTIME>
+                  <hurz_BOOL>
+                    <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
+                  </hurz_BOOL>
+                  <hurz_BYTE>
+                    <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
+                  </hurz_BYTE>
+                  <hurz_WORD>
+                    <PlcWORD dataType="uint" bitLength="16">2</PlcWORD>
+                  </hurz_WORD>
+                  <hurz_DWORD>
+                    <PlcDWORD dataType="uint" bitLength="32">3</PlcDWORD>
+                  </hurz_DWORD>
                   <hurz_LWORD>
-                    <PlcLWORD dataType="int" bitLength="64">4</PlcLWORD>
+                    <PlcLWORD dataType="uint" bitLength="64">4</PlcLWORD>
                   </hurz_LWORD>
-                  <hurz_REAL>
-                    <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
-                  </hurz_REAL>
-                  <hurz_ULINT>
-                    <PlcULINT dataType="int" bitLength="64">12</PlcULINT>
-                  </hurz_ULINT>
-                  <hurz_WSTRING>
-                    <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
-                  </hurz_WSTRING>
-                  <hurz_LINT>
-                    <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
-                  </hurz_LINT>
-                  <hurz_DATE_AND_TIME>
-                    <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
-                  </hurz_DATE_AND_TIME>
-                  <hurz_UINT>
-                    <PlcUINT dataType="int" bitLength="16">8</PlcUINT>
-                  </hurz_UINT>
                   <hurz_SINT>
                     <PlcSINT dataType="int" bitLength="8">5</PlcSINT>
                   </hurz_SINT>
                   <hurz_USINT>
-                    <PlcUSINT dataType="int" bitLength="8">6</PlcUSINT>
+                    <PlcUSINT dataType="uint" bitLength="8">6</PlcUSINT>
                   </hurz_USINT>
-                  <hurz_LREAL>
-                    <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
-                  </hurz_LREAL>
-                  <hurz_TIME_OF_DAY>
-                    <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
-                  </hurz_TIME_OF_DAY>
-                  <hurz_BOOL>
-                    <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
-                  </hurz_BOOL>
+                  <hurz_INT>
+                    <PlcINT dataType="int" bitLength="16">7</PlcINT>
+                  </hurz_INT>
+                  <hurz_UINT>
+                    <PlcUINT dataType="uint" bitLength="16">8</PlcUINT>
+                  </hurz_UINT>
                   <hurz_DINT>
                     <PlcDINT dataType="int" bitLength="32">9</PlcDINT>
                   </hurz_DINT>
                   <hurz_UDINT>
-                    <PlcUDINT dataType="int" bitLength="32">10</PlcUDINT>
+                    <PlcUDINT dataType="uint" bitLength="32">10</PlcUDINT>
                   </hurz_UDINT>
-                  <hurz_BYTE>
-                    <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
-                  </hurz_BYTE>
+                  <hurz_LINT>
+                    <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
+                  </hurz_LINT>
+                  <hurz_ULINT>
+                    <PlcULINT dataType="uint" bitLength="64">12</PlcULINT>
+                  </hurz_ULINT>
+                  <hurz_REAL>
+                    <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
+                  </hurz_REAL>
+                  <hurz_LREAL>
+                    <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
+                  </hurz_LREAL>
                   <hurz_TIME>
                     <PlcTIME dataType="string" bitLength="64" encoding="UTF-8">PT1.234S</PlcTIME>
                   </hurz_TIME>
-                  <hurz_DWORD>
-                    <PlcDWORD dataType="int" bitLength="32">3</PlcDWORD>
-                  </hurz_DWORD>
-                  <hurz_INT>
-                    <PlcINT dataType="int" bitLength="16">7</PlcINT>
-                  </hurz_INT>
-                  <hurz_WORD>
-                    <PlcWORD dataType="int" bitLength="16">2</PlcWORD>
-                  </hurz_WORD>
+                  <hurz_LTIME>
+                    <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
+                  </hurz_LTIME>
                   <hurz_DATE>
                     <PlcDATE dataType="string" bitLength="80" encoding="UTF-8">1978-03-28</PlcDATE>
                   </hurz_DATE>
+                  <hurz_TIME_OF_DAY>
+                    <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
+                  </hurz_TIME_OF_DAY>
+                  <hurz_DATE_AND_TIME>
+                    <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
+                  </hurz_DATE_AND_TIME>
+                  <hurz_STRING>
+                    <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
+                  </hurz_STRING>
+                  <hurz_WSTRING>
+                    <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
+                  </hurz_WSTRING>
                 </PlcStruct>
               </value>
             </tag>
diff --git a/plc4go/assets/testing/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml b/plc4go/assets/testing/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
index 58ab5c62e0..1a1ce25989 100644
--- a/plc4go/assets/testing/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
+++ b/plc4go/assets/testing/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
@@ -129,7 +129,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="uint" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </holding-register_2_BYTE>
@@ -1064,7 +1064,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="uint" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </holding-register_2_BYTE>
diff --git a/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml b/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
index 7804ad4fc3..a875b5f4d5 100644
--- a/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
+++ b/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
@@ -313,7 +313,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -401,7 +401,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                        <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -506,7 +506,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                  <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -594,7 +594,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                        <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -699,7 +699,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                  <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -789,7 +789,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                        <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1087,7 +1087,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                  <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1175,7 +1175,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                        <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1473,7 +1473,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                  <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1561,7 +1561,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                        <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1861,7 +1861,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1951,7 +1951,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                        <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -2251,7 +2251,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                  <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -2341,7 +2341,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                        <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
diff --git a/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes.xml b/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes.xml
index 1c5b7da057..31b5d343cd 100644
--- a/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes.xml
+++ b/plc4go/assets/testing/protocols/modbus/tcp/Modbus-all-datatypes.xml
@@ -307,7 +307,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -395,7 +395,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                        <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -500,7 +500,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                  <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -588,7 +588,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                        <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -693,7 +693,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                  <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -783,7 +783,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                        <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1081,7 +1081,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                  <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1169,7 +1169,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                        <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1467,7 +1467,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                  <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1555,7 +1555,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                        <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1855,7 +1855,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1945,7 +1945,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                        <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -2245,7 +2245,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                  <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -2335,7 +2335,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                        <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
diff --git a/plc4go/internal/ads/Connection.go b/plc4go/internal/ads/Connection.go
index 28c46db1f1..e1eff2a8fd 100644
--- a/plc4go/internal/ads/Connection.go
+++ b/plc4go/internal/ads/Connection.go
@@ -27,6 +27,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"time"
 
 	"github.com/rs/zerolog"
 
@@ -143,6 +144,18 @@ func (m *Connection) Connect(ctx context.Context) error {
 		return errors.Wrap(err, "error connecting to message codec")
 	}
 
+	// For testing purposes we can skip the waiting for a complete connection
+	if !m.driverContext.awaitSetupComplete {
+		m.wg.Go(func() {
+			if err := m.setupConnection(ctx); err != nil {
+				m.log.Error().Err(err).Msg("Error during connection setup")
+			}
+		})
+		m.log.Warn().Msg("Connection used in an unsafe way. !!!DON'T USE IN PRODUCTION!!!")
+		m.SetConnected(true)
+		return nil
+	}
+
 	if err := m.setupConnection(ctx); err != nil {
 		return errors.Wrap(err, "error setting up connection")
 	}
@@ -158,6 +171,18 @@ func (m *Connection) setupConnection(ctx context.Context) error {
 	m.driverContext.adsVersion = fmt.Sprintf("%d.%d.%d", deviceInfoResponse.GetMajorVersion(), deviceInfoResponse.GetMinorVersion(), deviceInfoResponse.GetVersion())
 	m.driverContext.deviceName = GetZeroTerminatedString(deviceInfoResponse.GetDevice())
 
+	// Read the online-version
+	// (The order online- before symbol-version matches the Java driver and the shared driver testsuite.)
+	onlineVersionResponse, err := m.ExecuteAdsReadWriteRequest(ctx, uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_VALBYNAME), 0, 4, nil, []byte("TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"))
+	if err != nil {
+		return errors.Wrap(err, "error reading online version")
+	}
+	rb := utils.NewReadBufferByteBased(onlineVersionResponse.GetData(), utils.WithByteOrderForReadBufferByteBased(binary.LittleEndian))
+	m.driverContext.onlineVersion, err = rb.ReadUint32("", 32)
+	if err != nil {
+		return errors.Wrap(err, "error reading online version")
+	}
+
 	// Read the symbol-version (offline changes)
 	symbolVersionResponse, err := m.ExecuteAdsReadRequest(ctx, uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_VERSION), 0, 1)
 	if err != nil {
@@ -170,17 +195,6 @@ func (m *Connection) setupConnection(ctx context.Context) error {
 	}
 	m.driverContext.symbolVersion = symbolVersionResponse.GetData()[0]
 
-	// Read the online-version
-	onlineVersionResponse, err := m.ExecuteAdsReadWriteRequest(ctx, uint32(readWriteModel.ReservedIndexGroups_ADSIGRP_SYM_VALBYNAME), 0, 4, nil, []byte("TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"))
-	if err != nil {
-		return errors.Wrap(err, "error reading online version")
-	}
-	rb := utils.NewReadBufferByteBased(onlineVersionResponse.GetData(), utils.WithByteOrderForReadBufferByteBased(binary.LittleEndian))
-	m.driverContext.onlineVersion, err = rb.ReadUint32("", 32)
-	if err != nil {
-		return errors.Wrap(err, "error reading online version")
-	}
-
 	// Read the data type and symbol table
 	err = m.readSymbolTableAndDatatypeTable(ctx)
 	if err != nil {
@@ -219,13 +233,16 @@ func (m *Connection) setupConnection(ctx context.Context) error {
 	})
 
 	// Subscribe for changes to the symbol or the offline-versions
+	// (Cyclic with a 1s check interval: the wire request is an ON_CHANGE device notification
+	// whose cycle time is the interval, matching the Java driver's Duration.ofMillis(1000).
+	// The online- before offline-version order matches the Java driver and the driver testsuite.)
 	versionChangeRequest, err := m.SubscriptionRequestBuilder().
-		AddChangeOfStateTagAddress("offlineVersion", "0xF008/0x0000:USINT").
-		AddPreRegisteredConsumer("offlineVersion", func(event apiModel.PlcSubscriptionEvent) {
-			if event.GetResponseCode("offlineVersion") == apiModel.PlcResponseCode_OK {
-				newVersion := event.GetValue("offlineVersion").GetUint8()
-				if newVersion != m.driverContext.symbolVersion {
-					m.log.Info().Msg("detected offline version change: reloading symbol- and data-type-table.")
+		AddCyclicTagAddress("onlineVersion", "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt", time.Second).
+		AddPreRegisteredConsumer("onlineVersion", func(event apiModel.PlcSubscriptionEvent) {
+			if event.GetResponseCode("onlineVersion") == apiModel.PlcResponseCode_OK {
+				newVersion := event.GetValue("onlineVersion").GetUint32()
+				if newVersion != m.driverContext.onlineVersion {
+					m.log.Info().Msg("detected online version change: reloading symbol- and data-type-table.")
 					err := m.readSymbolTableAndDatatypeTable(ctx)
 					if err != nil {
 						m.log.Error().Err(err).Msg("error updating data-type and symbol tables")
@@ -233,12 +250,12 @@ func (m *Connection) setupConnection(ctx context.Context) error {
 				}
 			}
 		}).
-		AddChangeOfStateTagAddress("onlineVersion", "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt").
-		AddPreRegisteredConsumer("onlineVersion", func(event apiModel.PlcSubscriptionEvent) {
-			if event.GetResponseCode("onlineVersion") == apiModel.PlcResponseCode_OK {
-				newVersion := event.GetValue("onlineVersion").GetUint32()
-				if newVersion != m.driverContext.onlineVersion {
-					m.log.Info().Msg("detected online version change: reloading symbol- and data-type-table.")
+		AddCyclicTagAddress("offlineVersion", "0xF008/0x0000:USINT", time.Second).
+		AddPreRegisteredConsumer("offlineVersion", func(event apiModel.PlcSubscriptionEvent) {
+			if event.GetResponseCode("offlineVersion") == apiModel.PlcResponseCode_OK {
+				newVersion := event.GetValue("offlineVersion").GetUint8()
+				if newVersion != m.driverContext.symbolVersion {
+					m.log.Info().Msg("detected offline version change: reloading symbol- and data-type-table.")
 					err := m.readSymbolTableAndDatatypeTable(ctx)
 					if err != nil {
 						m.log.Error().Err(err).Msg("error updating data-type and symbol tables")
@@ -309,7 +326,9 @@ func (m *Connection) readDataTypeTable(ctx context.Context, dataTableSize uint32
 		if err != nil {
 			return nil, fmt.Errorf("error parsing table: %v", err)
 		}
-		dataTypes[dataType.GetSecondaryName()] = dataType
+		// Key by the main name: that's the name symbols reference via their dataTypeName
+		// (and what the Java driver keys by); the secondary name is the aliased/simple type.
+		dataTypes[dataType.GetMainName()] = dataType
 	}
 	return dataTypes, nil
 }
@@ -401,7 +420,9 @@ func (m *Connection) resolveSymbolicAddress(ctx context.Context, addressParts []
 
 func (m *Connection) getPlcValueForAdsDataTypeTableEntry(entry readWriteModel.AdsDataTypeTableEntry) (apiValues.PlcValueType, int32) {
 	stringLength := -1
-	dataTypeName := entry.GetSecondaryName()
+	// The main name carries the type's name ("BYTE", "STRING(80)", ...); the secondary
+	// name is only set for aliased types (matching the Java driver's use of getMainName()).
+	dataTypeName := entry.GetMainName()
 	if strings.HasPrefix(dataTypeName, "STRING(") {
 		var err error
 		stringLength, err = strconv.Atoi(dataTypeName[7 : len(dataTypeName)-1])
diff --git a/plc4go/internal/ads/Driver.go b/plc4go/internal/ads/Driver.go
index 07577d02e5..d0743cee23 100644
--- a/plc4go/internal/ads/Driver.go
+++ b/plc4go/internal/ads/Driver.go
@@ -42,6 +42,9 @@ type Driver struct {
 
 	discoverer *Discoverer
 
+	awaitSetupComplete      bool
+	awaitDisconnectComplete bool
+
 	log      zerolog.Logger
 	_options []options.WithOption // Used to pass them downstream
 }
@@ -49,9 +52,11 @@ type Driver struct {
 func NewDriver(_options ...options.WithOption) plc4go.PlcDriver {
 	customLogger := options.ExtractCustomLoggerOrDefaultToGlobal(_options...)
 	driver := &Driver{
-		discoverer: NewDiscoverer(_options...),
-		log:        customLogger,
-		_options:   _options,
+		discoverer:              NewDiscoverer(_options...),
+		awaitSetupComplete:      true,
+		awaitDisconnectComplete: true,
+		log:                     customLogger,
+		_options:                _options,
 	}
 	driver.DefaultDriver = _default.NewDefaultDriver(driver, "ads", "Beckhoff TwinCat ADS", "tcp", NewTagHandler())
 	return driver
@@ -108,6 +113,8 @@ func (d *Driver) GetConnection(ctx context.Context, transportUrl url.URL, transp
 	if err != nil {
 		return nil, errors.Wrap(err, "couldn't create connection")
 	}
+	connection.driverContext.awaitSetupComplete = d.awaitSetupComplete
+	connection.driverContext.awaitDisconnectComplete = d.awaitDisconnectComplete
 	connectionLog.Debug().Interface("connection", connection).Msg("created connection, connecting now")
 	if err := connection.Connect(ctx); err != nil {
 		return nil, errors.Wrap(err, "Error connecting connection")
@@ -115,6 +122,17 @@ func (d *Driver) GetConnection(ctx context.Context, transportUrl url.URL, transp
 	return connection, nil
 }
 
+// SetAwaitSetupComplete lets the driver testsuite runner return from Connect before the
+// connection handshake ran, so the testsuite can feed the handshake's responses itself.
+func (d *Driver) SetAwaitSetupComplete(awaitComplete bool) {
+	d.awaitSetupComplete = awaitComplete
+}
+
+// SetAwaitDisconnectComplete is the disconnect-side counterpart of SetAwaitSetupComplete.
+func (d *Driver) SetAwaitDisconnectComplete(awaitComplete bool) {
+	d.awaitDisconnectComplete = awaitComplete
+}
+
 func (d *Driver) SupportsDiscovery() bool {
 	return true
 }
diff --git a/plc4go/internal/ads/DriverContext.go b/plc4go/internal/ads/DriverContext.go
index b3fe369d78..4b81eea754 100644
--- a/plc4go/internal/ads/DriverContext.go
+++ b/plc4go/internal/ads/DriverContext.go
@@ -61,8 +61,8 @@ func (m *DriverContext) clear() {
 	m.onlineVersion = 0
 	m.dataTypeTable = map[string]driverModel.AdsDataTypeTableEntry{}
 	m.symbolTable = map[string]driverModel.AdsSymbolTableEntry{}
-	m.awaitSetupComplete = false
-	m.awaitDisconnectComplete = false
+	// awaitSetupComplete/awaitDisconnectComplete are configuration handed down from the
+	// driver, not session state - clearing must not reset them.
 }
 
 func (m *DriverContext) getDirectTagForSymbolTag(symbolicPlcTag model.SymbolicPlcTag) (*model.DirectPlcTag, error) {
@@ -124,7 +124,8 @@ func (m *DriverContext) getDataTypeForDataTypeTableEntry(entry driverModel.AdsDa
 	if entry.GetNumChildren() > 0 {
 		return apiValues.Struct
 	}
-	dataTypeName := entry.GetSecondaryName()
+	// The main name carries the type's name (matching the Java driver's getMainName()).
+	dataTypeName := entry.GetMainName()
 	if strings.HasPrefix(dataTypeName, "STRING(") {
 		dataTypeName = "STRING"
 	} else if strings.HasPrefix(dataTypeName, "WSTRING(") {
@@ -135,7 +136,7 @@ func (m *DriverContext) getDataTypeForDataTypeTableEntry(entry driverModel.AdsDa
 }
 
 func (m *DriverContext) getStringLengthForDataTypeTableEntry(entry driverModel.AdsDataTypeTableEntry) int32 {
-	dataTypeName := entry.GetSecondaryName()
+	dataTypeName := entry.GetMainName()
 	if strings.HasPrefix(dataTypeName, "STRING(") {
 		lenStr := dataTypeName[7 : len(dataTypeName)-1]
 		lenVal, err := strconv.Atoi(lenStr)
diff --git a/plc4go/internal/ads/MessageTemplates.go b/plc4go/internal/ads/MessageTemplates.go
index eccf0cb147..ab396d5b7e 100644
--- a/plc4go/internal/ads/MessageTemplates.go
+++ b/plc4go/internal/ads/MessageTemplates.go
@@ -23,9 +23,10 @@ import adsModel "github.com/apache/plc4x/plc4go/protocols/ads/readwrite/model"
 
 func (m *Connection) NewAdsReadDeviceInfoRequest() adsModel.AmsTCPPacket {
 	return adsModel.NewAmsTCPPacket(
-		adsModel.NewAdsReadDeviceInfoRequest(m.configuration.TargetAmsNetId, uint16(adsModel.DefaultAmsPorts_RUNTIME_SYSTEM_01),
-			// TODO: Replace 800 with constant.
-			m.configuration.SourceAmsNetId, 800, 0, m.driverContext.getInvokeId()))
+		adsModel.NewAdsReadDeviceInfoRequest(
+			m.configuration.TargetAmsNetId, m.configuration.TargetAmsPort,
+			m.configuration.SourceAmsNetId, m.configuration.SourceAmsPort,
+			0, m.driverContext.getInvokeId()))
 }
 
 func (m *Connection) NewAdsReadRequest(indexGroup uint32, indexOffset uint32, length uint32) adsModel.AmsTCPPacket {
diff --git a/plc4go/internal/ads/Reader.go b/plc4go/internal/ads/Reader.go
index 75d69174bb..872c64c6bd 100644
--- a/plc4go/internal/ads/Reader.go
+++ b/plc4go/internal/ads/Reader.go
@@ -279,6 +279,7 @@ func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, a
 	} else if len(dataType.GetChildren()) > 0 {
 		// This is a Struct type.
 		plcValues := map[string]apiValues.PlcValue{}
+		var memberOrder []string
 		startPos := uint32(rb.GetPos())
 		curPos := uint32(0)
 		for _, child := range dataType.GetChildren() {
@@ -298,9 +299,12 @@ func (m *Connection) parsePlcValue(dataType driverModel.AdsDataTypeTableEntry, a
 				return nil, errors.Wrap(err, fmt.Sprintf("error parsing propery %s of type %s", childName, dataType.GetSecondaryName()))
 			}
 			plcValues[childName] = childValue
+			memberOrder = append(memberOrder, childName)
 			curPos = uint32(rb.GetPos()) - startPos
 		}
-		return spiValues.NewPlcStruct(plcValues), nil
+		// Keep the struct's declaration order (the order of the children in the data type
+		// table), like the Java driver does with its LinkedHashMap-based PlcStruct.
+		return spiValues.NewPlcStructOrdered(plcValues, memberOrder), nil
 	} else {
 		// This is a primitive type.
 		valueType, stringLength := m.getPlcValueForAdsDataTypeTableEntry(dataType)
diff --git a/plc4go/internal/ads/Subscriber.go b/plc4go/internal/ads/Subscriber.go
index 0d7d9dc807..8cb1457221 100644
--- a/plc4go/internal/ads/Subscriber.go
+++ b/plc4go/internal/ads/Subscriber.go
@@ -62,6 +62,7 @@ func (m *Connection) Subscribe(ctx context.Context, subscriptionRequest apiModel
 			symbolicTag := tag.(dirverModel.SymbolicPlcTag)
 			directTagPtr, err := m.driverContext.getDirectTagForSymbolTag(symbolicTag)
 			if err != nil {
+				m.log.Warn().Err(err).Str("tagName", tagName).Msg("error resolving symbolic tag for subscription")
 				subResults[tagName] = spiModel.NewDefaultPlcSubscriptionRequestResult(subscriptionRequest, nil, errors.Wrap(err, "error resolving symbolic tag"))
 				continue
 			}
@@ -84,20 +85,18 @@ func (m *Connection) Subscribe(ctx context.Context, subscriptionRequest apiModel
 		)
 	}
 
-	// If this is a single item request, we can take a shortcut.
-	if len(subSubscriptionRequests) == 1 {
+	// If this is a single item request with a successfully resolved tag, we can take a shortcut.
+	// (Indexing by the request's first tag name would be wrong here: with multiple tags where
+	// all but one failed resolution, the surviving entry is not necessarily the first tag.)
+	if len(subSubscriptionRequests) == 1 && len(subscriptionRequest.GetTagNames()) == 1 {
 		tagName := subscriptionRequest.GetTagNames()[0]
 		subSubscriptionRequest := subSubscriptionRequests[tagName]
 		return m.subscribe(ctx, subSubscriptionRequest)
 	}
 
-	// Create a sub-result-channel map and prepare execute the subscriptions.
-	subResultChannels := map[string]<-chan apiModel.PlcSubscriptionRequestResult{}
-	for tagName, subSubscriptionRequest := range subSubscriptionRequests {
-		subResultChannels[tagName] = m.subscribe(ctx, subSubscriptionRequest)
-	}
-
-	// Create a new result-channel, which completes as soon as all sub-result-channels have returned
+	// Create a new result-channel, which completes as soon as all sub-requests are done.
+	// The sub-requests are executed sequentially in request order: each is a single
+	// round-trip anyway, and it keeps the order of the requests on the wire deterministic.
 	globalResultChannel := make(chan apiModel.PlcSubscriptionRequestResult, 1)
 	m.wg.Go(func() {
 		defer func() {
@@ -108,15 +107,17 @@ func (m *Connection) Subscribe(ctx context.Context, subscriptionRequest apiModel
 					Msg("panic-ed")
 			}
 		}()
-		// Iterate over all sub-results
-		for _, subResultChannel := range subResultChannels {
+		for _, tagName := range subscriptionRequest.GetTagNames() {
+			subSubscriptionRequest, ok := subSubscriptionRequests[tagName]
+			if !ok {
+				// Tag resolution failed; its error result is already recorded in subResults.
+				continue
+			}
 			select {
 			case <-ctx.Done():
 				utils.DeliverResult(m.log, globalResultChannel, spiModel.NewDefaultPlcSubscriptionRequestResult(subscriptionRequest, nil, ctx.Err()))
 				return
-			case subResult := <-subResultChannel:
-				// These are all single value requests ... so it's safe to assume this shortcut.
-				tagName := subResult.GetRequest().GetTagNames()[0]
+			case subResult := <-m.subscribe(ctx, subSubscriptionRequest):
 				subResults[tagName] = subResult
 			}
 		}
@@ -141,16 +142,29 @@ func (m *Connection) subscribe(ctx context.Context, subscriptionRequest apiModel
 		tagName := subscriptionRequest.GetTagNames()[0]
 		directTag := subscriptionRequest.GetTag(tagName).(dirverModel.DirectPlcTag)
 		if directTag.DataType == nil {
-			directTag.DataType = m.driverContext.dataTypeTable[directTag.ValueType.String()]
+			dataType, ok := m.driverContext.dataTypeTable[directTag.ValueType.String()]
+			if !ok {
+				utils.DeliverResult(m.log, responseChan, spiModel.NewDefaultPlcSubscriptionRequestResult(
+					subscriptionRequest,
+					nil,
+					errors.Errorf("no entry for data type %s of tag %s in the data type table", directTag.ValueType, tagName),
+				))
+				return
+			}
+			directTag.DataType = dataType
 		}
 
-		response, err := m.ExecuteAdsAddDeviceNotificationRequest(ctx, directTag.IndexGroup, directTag.IndexOffset, directTag.DataType.GetSize(), model.AdsTransMode_ON_CHANGE, 0, 0)
+		// The requested interval is the device's cycle time for checking the value (in ms on
+		// the wire, matching the Java driver); 0 leaves the check cycle to the device.
+		cycleTime := uint32(subscriptionRequest.(*spiModel.DefaultPlcSubscriptionRequest).GetInterval(tagName).Milliseconds())
+		response, err := m.ExecuteAdsAddDeviceNotificationRequest(ctx, directTag.IndexGroup, directTag.IndexOffset, directTag.DataType.GetSize(), model.AdsTransMode_ON_CHANGE, 0, cycleTime)
 		if err != nil {
 			utils.DeliverResult(m.log, responseChan, spiModel.NewDefaultPlcSubscriptionRequestResult(
 				subscriptionRequest,
 				nil,
 				err,
 			))
+			return
 		}
 		// Create a new subscription handle.
 		subscriptionHandle := dirverModel.NewAdsSubscriptionHandle(
diff --git a/plc4go/internal/ads/model/Configuration.go b/plc4go/internal/ads/model/Configuration.go
index fd10219354..a76dbdc385 100644
--- a/plc4go/internal/ads/model/Configuration.go
+++ b/plc4go/internal/ads/model/Configuration.go
@@ -39,7 +39,7 @@ type Configuration struct {
 func ParseFromOptions(localLogger zerolog.Logger, options map[string][]string) (Configuration, error) {
 	configuration := Configuration{}
 
-	sourceAmsNetId := getFromOptions(localLogger, options, "sourceAmsNetId")
+	sourceAmsNetId := getFromOptions(localLogger, options, "sourceAmsNetId", "source-ams-net-id")
 	if sourceAmsNetId == "" {
 		return Configuration{}, errors.New("Required parameter sourceAmsNetId missing")
 	}
@@ -76,7 +76,7 @@ func ParseFromOptions(localLogger zerolog.Logger, options map[string][]string) (
 		uint8(octet5),
 		uint8(octet6),
 	)
-	sourceAmsPort := getFromOptions(localLogger, options, "sourceAmsPort")
+	sourceAmsPort := getFromOptions(localLogger, options, "sourceAmsPort", "source-ams-port")
 	if sourceAmsPort == "" {
 		return Configuration{}, errors.New("Required parameter sourceAmsPort missing")
 	}
@@ -85,8 +85,8 @@ func ParseFromOptions(localLogger zerolog.Logger, options map[string][]string) (
 		return Configuration{}, errors.Wrap(err, "error parsing sourceAmsPort")
 	}
 	configuration.SourceAmsPort = uint16(parsedUint)
-	targetAmsNetId := getFromOptions(localLogger, options, "targetAmsNetId")
-	if sourceAmsNetId == "" {
+	targetAmsNetId := getFromOptions(localLogger, options, "targetAmsNetId", "target-ams-net-id")
+	if targetAmsNetId == "" {
 		return Configuration{}, errors.New("Required parameter targetAmsNetId missing")
 	}
 	split = strings.Split(targetAmsNetId, ".")
@@ -122,7 +122,7 @@ func ParseFromOptions(localLogger zerolog.Logger, options map[string][]string) (
 		uint8(octet5),
 		uint8(octet6),
 	)
-	targetAmsPort := getFromOptions(localLogger, options, "targetAmsPort")
+	targetAmsPort := getFromOptions(localLogger, options, "targetAmsPort", "target-ams-port")
 	if targetAmsPort == "" {
 		return Configuration{}, errors.New("Required parameter targetAmsPort missing")
 	}
@@ -135,15 +135,20 @@ func ParseFromOptions(localLogger zerolog.Logger, options map[string][]string) (
 	return configuration, nil
 }
 
-func getFromOptions(localLogger zerolog.Logger, options map[string][]string, key string) string {
-	if optionValues, ok := options[key]; ok {
-		if len(optionValues) <= 0 {
-			return ""
-		}
-		if len(optionValues) > 1 {
-			localLogger.Warn().Str("key", key).Msg("Options key must be unique")
+// getFromOptions returns the value of the first key present in the options. The additional
+// keys are aliases: the kebab-case names match the plc4j driver's connection parameters, so
+// the same connection string works with both implementations.
+func getFromOptions(localLogger zerolog.Logger, options map[string][]string, keys ...string) string {
+	for _, key := range keys {
+		if optionValues, ok := options[key]; ok {
+			if len(optionValues) <= 0 {
+				continue
+			}
+			if len(optionValues) > 1 {
+				localLogger.Warn().Str("key", key).Msg("Options key must be unique")
+			}
+			return optionValues[0]
 		}
-		return optionValues[0]
 	}
 	return ""
 }
diff --git a/plc4go/protocols/ads/readwrite/model/DataItem.go b/plc4go/protocols/ads/readwrite/model/DataItem.go
index 5ff0cacf37..61c16a4666 100644
--- a/plc4go/protocols/ads/readwrite/model/DataItem.go
+++ b/plc4go/protocols/ads/readwrite/model/DataItem.go
@@ -193,7 +193,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, p
 		return values.NewPlcCHAR(value), nil
 	case plcValueType == api.WCHAR: // WCHAR
 		// Simple Field (value)
-		value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF8"))
+		value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(16), utils.WithEncoding("UTF16LE"))
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -216,7 +216,7 @@ func DataItemParseWithBuffer(ctx context.Context, readBuffer utils.ReadBuffer, p
 		return values.NewPlcSTRING(value), nil
 	case plcValueType == api.WSTRING: // WSTRING
 		// Simple Field (value)
-		value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(((stringLength)*(8))*(2)), utils.WithEncoding("UTF8"))
+		value, _valueErr := /*TODO: migrate me*/ /*TODO: migrate me*/ readBuffer.ReadString("value", uint32(((stringLength)*(8))*(2)), utils.WithEncoding("UTF16LE"))
 		if _valueErr != nil {
 			return nil, errors.Wrap(_valueErr, "Error parsing 'value' field")
 		}
@@ -418,17 +418,17 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
 		}
 	case plcValueType == api.CHAR: // CHAR
 		// Simple Field (value)
-		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(8), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
 			return errors.Wrap(_err, "Error serializing 'value' field")
 		}
 	case plcValueType == api.WCHAR: // WCHAR
 		// Simple Field (value)
-		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(16), value.GetString(), utils.WithEncoding("UTF16LE")); _err != nil {
 			return errors.Wrap(_err, "Error serializing 'value' field")
 		}
 	case plcValueType == api.STRING: // STRING
 		// Simple Field (value)
-		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32((stringLength)*(8)), value.GetString(), utils.WithEncoding("UTF8")); _err != nil {
 			return errors.Wrap(_err, "Error serializing 'value' field")
 		}
 
@@ -438,7 +438,7 @@ func DataItemSerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.Wri
 		}
 	case plcValueType == api.WSTRING: // WSTRING
 		// Simple Field (value)
-		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(((stringLength)*(8))*(2)), value.GetString(), utils.WithEncoding("UTF8)")); _err != nil {
+		if _err := /*TODO: migrate me*/ writeBuffer.WriteString("value", uint32(((stringLength)*(8))*(2)), value.GetString(), utils.WithEncoding("UTF16LE")); _err != nil {
 			return errors.Wrap(_err, "Error serializing 'value' field")
 		}
 
diff --git a/plc4go/spi/testutils/DriverTestRunner.go b/plc4go/spi/testutils/DriverTestRunner.go
index 19af308859..ad76c7382e 100644
--- a/plc4go/spi/testutils/DriverTestRunner.go
+++ b/plc4go/spi/testutils/DriverTestRunner.go
@@ -26,6 +26,7 @@ import (
 	"fmt"
 	"os"
 	"runtime/debug"
+	"sort"
 	"strconv"
 	"strings"
 	"testing"
@@ -223,6 +224,8 @@ func (m DriverTestsuite) ExecuteStep(t *testing.T, connection plc4go.PlcConnecti
 						tagValue = append(tagValue, valueChild.Text)
 					}
 					wrb.AddTagAddress(tagName, tagAddress, tagValue)
+				} else if structValue := convertApiRequestStructValue(tagNode.GetChild("value")); structValue != nil {
+					wrb.AddTagAddress(tagName, tagAddress, structValue)
 				} else {
 					tagValue := tagNode.GetChild("value").Text
 					wrb.AddTagAddress(tagName, tagAddress, tagValue)
@@ -259,10 +262,11 @@ func (m DriverTestsuite) ExecuteStep(t *testing.T, connection plc4go.PlcConnecti
 				return errors.Wrap(err, "error serializing response")
 			}
 			actualResponse := xmlWriteBuffer.GetXmlString()
-			// Get the reference XML
-			referenceSerialized := step.payload.XMLPretty()
+			// Compare only the values sections: like on the Java side, the expected XML may
+			// contain a request element whose serialization is implementation-specific.
+			actualSection, referenceSerialized := extractResponseSection(actualResponse, step.payload, "values")
 			// Compare the results
-			err = CompareResults(t, []byte(actualResponse), []byte(referenceSerialized))
+			err = CompareResults(t, []byte(actualSection), []byte(referenceSerialized))
 			if err != nil {
 				return errors.Wrap(err, "Error comparing the results")
 			}
@@ -286,10 +290,11 @@ func (m DriverTestsuite) ExecuteStep(t *testing.T, connection plc4go.PlcConnecti
 				return errors.Wrap(err, "error serializing response")
 			}
 			actualResponse := xmlWriteBuffer.GetXmlString()
-			// Get the reference XML
-			referenceSerialized := step.payload.XMLPretty()
+			// Compare only the response-code sections: like on the Java side, the expected XML
+			// may contain a request element whose serialization is implementation-specific.
+			actualSection, referenceSerialized := extractResponseSection(actualResponse, step.payload, "responseCodes")
 			// Compare the results
-			err = CompareResults(t, []byte(actualResponse), []byte(referenceSerialized))
+			err = CompareResults(t, []byte(actualSection), []byte(referenceSerialized))
 			if err != nil {
 				return errors.Wrap(err, "Error comparing the results")
 			}
@@ -565,6 +570,68 @@ type ConnectionConnectAwaiter interface {
 	SetAwaitDisconnectComplete(awaitComplete bool)
 }
 
+// convertApiRequestStructValue converts a structured api-request value (a PlcStruct element
+// with one member element per property) into the member-name-to-value map form the driver
+// value handlers accept, recursing for nested structs. Plain text values return nil.
+func convertApiRequestStructValue(valueNode *xmldom.Node) any {
+	if valueNode == nil || len(valueNode.Children) != 1 || valueNode.Children[0].Name != "PlcStruct" {
+		return nil
+	}
+	return structValueNodeToMap(valueNode.Children[0])
+}
+
+func structValueNodeToMap(structNode *xmldom.Node) map[string]any {
+	members := map[string]any{}
+	for _, member := range structNode.Children {
+		switch {
+		case len(member.Children) == 1 && member.Children[0].Name == "PlcStruct":
+			members[member.Name] = structValueNodeToMap(member.Children[0])
+		case len(member.Children) == 1:
+			members[member.Name] = member.Children[0].Text
+		default:
+			members[member.Name] = member.Text
+		}
+	}
+	return members
+}
+
+// extractResponseSection narrows an api-response comparison to the named child element
+// (e.g. "values" of a PlcReadResponse), mirroring the Java driver testsuite runner: the
+// reference XML may contain sections (like the request) whose serialization is
+// implementation-specific. When either side lacks the section, both are returned unchanged.
+//
+// Within the section, sibling elements are sorted by name on both sides before comparing:
+// response values are keyed by tag/member name (maps in the API), so their order is not
+// part of the contract and differs between implementations.
+func extractResponseSection(actualResponse string, reference xmldom.Node, sectionName string) (string, string) {
+	referenceSection := reference.GetChild(sectionName)
+	if referenceSection == nil {
+		return actualResponse, reference.XMLPretty()
+	}
+	actualDocument, err := xmldom.Parse(strings.NewReader(actualResponse))
+	if err != nil {
+		return actualResponse, reference.XMLPretty()
+	}
+	actualSection := actualDocument.Root.GetChild(sectionName)
+	if actualSection == nil {
+		return actualResponse, reference.XMLPretty()
+	}
+	sortChildElementsByName(actualSection)
+	sortChildElementsByName(referenceSection)
+	return actualSection.XMLPretty(), referenceSection.XMLPretty()
+}
+
+// sortChildElementsByName recursively brings sibling elements into a canonical (name-sorted)
+// order. Only safe where sibling names are unique keys, as they are in api-response sections.
+func sortChildElementsByName(node *xmldom.Node) {
+	sort.SliceStable(node.Children, func(i, j int) bool {
+		return node.Children[i].Name < node.Children[j].Name
+	})
+	for _, child := range node.Children {
+		sortChildElementsByName(child)
+	}
+}
+
 func ParseDriverTestsuiteXml(t *testing.T, testPath string) *xmldom.Node {
 	// Get the current working directory
 	path, err := os.Getwd()
diff --git a/plc4go/spi/utils/ReadBufferByteBased.go b/plc4go/spi/utils/ReadBufferByteBased.go
index 6f6ea829ce..9cc00d9720 100644
--- a/plc4go/spi/utils/ReadBufferByteBased.go
+++ b/plc4go/spi/utils/ReadBufferByteBased.go
@@ -27,6 +27,7 @@ import (
 	"os"
 	"strconv"
 	"strings"
+	"unicode/utf16"
 
 	"github.com/rs/zerolog/log"
 
@@ -469,19 +470,38 @@ func (rb *byteReadBuffer) ReadBigFloat(logicalName string, bitLength uint8, _ ..
 	return big.NewFloat(readFloat64), nil
 }
 
-func (rb *byteReadBuffer) ReadString(logicalName string, bitLength uint32, _ ...WithReaderArgs) (string, error) {
+func (rb *byteReadBuffer) ReadString(logicalName string, bitLength uint32, readerArgs ...WithReaderArgs) (string, error) {
 	stringBytes, err := rb.ReadByteArray(logicalName, int(bitLength/8))
 	if err != nil {
-		return "", errors.Wrap(err, "Error reading big int")
-	}
-	// TODO: make the null-termination a reader arg
-	// End the string at the 0-character.
-	for i, value := range stringBytes {
-		if value == 0x00 {
-			return string(stringBytes[0:i]), nil
+		return "", errors.Wrap(err, "Error reading string bytes")
+	}
+	encoding := strings.ToUpper(strings.ReplaceAll(BufferCommons{}.ExtractEncoding(UpcastReaderArgs(readerArgs...)...), "-", ""))
+	switch encoding {
+	case "UTF16", "UTF16LE", "UTF16BE":
+		byteOrder := binary.ByteOrder(binary.LittleEndian)
+		if encoding == "UTF16BE" {
+			byteOrder = binary.BigEndian
+		}
+		codeUnits := make([]uint16, 0, len(stringBytes)/2)
+		for i := 0; i+1 < len(stringBytes); i += 2 {
+			codeUnit := byteOrder.Uint16(stringBytes[i : i+2])
+			// End the string at the 0-character.
+			if codeUnit == 0x0000 {
+				break
+			}
+			codeUnits = append(codeUnits, codeUnit)
+		}
+		return string(utf16.Decode(codeUnits)), nil
+	default:
+		// TODO: make the null-termination a reader arg
+		// End the string at the 0-character.
+		for i, value := range stringBytes {
+			if value == 0x00 {
+				return string(stringBytes[0:i]), nil
+			}
 		}
+		return string(stringBytes), nil
 	}
-	return string(stringBytes), nil
 }
 
 func (rb *byteReadBuffer) CloseContext(_ string, _ ...WithReaderArgs) error {
diff --git a/plc4go/spi/utils/WriteBufferXmlBased.go b/plc4go/spi/utils/WriteBufferXmlBased.go
index 8c370f8784..d3ae02aa27 100644
--- a/plc4go/spi/utils/WriteBufferXmlBased.go
+++ b/plc4go/spi/utils/WriteBufferXmlBased.go
@@ -196,16 +196,17 @@ func (x *xmlWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, value
 
 func (x *xmlWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, value float32, writerArgs ...WithWriterArgs) error {
 	x.move(uint(bitLength))
-	// Render the shortest decimal that round-trips back to the same float32, the
-	// way Java's Float.toString does. Printing a fixed 16 fraction digits instead
-	// spells out the full binary expansion (9.87 -> 9.8699998855590820), which no
-	// testsuite reference - all authored against the Java output - can match.
+	// Render the shortest decimal that round-trips back to the same float32. Printing a
+	// fixed number of fraction digits instead spells out the full binary expansion
+	// (9.87 -> 9.8699998855590820), which no testsuite reference can match. Fraction-digit
+	// differences to other implementations (13 vs 13.0) are absorbed by the comparison.
 	return x.encodeElement(logicalName, strconv.FormatFloat(float64(value), 'f', -1, 32), x.generateAttr(rwFloatKey, uint(bitLength), writerArgs...), writerArgs...)
 }
 
 func (x *xmlWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, value float64, writerArgs ...WithWriterArgs) error {
 	x.move(uint(bitLength))
-	return x.encodeElement(logicalName, fmt.Sprintf("%32.32f", value), x.generateAttr(rwFloatKey, uint(bitLength), writerArgs...), writerArgs...)
+	// Shortest round-trip form, for the same reason as WriteFloat32.
+	return x.encodeElement(logicalName, strconv.FormatFloat(value, 'f', -1, 64), x.generateAttr(rwFloatKey, uint(bitLength), writerArgs...), writerArgs...)
 }
 
 func (x *xmlWriteBuffer) WriteBigFloat(logicalName string, bitLength uint8, value *big.Float, writerArgs ...WithWriterArgs) error {
diff --git a/plc4go/spi/values/PlcCHAR.go b/plc4go/spi/values/PlcCHAR.go
index 1129ae4cf5..94eba4bcbf 100644
--- a/plc4go/spi/values/PlcCHAR.go
+++ b/plc4go/spi/values/PlcCHAR.go
@@ -69,7 +69,7 @@ func (m PlcCHAR) Serialize() ([]byte, error) {
 }
 
 func (m PlcCHAR) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcCHAR", 8, m.value)
+	return writeBuffer.WriteString("PlcCHAR", 8, m.value, utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcCHAR) String() string {
diff --git a/plc4go/spi/values/PlcDATE.go b/plc4go/spi/values/PlcDATE.go
index 6e4da89c3b..b419a17eb1 100644
--- a/plc4go/spi/values/PlcDATE.go
+++ b/plc4go/spi/values/PlcDATE.go
@@ -127,7 +127,7 @@ func (m PlcDATE) Serialize() ([]byte, error) {
 }
 
 func (m PlcDATE) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcDATE", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcDATE", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcDATE) String() string {
diff --git a/plc4go/spi/values/PlcDATE_AND_LTIME.go b/plc4go/spi/values/PlcDATE_AND_LTIME.go
index 539cda1eb5..d1c813ba60 100644
--- a/plc4go/spi/values/PlcDATE_AND_LTIME.go
+++ b/plc4go/spi/values/PlcDATE_AND_LTIME.go
@@ -141,7 +141,7 @@ func (m PlcDATE_AND_LTIME) Serialize() ([]byte, error) {
 }
 
 func (m PlcDATE_AND_LTIME) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcDATE_AND_LTIME", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcDATE_AND_LTIME", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcDATE_AND_LTIME) String() string {
diff --git a/plc4go/spi/values/PlcDATE_AND_TIME.go b/plc4go/spi/values/PlcDATE_AND_TIME.go
index 0701990cf0..ca1218d27a 100644
--- a/plc4go/spi/values/PlcDATE_AND_TIME.go
+++ b/plc4go/spi/values/PlcDATE_AND_TIME.go
@@ -127,7 +127,9 @@ func (m PlcDATE_AND_TIME) GetDateTime() time.Time {
 }
 
 func (m PlcDATE_AND_TIME) GetString() string {
-	return fmt.Sprintf("%v", m.GetDateTime())
+	// DATE_AND_TIME is a wall-clock value without a time zone: render the instant's UTC
+	// wall time in ISO-8601, with the fraction only when there is one.
+	return m.GetDateTime().UTC().Format("2006-01-02T15:04:05.999999999")
 }
 
 func (m PlcDATE_AND_TIME) GetPlcValueType() apiValues.PlcValueType {
@@ -143,7 +145,7 @@ func (m PlcDATE_AND_TIME) Serialize() ([]byte, error) {
 }
 
 func (m PlcDATE_AND_TIME) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcDATE_AND_TIME", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcDATE_AND_TIME", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcDATE_AND_TIME) String() string {
diff --git a/plc4go/spi/values/PlcDWORD.go b/plc4go/spi/values/PlcDWORD.go
index 378b189230..5c2cf73a68 100644
--- a/plc4go/spi/values/PlcDWORD.go
+++ b/plc4go/spi/values/PlcDWORD.go
@@ -218,7 +218,7 @@ func (m PlcDWORD) Serialize() ([]byte, error) {
 }
 
 func (m PlcDWORD) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteUint32("PlcDINT", 32, m.value)
+	return writeBuffer.WriteUint32("PlcDWORD", 32, m.value)
 }
 
 func (m PlcDWORD) String() string {
diff --git a/plc4go/spi/values/PlcLDATE.go b/plc4go/spi/values/PlcLDATE.go
index d9aea97f53..9fae901e2f 100644
--- a/plc4go/spi/values/PlcLDATE.go
+++ b/plc4go/spi/values/PlcLDATE.go
@@ -94,7 +94,7 @@ func (m PlcLDATE) Serialize() ([]byte, error) {
 }
 
 func (m PlcLDATE) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcLDATE", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcLDATE", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcLDATE) String() string {
diff --git a/plc4go/spi/values/PlcLDATE_AND_TIME.go b/plc4go/spi/values/PlcLDATE_AND_TIME.go
index c2e80a9eae..11ad576844 100644
--- a/plc4go/spi/values/PlcLDATE_AND_TIME.go
+++ b/plc4go/spi/values/PlcLDATE_AND_TIME.go
@@ -93,7 +93,7 @@ func (m PlcLDATE_AND_TIME) Serialize() ([]byte, error) {
 }
 
 func (m PlcLDATE_AND_TIME) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcLDATE_AND_TIME", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcLDATE_AND_TIME", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcLDATE_AND_TIME) String() string {
diff --git a/plc4go/spi/values/PlcLTIME.go b/plc4go/spi/values/PlcLTIME.go
index 27eefad7e1..f49b985cba 100644
--- a/plc4go/spi/values/PlcLTIME.go
+++ b/plc4go/spi/values/PlcLTIME.go
@@ -70,7 +70,7 @@ func (m PlcLTIME) IsString() bool {
 }
 
 func (m PlcLTIME) GetString() string {
-	return fmt.Sprintf("PT%0.fS", m.GetDuration().Seconds())
+	return formatDurationIso8601(m.GetDuration())
 }
 
 func (m PlcLTIME) GetPlcValueType() apiValues.PlcValueType {
@@ -86,7 +86,7 @@ func (m PlcLTIME) Serialize() ([]byte, error) {
 }
 
 func (m PlcLTIME) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcLTIME", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcLTIME", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcLTIME) String() string {
diff --git a/plc4go/spi/values/PlcLTIME_OF_DAY.go b/plc4go/spi/values/PlcLTIME_OF_DAY.go
index ec72f1a784..c65ebc982f 100644
--- a/plc4go/spi/values/PlcLTIME_OF_DAY.go
+++ b/plc4go/spi/values/PlcLTIME_OF_DAY.go
@@ -99,7 +99,7 @@ func (m PlcLTIME_OF_DAY) Serialize() ([]byte, error) {
 }
 
 func (m PlcLTIME_OF_DAY) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcLTIME_OF_DAY", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcLTIME_OF_DAY", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcLTIME_OF_DAY) String() string {
diff --git a/plc4go/spi/values/PlcSINT.go b/plc4go/spi/values/PlcSINT.go
index 32e2ebea4e..0605f5034a 100644
--- a/plc4go/spi/values/PlcSINT.go
+++ b/plc4go/spi/values/PlcSINT.go
@@ -151,7 +151,7 @@ func (m PlcSINT) Serialize() ([]byte, error) {
 }
 
 func (m PlcSINT) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteInt8("PlcINT", 8, m.value)
+	return writeBuffer.WriteInt8("PlcSINT", 8, m.value)
 }
 
 func (m PlcSINT) String() string {
diff --git a/plc4go/spi/values/PlcSTRING.go b/plc4go/spi/values/PlcSTRING.go
index 003b00e778..5ca4eab578 100644
--- a/plc4go/spi/values/PlcSTRING.go
+++ b/plc4go/spi/values/PlcSTRING.go
@@ -69,7 +69,7 @@ func (m PlcSTRING) Serialize() ([]byte, error) {
 }
 
 func (m PlcSTRING) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcSTRING", uint32(len([]rune(m.value))*8), m.value)
+	return writeBuffer.WriteString("PlcSTRING", uint32(len([]rune(m.value))*8), m.value, utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcSTRING) String() string {
diff --git a/plc4go/spi/values/PlcStruct.go b/plc4go/spi/values/PlcStruct.go
index fa2aa95d10..e2e63d96dd 100644
--- a/plc4go/spi/values/PlcStruct.go
+++ b/plc4go/spi/values/PlcStruct.go
@@ -23,6 +23,7 @@ import (
 	"context"
 	"encoding/binary"
 	"fmt"
+	"sort"
 	"strings"
 
 	"github.com/rs/zerolog/log"
@@ -34,12 +35,47 @@ import (
 
 type PlcStruct struct {
 	values map[string]apiValues.PlcValue
+	// order fixes the member order for GetKeys and serialization: insertion order when
+	// constructed with NewPlcStructOrdered (e.g. the declaration order of a decoded PLC
+	// struct), sorted key order otherwise - never Go's random map iteration order.
+	order []string
 	PlcValueAdapter
 }
 
 func NewPlcStruct(value map[string]apiValues.PlcValue) PlcStruct {
+	order := make([]string, 0, len(value))
+	for key := range value {
+		order = append(order, key)
+	}
+	sort.Strings(order)
 	return PlcStruct{
 		values: value,
+		order:  order,
+	}
+}
+
+// NewPlcStructOrdered creates a PlcStruct whose members keep the given order (usually the
+// struct's declaration order on the PLC). Keys missing from values are ignored; values not
+// listed in order are appended in sorted order.
+func NewPlcStructOrdered(value map[string]apiValues.PlcValue, order []string) PlcStruct {
+	seen := make(map[string]struct{}, len(order))
+	orderedKeys := make([]string, 0, len(value))
+	for _, key := range order {
+		if _, ok := value[key]; ok {
+			orderedKeys = append(orderedKeys, key)
+			seen[key] = struct{}{}
+		}
+	}
+	var rest []string
+	for key := range value {
+		if _, ok := seen[key]; !ok {
+			rest = append(rest, key)
+		}
+	}
+	sort.Strings(rest)
+	return PlcStruct{
+		values: value,
+		order:  append(orderedKeys, rest...),
 	}
 }
 
@@ -67,11 +103,7 @@ func (m PlcStruct) IsStruct() bool {
 }
 
 func (m PlcStruct) GetKeys() []string {
-	var keys []string
-	for k := range m.values {
-		keys = append(keys, k)
-	}
-	return keys
+	return append([]string(nil), m.order...)
 }
 
 func (m PlcStruct) HasKey(key string) bool {
@@ -99,7 +131,8 @@ func (m PlcStruct) IsString() bool {
 func (m PlcStruct) GetString() string {
 	var sb strings.Builder
 	sb.WriteString("PlcStruct{\n")
-	for tagName, tagValue := range m.values {
+	for _, tagName := range m.order {
+		tagValue := m.values[tagName]
 		sb.WriteString("  ")
 		sb.WriteString(tagName)
 		sb.WriteString(": \"")
@@ -130,7 +163,8 @@ func (m PlcStruct) SerializeWithWriteBuffer(ctx context.Context, writeBuffer uti
 	if err := writeBuffer.PushContext("PlcStruct"); err != nil {
 		return err
 	}
-	for tagName, tagValue := range m.values {
+	for _, tagName := range m.order {
+		tagValue := m.values[tagName]
 		if err := writeBuffer.PushContext(tagName); err != nil {
 			return err
 		}
diff --git a/plc4go/spi/values/PlcTIME.go b/plc4go/spi/values/PlcTIME.go
index 67ab66bad0..cf13b1cf33 100644
--- a/plc4go/spi/values/PlcTIME.go
+++ b/plc4go/spi/values/PlcTIME.go
@@ -23,6 +23,8 @@ import (
 	"context"
 	"encoding/binary"
 	"fmt"
+	"strconv"
+	"strings"
 	"time"
 
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
@@ -70,7 +72,76 @@ func (m PlcTIME) IsString() bool {
 }
 
 func (m PlcTIME) GetString() string {
-	return fmt.Sprintf("PT%0.fS", m.GetDuration().Seconds())
+	return formatDurationIso8601(m.GetDuration())
+}
+
+// parseDurationIso8601 parses the time-only ISO-8601 duration form produced by
+// formatDurationIso8601 ("PT24015H23M12.034002044S").
+func parseDurationIso8601(value string) (time.Duration, error) {
+	input := value
+	negative := strings.HasPrefix(input, "-")
+	input = strings.TrimPrefix(input, "-")
+	rest, ok := strings.CutPrefix(input, "PT")
+	if !ok || rest == "" {
+		return 0, fmt.Errorf("invalid ISO-8601 duration %q", value)
+	}
+	var duration time.Duration
+	for _, component := range []struct {
+		designator string
+		unit       time.Duration
+	}{{"H", time.Hour}, {"M", time.Minute}, {"S", time.Second}} {
+		number, remainder, found := strings.Cut(rest, component.designator)
+		if !found {
+			continue
+		}
+		amount, err := strconv.ParseFloat(number, 64)
+		if err != nil {
+			return 0, fmt.Errorf("invalid ISO-8601 duration %q: %v", value, err)
+		}
+		duration += time.Duration(amount * float64(component.unit))
+		rest = remainder
+	}
+	if rest != "" {
+		return 0, fmt.Errorf("invalid ISO-8601 duration %q", value)
+	}
+	if negative {
+		duration = -duration
+	}
+	return duration, nil
+}
+
+// formatDurationIso8601 renders a duration in ISO-8601 form with an hours/minutes/seconds
+// decomposition and the sub-second fraction ("PT24015H23M12.034002044S"), the shared
+// cross-implementation rendering of duration-typed PLC values.
+func formatDurationIso8601(duration time.Duration) string {
+	if duration == 0 {
+		return "PT0S"
+	}
+	var sb strings.Builder
+	if duration < 0 {
+		sb.WriteString("-")
+		duration = -duration
+	}
+	sb.WriteString("PT")
+	totalSeconds := int64(duration / time.Second)
+	nanos := int64(duration % time.Second)
+	hours := totalSeconds / 3600
+	minutes := (totalSeconds % 3600) / 60
+	seconds := totalSeconds % 60
+	if hours != 0 {
+		fmt.Fprintf(&sb, "%dH", hours)
+	}
+	if minutes != 0 {
+		fmt.Fprintf(&sb, "%dM", minutes)
+	}
+	if seconds != 0 || nanos != 0 || (hours == 0 && minutes == 0) {
+		if nanos == 0 {
+			fmt.Fprintf(&sb, "%dS", seconds)
+		} else {
+			fmt.Fprintf(&sb, "%d.%sS", seconds, strings.TrimRight(fmt.Sprintf("%09d", nanos), "0"))
+		}
+	}
+	return sb.String()
 }
 
 func (m PlcTIME) GetPlcValueType() apiValues.PlcValueType {
@@ -86,7 +157,7 @@ func (m PlcTIME) Serialize() ([]byte, error) {
 }
 
 func (m PlcTIME) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcTIME", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcTIME", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcTIME) String() string {
diff --git a/plc4go/spi/values/PlcTIME_OF_DAY.go b/plc4go/spi/values/PlcTIME_OF_DAY.go
index b9e6f47084..d25891f8f8 100644
--- a/plc4go/spi/values/PlcTIME_OF_DAY.go
+++ b/plc4go/spi/values/PlcTIME_OF_DAY.go
@@ -126,7 +126,7 @@ func (m PlcTIME_OF_DAY) Serialize() ([]byte, error) {
 }
 
 func (m PlcTIME_OF_DAY) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcTIME_OF_DAY", uint32(len([]rune(m.GetString()))*8), m.GetString())
+	return writeBuffer.WriteString("PlcTIME_OF_DAY", uint32(len([]rune(m.GetString()))*8), m.GetString(), utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcTIME_OF_DAY) String() string {
diff --git a/plc4go/spi/values/PlcULINT.go b/plc4go/spi/values/PlcULINT.go
index 97a1cee62e..826b86f381 100644
--- a/plc4go/spi/values/PlcULINT.go
+++ b/plc4go/spi/values/PlcULINT.go
@@ -173,7 +173,7 @@ func (m PlcULINT) Serialize() ([]byte, error) {
 }
 
 func (m PlcULINT) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteUint64("PlcUINT", 64, m.value)
+	return writeBuffer.WriteUint64("PlcULINT", 64, m.value)
 }
 
 func (m PlcULINT) String() string {
diff --git a/plc4go/spi/values/PlcValueHandler.go b/plc4go/spi/values/PlcValueHandler.go
index dc4c396689..24dd00a746 100644
--- a/plc4go/spi/values/PlcValueHandler.go
+++ b/plc4go/spi/values/PlcValueHandler.go
@@ -349,20 +349,33 @@ func (m DefaultValueHandler) NewPlcValueFromType(valueType apiValues.PlcValueTyp
 
 	// Temporal Values
 	// - Duration
-	case apiValues.TIME:
+	case apiValues.TIME, apiValues.LTIME:
+		var duration time.Duration
 		if isString {
-			return nil, errors.New("string to IEC61131_TIME conversion not implemented")
+			parsed, err := parseDurationIso8601(stringValue)
+			if err != nil {
+				return nil, errors.Wrap(err, "couldn't parse string value '"+stringValue+"' to a duration")
+			}
+			duration = parsed
 		} else {
 			casted, ok := value.(time.Duration)
 			if !ok {
 				return nil, errors.New("couldn't cast value of type " + reflect.TypeOf(value).Name() + " to time.Duration")
 			}
-			return NewPlcTIME(casted), nil
+			duration = casted
+		}
+		if valueType == apiValues.LTIME {
+			return NewPlcLTIME(duration), nil
 		}
+		return NewPlcTIME(duration), nil
 	// - Date
 	case apiValues.DATE:
 		if isString {
-			return nil, errors.New("string to IEC61131_DATE conversion not implemented")
+			casted, err := time.Parse("2006-01-02", stringValue)
+			if err != nil {
+				return nil, errors.Wrap(err, "couldn't parse string value '"+stringValue+"' to a date")
+			}
+			return NewPlcDATE(casted), nil
 		} else {
 			casted, ok := value.(time.Time)
 			if !ok {
@@ -373,7 +386,11 @@ func (m DefaultValueHandler) NewPlcValueFromType(valueType apiValues.PlcValueTyp
 	// - Time
 	case apiValues.TIME_OF_DAY:
 		if isString {
-			return nil, errors.New("string to IEC61131_TIME_OF_DAY conversion not implemented")
+			casted, err := time.Parse("15:04:05.999999999", stringValue)
+			if err != nil {
+				return nil, errors.Wrap(err, "couldn't parse string value '"+stringValue+"' to a time of day")
+			}
+			return NewPlcTIME_OF_DAY(casted), nil
 		} else {
 			casted, ok := value.(time.Time)
 			if !ok {
@@ -384,7 +401,11 @@ func (m DefaultValueHandler) NewPlcValueFromType(valueType apiValues.PlcValueTyp
 	// - Date and Time
 	case apiValues.DATE_AND_TIME:
 		if isString {
-			return nil, errors.New("string to IEC61131_DATE_AND_TIME conversion not implemented")
+			casted, err := time.Parse("2006-01-02T15:04:05.999999999", stringValue)
+			if err != nil {
+				return nil, errors.Wrap(err, "couldn't parse string value '"+stringValue+"' to a date and time")
+			}
+			return NewPlcDATE_AND_TIME(casted), nil
 		} else {
 			casted, ok := value.(time.Time)
 			if !ok {
diff --git a/plc4go/spi/values/PlcWSTRING.go b/plc4go/spi/values/PlcWSTRING.go
index 5ea495de6d..7e39c608c6 100644
--- a/plc4go/spi/values/PlcWSTRING.go
+++ b/plc4go/spi/values/PlcWSTRING.go
@@ -23,6 +23,7 @@ import (
 	"context"
 	"encoding/binary"
 	"fmt"
+	"unicode/utf16"
 
 	apiValues "github.com/apache/plc4x/plc4go/pkg/api/values"
 	"github.com/apache/plc4x/plc4go/spi/utils"
@@ -69,7 +70,10 @@ func (m PlcWSTRING) Serialize() ([]byte, error) {
 }
 
 func (m PlcWSTRING) SerializeWithWriteBuffer(ctx context.Context, writeBuffer utils.WriteBuffer) error {
-	return writeBuffer.WriteString("PlcSTRING", uint32(len(m.value)*8), m.value)
+	// The bit length is the UTF-16 size of the value including the byte order mark
+	// (2 bytes per code unit plus 2 for the BOM), matching the Java implementation.
+	bitLength := uint32((1 + len(utf16.Encode([]rune(m.value)))) * 16)
+	return writeBuffer.WriteString("PlcWSTRING", bitLength, m.value, utils.WithEncoding("UTF-8"))
 }
 
 func (m PlcWSTRING) String() string {
diff --git a/plc4go/tests/drivers/tests/ads_driver_test.go b/plc4go/tests/drivers/tests/ads_driver_test.go
index 9cee641f37..204de1357b 100644
--- a/plc4go/tests/drivers/tests/ads_driver_test.go
+++ b/plc4go/tests/drivers/tests/ads_driver_test.go
@@ -30,7 +30,6 @@ import (
 )
 
 func TestAdsDriver(t *testing.T) {
-	t.Skip("I have to port the commands for reading the symbol-table first")
 	parser := func(readBufferByteBased utils.ReadBufferByteBased) (any, error) {
 		return readWriteModel.AmsTCPPacketParseWithBuffer(t.Context(), readBufferByteBased)
 	}
diff --git a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/java/ads/AdsDriverIT.java b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/java/ads/AdsDriverIT.java
index f0e567d83b..c984d16442 100644
--- a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/java/ads/AdsDriverIT.java
+++ b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/java/ads/AdsDriverIT.java
@@ -23,7 +23,7 @@ import org.apache.plc4x.java.utils.testutils.driver.DriverTestsuiteRunner;
 public class AdsDriverIT extends DriverTestsuiteRunner {
 
     public AdsDriverIT() {
-        super("/protocols/ads/DriverTestsuite.xml", "org.apache.plc4x.java.ads.readwrite", true);
+        super("/protocols/ads/DriverTestsuite.xml", "org.apache.plc4x.java.ads.readwrite", false);
     }
 
 }
diff --git a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
index 2348e70f3c..6b828d3aad 100644
--- a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
+++ b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcBYTE.java
@@ -291,7 +291,8 @@ public class PlcBYTE extends PlcIECValue<Short> {
 
     @Override
     public void serialize(WriteBuffer writeBuffer) throws BufferException {
-        writeBuffer.writeSignedShort(8, value, WithOption.WithName(getClass().getSimpleName()));
+        // A BYTE is a bit string, not a number: render it the way byte fields render (0x..).
+        writeBuffer.writeBits(8, new byte[]{(byte) (value & 0xFF)}, WithOption.WithName(getClass().getSimpleName()));
     }
 
 }
diff --git a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
index cd456d6abf..b78398c811 100644
--- a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
+++ b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcDWORD.java
@@ -294,7 +294,7 @@ public class PlcDWORD extends PlcIECValue<Long> {
 
     @Override
     public void serialize(WriteBuffer writeBuffer) throws BufferException {
-        writeBuffer.writeSignedLong(32, value, WithOption.WithName(getClass().getSimpleName()));
+        writeBuffer.writeUnsignedLong(32, value, WithOption.WithName(getClass().getSimpleName()));
     }
 
 }
diff --git a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
index 4ea7931670..06bacfb7b3 100644
--- a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
+++ b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcLWORD.java
@@ -308,7 +308,7 @@ public class PlcLWORD extends PlcIECValue<BigInteger> {
 
     @Override
     public void serialize(WriteBuffer writeBuffer) throws BufferException {
-        writeBuffer.writeSignedBigInteger(64, value, WithOption.WithName(getClass().getSimpleName()));
+        writeBuffer.writeUnsignedBigInteger(64, value, WithOption.WithName(getClass().getSimpleName()));
     }
 
 }
diff --git a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME.java b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME.java
index 98acb6cb03..31fdd0c7d8 100644
--- a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME.java
+++ b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcTIME.java
@@ -168,7 +168,10 @@ public class PlcTIME extends PlcIECValue<Duration> {
 
     @Override
     public void serialize(WriteBuffer writeBuffer) throws BufferException {
-        writeBuffer.writeSignedLong(32, value.toMillis(), WithOption.WithName(getClass().getSimpleName()));
+        // Durations render as ISO-8601 (like PlcLTIME), not as a raw millisecond count.
+        String valueString = value.toString();
+        writeBuffer.writeString(valueString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length * 8,
+            valueString, WithOption.WithName(getClass().getSimpleName()), WithOption.WithEncoding("UTF8"));
     }
 
 }
diff --git a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
index 7909e13a4e..1325d99c60 100644
--- a/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
+++ b/plc4j/spi/values/src/main/java/org/apache/plc4x/java/spi/values/PlcWORD.java
@@ -288,7 +288,7 @@ public class PlcWORD extends PlcIECValue<Integer> {
 
     @Override
     public void serialize(WriteBuffer writeBuffer) throws BufferException {
-        writeBuffer.writeSignedInt(16, value, WithOption.WithName(getClass().getSimpleName()));
+        writeBuffer.writeUnsignedInt(16, value, WithOption.WithName(getClass().getSimpleName()));
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/driver/internal/handlers/ApiResponseHandler.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/driver/internal/handlers/ApiResponseHandler.java
index 89fc7c09ad..afd14f7c2e 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/driver/internal/handlers/ApiResponseHandler.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/driver/internal/handlers/ApiResponseHandler.java
@@ -237,7 +237,7 @@ public class ApiResponseHandler {
         // Handle RAW_BYTE_ARRAY first since it reports isList()=true but should be serialized as a hex string
         if (plcValueType == PlcValueType.RAW_BYTE_ARRAY) {
             Element valueElement = parentElement.addElement("PlcRAW_BYTE_ARRAY");
-            addTypeAttributes(valueElement, plcValueType);
+            addTypeAttributes(valueElement, plcValueType, value.toString());
             valueElement.setText(value.toString());
         } else if (value.isStruct()) {
             Element structElement = parentElement.addElement("PlcStruct");
@@ -255,25 +255,35 @@ public class ApiResponseHandler {
             String typeName = (plcValueType != null) ? "Plc" + plcValueType.name() : "PlcValue";
             Element valueElement = parentElement.addElement(typeName);
 
+            // A BYTE is a bit string, not a number: render it the way byte fields render (0x..).
+            String text = (plcValueType == PlcValueType.BYTE)
+                ? String.format("0x%02x", value.getShort() & 0xFF)
+                : value.toString();
+
             // Add dataType and bitLength attributes based on the PlcValueType
             if (plcValueType != null) {
-                addTypeAttributes(valueElement, plcValueType);
+                addTypeAttributes(valueElement, plcValueType, text);
             }
 
-            valueElement.setText(value.toString());
+            valueElement.setText(text);
         }
     }
 
     /**
      * Adds dataType and bitLength attributes to an element based on the PlcValueType.
+     * The rendered text is passed in for the types whose bit length derives from it.
      */
-    private void addTypeAttributes(Element element, PlcValueType plcValueType) {
+    private void addTypeAttributes(Element element, PlcValueType plcValueType, String text) {
         switch (plcValueType) {
             case BOOL -> {
                 element.addAttribute("dataType", "bit");
                 element.addAttribute("bitLength", "1");
             }
-            case BYTE, USINT -> {
+            case BYTE -> {
+                element.addAttribute("dataType", "byte");
+                element.addAttribute("bitLength", "8");
+            }
+            case USINT -> {
                 element.addAttribute("dataType", "uint");
                 element.addAttribute("bitLength", "8");
             }
@@ -313,12 +323,18 @@ public class ApiResponseHandler {
                 element.addAttribute("dataType", "float");
                 element.addAttribute("bitLength", "64");
             }
-            case STRING, WSTRING, CHAR, WCHAR -> {
+            case WSTRING -> {
                 element.addAttribute("dataType", "string");
+                // UTF-16 size of the value including the byte order mark.
+                element.addAttribute("bitLength", String.valueOf((text.codePointCount(0, text.length()) + 1) * 16));
                 element.addAttribute("encoding", "UTF-8");
             }
-            case TIME, LTIME, DATE, LDATE, TIME_OF_DAY, LTIME_OF_DAY, DATE_AND_TIME, LDATE_AND_TIME, DATE_AND_LTIME -> {
-                element.addAttribute("dataType", "time");
+            case STRING, CHAR, WCHAR,
+                 // Temporal values render as their ISO-8601 string form.
+                 TIME, LTIME, DATE, LDATE, TIME_OF_DAY, LTIME_OF_DAY, DATE_AND_TIME, LDATE_AND_TIME, DATE_AND_LTIME -> {
+                element.addAttribute("dataType", "string");
+                element.addAttribute("bitLength", String.valueOf(text.getBytes(java.nio.charset.StandardCharsets.UTF_8).length * 8));
+                element.addAttribute("encoding", "UTF-8");
             }
             case RAW_BYTE_ARRAY -> {
                 element.addAttribute("dataType", "byte");
diff --git a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
index 33d0248a5e..021ce08bfc 100644
--- a/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
+++ b/protocols/ads/src/test/resources/protocols/ads/DriverTestsuite.xml
@@ -1206,72 +1206,72 @@
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
                   <PlcStruct>
-                    <hurz_STRING>
-                      <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
-                    </hurz_STRING>
-                    <hurz_LTIME>
-                      <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
-                    </hurz_LTIME>
+                    <hurz_BOOL>
+                      <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
+                    </hurz_BOOL>
+                    <hurz_BYTE>
+                      <PlcBYTE dataType="byte" bitLength="8">0x01</PlcBYTE>
+                    </hurz_BYTE>
+                    <hurz_WORD>
+                      <PlcWORD dataType="uint" bitLength="16">2</PlcWORD>
+                    </hurz_WORD>
+                    <hurz_DWORD>
+                      <PlcDWORD dataType="uint" bitLength="32">3</PlcDWORD>
+                    </hurz_DWORD>
                     <hurz_LWORD>
-                      <PlcLWORD dataType="int" bitLength="64">4</PlcLWORD>
+                      <PlcLWORD dataType="uint" bitLength="64">4</PlcLWORD>
                     </hurz_LWORD>
-                    <hurz_REAL>
-                      <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
-                    </hurz_REAL>
-                    <hurz_ULINT>
-                      <PlcULINT dataType="int" bitLength="64">12</PlcULINT>
-                    </hurz_ULINT>
-                    <hurz_WSTRING>
-                      <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
-                    </hurz_WSTRING>
-                    <hurz_LINT>
-                      <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
-                    </hurz_LINT>
-                    <hurz_DATE_AND_TIME>
-                      <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
-                    </hurz_DATE_AND_TIME>
-                    <hurz_UINT>
-                      <PlcUINT dataType="int" bitLength="16">8</PlcUINT>
-                    </hurz_UINT>
                     <hurz_SINT>
                       <PlcSINT dataType="int" bitLength="8">5</PlcSINT>
                     </hurz_SINT>
                     <hurz_USINT>
-                      <PlcUSINT dataType="int" bitLength="8">6</PlcUSINT>
+                      <PlcUSINT dataType="uint" bitLength="8">6</PlcUSINT>
                     </hurz_USINT>
-                    <hurz_LREAL>
-                      <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
-                    </hurz_LREAL>
-                    <hurz_TIME_OF_DAY>
-                      <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
-                    </hurz_TIME_OF_DAY>
-                    <hurz_BOOL>
-                      <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
-                    </hurz_BOOL>
+                    <hurz_INT>
+                      <PlcINT dataType="int" bitLength="16">7</PlcINT>
+                    </hurz_INT>
+                    <hurz_UINT>
+                      <PlcUINT dataType="uint" bitLength="16">8</PlcUINT>
+                    </hurz_UINT>
                     <hurz_DINT>
                       <PlcDINT dataType="int" bitLength="32">9</PlcDINT>
                     </hurz_DINT>
                     <hurz_UDINT>
-                      <PlcUDINT dataType="int" bitLength="32">10</PlcUDINT>
+                      <PlcUDINT dataType="uint" bitLength="32">10</PlcUDINT>
                     </hurz_UDINT>
-                    <hurz_BYTE>
-                      <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
-                    </hurz_BYTE>
+                    <hurz_LINT>
+                      <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
+                    </hurz_LINT>
+                    <hurz_ULINT>
+                      <PlcULINT dataType="uint" bitLength="64">12</PlcULINT>
+                    </hurz_ULINT>
+                    <hurz_REAL>
+                      <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
+                    </hurz_REAL>
+                    <hurz_LREAL>
+                      <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
+                    </hurz_LREAL>
                     <hurz_TIME>
-                      <PlcTIME dataType="int" bitLength="32">1234</PlcTIME>
+                      <PlcTIME dataType="string" bitLength="64" encoding="UTF-8">PT1.234S</PlcTIME>
                     </hurz_TIME>
-                    <hurz_DWORD>
-                      <PlcDWORD dataType="int" bitLength="32">3</PlcDWORD>
-                    </hurz_DWORD>
-                    <hurz_INT>
-                      <PlcINT dataType="int" bitLength="16">7</PlcINT>
-                    </hurz_INT>
-                    <hurz_WORD>
-                      <PlcWORD dataType="int" bitLength="16">2</PlcWORD>
-                    </hurz_WORD>
+                    <hurz_LTIME>
+                      <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
+                    </hurz_LTIME>
                     <hurz_DATE>
                       <PlcDATE dataType="string" bitLength="80" encoding="UTF-8">1978-03-28</PlcDATE>
                     </hurz_DATE>
+                    <hurz_TIME_OF_DAY>
+                      <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
+                    </hurz_TIME_OF_DAY>
+                    <hurz_DATE_AND_TIME>
+                      <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
+                    </hurz_DATE_AND_TIME>
+                    <hurz_STRING>
+                      <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
+                    </hurz_STRING>
+                    <hurz_WSTRING>
+                      <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
+                    </hurz_WSTRING>
                   </PlcStruct>
                 </value>
               </PlcResponseItem>
@@ -1305,72 +1305,72 @@
               <address>MAIN.hurz_Struct</address>
               <value>
                 <PlcStruct>
-                  <hurz_STRING>
-                    <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
-                  </hurz_STRING>
-                  <hurz_LTIME>
-                    <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
-                  </hurz_LTIME>
+                  <hurz_BOOL>
+                    <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
+                  </hurz_BOOL>
+                  <hurz_BYTE>
+                    <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
+                  </hurz_BYTE>
+                  <hurz_WORD>
+                    <PlcWORD dataType="uint" bitLength="16">2</PlcWORD>
+                  </hurz_WORD>
+                  <hurz_DWORD>
+                    <PlcDWORD dataType="uint" bitLength="32">3</PlcDWORD>
+                  </hurz_DWORD>
                   <hurz_LWORD>
-                    <PlcLWORD dataType="int" bitLength="64">4</PlcLWORD>
+                    <PlcLWORD dataType="uint" bitLength="64">4</PlcLWORD>
                   </hurz_LWORD>
-                  <hurz_REAL>
-                    <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
-                  </hurz_REAL>
-                  <hurz_ULINT>
-                    <PlcULINT dataType="int" bitLength="64">12</PlcULINT>
-                  </hurz_ULINT>
-                  <hurz_WSTRING>
-                    <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
-                  </hurz_WSTRING>
-                  <hurz_LINT>
-                    <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
-                  </hurz_LINT>
-                  <hurz_DATE_AND_TIME>
-                    <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
-                  </hurz_DATE_AND_TIME>
-                  <hurz_UINT>
-                    <PlcUINT dataType="int" bitLength="16">8</PlcUINT>
-                  </hurz_UINT>
                   <hurz_SINT>
                     <PlcSINT dataType="int" bitLength="8">5</PlcSINT>
                   </hurz_SINT>
                   <hurz_USINT>
-                    <PlcUSINT dataType="int" bitLength="8">6</PlcUSINT>
+                    <PlcUSINT dataType="uint" bitLength="8">6</PlcUSINT>
                   </hurz_USINT>
-                  <hurz_LREAL>
-                    <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
-                  </hurz_LREAL>
-                  <hurz_TIME_OF_DAY>
-                    <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
-                  </hurz_TIME_OF_DAY>
-                  <hurz_BOOL>
-                    <PlcBOOL dataType="bit" bitLength="1">true</PlcBOOL>
-                  </hurz_BOOL>
+                  <hurz_INT>
+                    <PlcINT dataType="int" bitLength="16">7</PlcINT>
+                  </hurz_INT>
+                  <hurz_UINT>
+                    <PlcUINT dataType="uint" bitLength="16">8</PlcUINT>
+                  </hurz_UINT>
                   <hurz_DINT>
                     <PlcDINT dataType="int" bitLength="32">9</PlcDINT>
                   </hurz_DINT>
                   <hurz_UDINT>
-                    <PlcUDINT dataType="int" bitLength="32">10</PlcUDINT>
+                    <PlcUDINT dataType="uint" bitLength="32">10</PlcUDINT>
                   </hurz_UDINT>
-                  <hurz_BYTE>
-                    <PlcBYTE dataType="int" bitLength="8">1</PlcBYTE>
-                  </hurz_BYTE>
+                  <hurz_LINT>
+                    <PlcLINT dataType="int" bitLength="64">11</PlcLINT>
+                  </hurz_LINT>
+                  <hurz_ULINT>
+                    <PlcULINT dataType="uint" bitLength="64">12</PlcULINT>
+                  </hurz_ULINT>
+                  <hurz_REAL>
+                    <PlcREAL dataType="float" bitLength="32">13.0</PlcREAL>
+                  </hurz_REAL>
+                  <hurz_LREAL>
+                    <PlcLREAL dataType="float" bitLength="64">14.0</PlcLREAL>
+                  </hurz_LREAL>
                   <hurz_TIME>
                     <PlcTIME dataType="string" bitLength="64" encoding="UTF-8">PT1.234S</PlcTIME>
                   </hurz_TIME>
-                  <hurz_DWORD>
-                    <PlcDWORD dataType="int" bitLength="32">3</PlcDWORD>
-                  </hurz_DWORD>
-                  <hurz_INT>
-                    <PlcINT dataType="int" bitLength="16">7</PlcINT>
-                  </hurz_INT>
-                  <hurz_WORD>
-                    <PlcWORD dataType="int" bitLength="16">2</PlcWORD>
-                  </hurz_WORD>
+                  <hurz_LTIME>
+                    <PlcLTIME dataType="string" bitLength="192" encoding="UTF-8">PT24015H23M12.034002044S</PlcLTIME>
+                  </hurz_LTIME>
                   <hurz_DATE>
                     <PlcDATE dataType="string" bitLength="80" encoding="UTF-8">1978-03-28</PlcDATE>
                   </hurz_DATE>
+                  <hurz_TIME_OF_DAY>
+                    <PlcTIME_OF_DAY dataType="string" bitLength="96" encoding="UTF-8">15:36:30.123</PlcTIME_OF_DAY>
+                  </hurz_TIME_OF_DAY>
+                  <hurz_DATE_AND_TIME>
+                    <PlcDATE_AND_TIME dataType="string" bitLength="152" encoding="UTF-8">1996-05-06T15:36:30</PlcDATE_AND_TIME>
+                  </hurz_DATE_AND_TIME>
+                  <hurz_STRING>
+                    <PlcSTRING dataType="string" bitLength="32" encoding="UTF-8">hurz</PlcSTRING>
+                  </hurz_STRING>
+                  <hurz_WSTRING>
+                    <PlcWSTRING dataType="string" bitLength="80" encoding="UTF-8">wolf</PlcWSTRING>
+                  </hurz_WSTRING>
                 </PlcStruct>
               </value>
             </tag>
diff --git a/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverNMTIT.xml b/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverNMTIT.xml
index 9855becb85..716dbc1771 100644
--- a/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverNMTIT.xml
+++ b/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverNMTIT.xml
@@ -100,7 +100,7 @@
                         </CANOpenNMTTag>
                       </tag>
                       <value>
-                        <PlcUSINT dataType="int" bitLength="8">128</PlcUSINT>
+                        <PlcUSINT dataType="uint" bitLength="8">128</PlcUSINT>
                       </value>
                     </PlcTagValueItem>
                   </boot_up_request>
diff --git a/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverSDOIT.xml b/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverSDOIT.xml
index e3d7300fb2..89a19be36b 100644
--- a/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverSDOIT.xml
+++ b/protocols/canopen/src/test/resources/protocols/canopen/CANOpenDriverSDOIT.xml
@@ -208,7 +208,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">1717859169</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">1717859169</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </expeditedSdo>
@@ -343,7 +343,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUSINT dataType="int" bitLength="8">97</PlcUSINT>
+                  <PlcUSINT dataType="uint" bitLength="8">97</PlcUSINT>
                 </value>
               </PlcResponseItem>
             </expeditedShort>
@@ -525,7 +525,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">1717859169</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">1717859169</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </expeditedSdoCustomAnswer>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml b/protocols/modbus/src/test/resources/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
index 58ab5c62e0..1a1ce25989 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/tcp/ManualFactoryModbusTCPDriverTest-testsuite.xml
@@ -129,7 +129,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="uint" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </holding-register_2_BYTE>
@@ -1064,7 +1064,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="uint" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </holding-register_2_BYTE>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml b/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
index 7804ad4fc3..a875b5f4d5 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes-little-endian.xml
@@ -313,7 +313,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -401,7 +401,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                        <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -506,7 +506,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                  <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -594,7 +594,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                        <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -699,7 +699,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                  <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -789,7 +789,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                        <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1087,7 +1087,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                  <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1175,7 +1175,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                        <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1473,7 +1473,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                  <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1561,7 +1561,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                        <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1861,7 +1861,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1951,7 +1951,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                        <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -2251,7 +2251,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                  <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -2341,7 +2341,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                        <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
diff --git a/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes.xml b/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes.xml
index 1c5b7da057..31b5d343cd 100644
--- a/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes.xml
+++ b/protocols/modbus/src/test/resources/protocols/modbus/tcp/Modbus-all-datatypes.xml
@@ -307,7 +307,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                  <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -395,7 +395,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcBYTE dataType="int" bitLength="8">42</PlcBYTE>
+                        <PlcBYTE dataType="byte" bitLength="8">0x2a</PlcBYTE>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -500,7 +500,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                  <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -588,7 +588,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcWORD dataType="int" bitLength="16">42424</PlcWORD>
+                        <PlcWORD dataType="uint" bitLength="16">42424</PlcWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -693,7 +693,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                  <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -783,7 +783,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcDWORD dataType="int" bitLength="32">4242442424</PlcDWORD>
+                        <PlcDWORD dataType="uint" bitLength="32">4242442424</PlcDWORD>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1081,7 +1081,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                  <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1169,7 +1169,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUSINT dataType="int" bitLength="8">42</PlcUSINT>
+                        <PlcUSINT dataType="uint" bitLength="8">42</PlcUSINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1467,7 +1467,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                  <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1555,7 +1555,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUINT dataType="int" bitLength="16">42424</PlcUINT>
+                        <PlcUINT dataType="uint" bitLength="16">42424</PlcUINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -1855,7 +1855,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                  <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -1945,7 +1945,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcUDINT dataType="int" bitLength="32">4242442424</PlcUDINT>
+                        <PlcUDINT dataType="uint" bitLength="32">4242442424</PlcUDINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>
@@ -2245,7 +2245,7 @@
               <PlcResponseItem>
                 <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
                 <value>
-                  <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                  <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                 </value>
               </PlcResponseItem>
             </hurz>
@@ -2335,7 +2335,7 @@
                         </ModbusTagHoldingRegister>
                       </tag>
                       <value>
-                        <PlcULINT dataType="int" bitLength="64">4242442424242424242</PlcULINT>
+                        <PlcULINT dataType="uint" bitLength="64">4242442424242424242</PlcULINT>
                       </value>
                     </PlcTagValueItem>
                   </hurz>