diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8761e98
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,9 @@
+* text=auto
+*.py text eol=lf
+*.c text eol=lf
+*.h text eol=lf
+*.m4 text eol=lf
+*.md text eol=lf
+*.so binary
+*.precompilecache binary
+*.library binary
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..82d6b34
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+# Native build outputs
+component-source/component/out/
+component-source/component/*.o
+component-source/tests/driver
+component-source/tests/bridge_driver
+component-source/tests/test_bridge
+__pycache__/
+*.pyc
+# CODESYS local working caches
+*.precompilecache
+*.compileinfo
+*.bootinfo
+*.bak
+*.opt
+# Keep the supplied cache as a reference artifact
+!artifacts/arm64/CmpAtomModbus_library.precompilecache
diff --git a/README.md b/README.md
index 1d2fce1..a3ee7b3 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,37 @@
-# atMb — documented working library
+# Atom Modbus Library (`atMb`)
-Start with `library/atMb-Documented.export`: comments-only documentation of your
-working CmpAtomModbus export, retaining its embedded C library object. It uses
-`ClientTCP`, matching the uploaded working interface.
+CODESYS library with a native C engine for Modbus TCP client, RTU client and TCP
+slave operation. Public namespace: `atMb`. No ModbusFB dependency is required.
-Read `docs/USER-GUIDE.md` for setup and examples and `docs/API-REFERENCE.md` for
-all 95 code objects, parameters, outputs, methods and properties.
-`docs/DOCUMENTATION-VALIDATION.md` records code/payload preservation checks.
-`reference/Working-CmpAtomModbus.export` is the exact uploaded original.
+## Use the library
-The earlier development export and generator are retained for source history.
-`library/build_native_export.py` generates the earlier migration export; it does
-not generate or supersede the newly documented working export. Do not overwrite
-working IDE changes by regenerating that migration export. The documentation
-adds no C changes; the source-to-uploaded-binary match remains unverified.
+Open `library/CmpAtomModbus.library` in CODESYS, or install it using Library
+Repository and reference it from your application. Keep its project title and
+external C interface settings intact. The development target is Raspberry Pi
+64 SL (ARM64), using CODESYS 3.5 SP22; runtime/target compatibility must be checked
+when changing platforms. Read [the user guide](docs/USER-GUIDE.md) for examples
+and [the API reference](docs/API-REFERENCE.md) for members and methods.
-The rest of the source/build kit remains below.
+## Repository contents
-# atMb — native Modbus for CODESYS
+| Path | Purpose |
+|---|---|
+| `library/CmpAtomModbus.library` | Working CODESYS library file; edit IEC code here |
+| `component-source/src/` | C protocol, client, serial and server implementation |
+| `component-source/component/` | Active component frame, ABI interface and makefile |
+| `component-source/tests/` | Host protocol and bridge tests |
+| `ExtensionSDK/` | Supplied SDK required for component builds |
+| `artifacts/arm64/libCmpAtomModbus.so` | Supplied ARM64 native binary |
+| `docs/BUILD-AND-USAGE.md` | Native build and deployment instructions |
+| `docs/USER-GUIDE.md` | Calling patterns, configuration and diagnostics |
+| `docs/API-REFERENCE.md` | Detailed IEC reference based on the last working export |
+| `docs/CLEANUP.md` | Removed files, preservation checks and update workflow |
+| `docs/VALIDATION.md` | Validation scope |
+| `SHA256SUMS.txt` | Current working-file snapshot checksums, excluding Git metadata |
-Git-ready source snapshot, revision 0.9.1. Public namespace `atMb`.
-C implementation supports TCP client, RTU client and TCP slave; IEC code has
-no ModbusFB dependency. Online-change support remains future work.
+## Build on the Pi
-## Files
-
-- `component-source/`: C engine, CODESYS component frame/interface and host tests.
-- `ExtensionSDK/`: supplied SDK used by the component build.
-- `library/atMb-Native.export`: corrected IEC import; includes public status declarations.
-- `library/atMb-Native-Review.st`: readable generated IEC source.
-- `library/build_native_export.py`: reproducible export generator.
-- `reference/CmpAtomModbus-AllInOne.export`: required generator baseline, not the final import.
-- `artifacts/arm64/`: your uploaded shared object and precompile cache, preserved unchanged.
-- `docs/BUILD-AND-USAGE.md`: import, deployment, API, diagnostics and limitations.
-- `SHA256SUMS.txt`: snapshot file checksums.
-
-## Build and test on the Pi
+Run from the repository root:
```sh
sudo apt install build-essential m4 dos2unix python3
@@ -44,38 +40,21 @@ make -C component-source/component SDKDIR="$(realpath ExtensionSDK)" all
make -C component-source test
```
-Build natively for each Linux target architecture; the uploaded ARM64 `.so`
-cannot run on ARM32 or x86-64. Runtime/SDK compatibility must also be checked
-for each CODESYS target. The host tests exercise protocol code independently
-of the CODESYS runtime.
+Native output: `component-source/component/out/libCmpAtomModbus.so`.
+See the build guide before updating the embedded component. An ARM64 binary
+cannot run on ARM32 or x86-64; build for each architecture and verify the SDK/runtime
+combination. The supplied binary has not been proven byte-equivalent to this source.
-## IEC export
+## Update and review
-```sh
-python3 library/build_native_export.py
-```
+Edit the IEC library in CODESYS. After significant IEC changes, export the current
+objects and update the API reference against that export. Binary `.library` files
+cannot be reviewed as ordinary text diffs. This snapshot intentionally contains no
+old migration exports or generators that overwrite current IDE changes.
-Import `library/atMb-Native.export` into a fresh CODESYS library project,
-namespace `atMb`, and embed the newly built `.so` in a C Implemented Library
-object. See the full instructions in `docs/BUILD-AND-USAGE.md`.
-The export is source, not a compiled `.library`. The supplied precompile cache
-is an opaque reference artifact and is not a substitute for the library project.
+This ZIP retains the existing Git history and remote metadata. Cleanup changes
+are uncommitted and unstaged. Review locally with `git status` and `git diff`,
+then stage/commit when ready. No push is performed by this package.
-Your uploaded `.so` is ARM64 and contains RTU/server symbols. Its exact match
-to this source snapshot and its operation in the runtime have not been verified;
-rebuild from source before making a release. The older development instructions
-say no prebuilt binary is included: that applies to the earlier kit; this repo
-snapshot adds your uploaded binary under `artifacts/arm64/`.
-
-## Start a repository
-
-```sh
-cd atMb-repo
-git init
-git add .
-git commit -m "Initial atMb native Modbus source"
-```
-
-No Git history or remote is included. The SDK and baseline came from supplied
-files; review their redistribution terms before publishing a public repository.
-No new license is assigned by this snapshot.
+Online-change qualification remains future work. Keep all native calls owned by
+one IEC task. No new license is assigned to the supplied SDK/source files.
diff --git a/SHA256SUMS.txt b/SHA256SUMS.txt
index 977275c..c99521e 100644
--- a/SHA256SUMS.txt
+++ b/SHA256SUMS.txt
@@ -1,5 +1,5 @@
d1192772047955638e8bb171080ed9b37e10683de935e4e0503c93b6d26f03fc .gitattributes
-675d431f63e2c212360b692b18de50a344aed5664d17b3683f0b687b96479f24 .gitignore
+02f0eff1a80c9a8f2fe037d1b5980eb391b65e4dc07dba6fe5d109b08c180c1a .gitignore
0ac6e4fe82a82d1bd27ff20dec2f18820c0e0a5057cd0cb1a8020f6dc506603f ExtensionSDK/README
1cc355e875e572de3829d28bff9c100a4eecbfd741d938654be97881023c84d5 ExtensionSDK/include/CmpErrors.h
2010310fbeb8b4734e638610d2f6dc01b600fe42b8b104155806ef0784e95f2d ExtensionSDK/include/CmpItf.h
@@ -10,16 +10,13 @@ a8de018bfde8d10d3f281bb45de03c4b4f3cd28466eb0fa0981086bc4033a69c ExtensionSDK/i
814d06ca83d775f3bcb93f80859602b6c1debe9511b3d42ef337948bd2e2b5d0 ExtensionSDK/makefile
4fc8013238169e924ee2eb5dd6c2b39c9d274f4c7c2219dc0b9a530687097519 ExtensionSDK/makefile_template
aa7ccad11508ccbf4f9b24aa8db8f22392f9d723ae3af5cbfa67e38271cfbac3 ExtensionSDK/src/CmpFrame.c
-67076180ec906d9f27f5b63406d8a2701faa58771f76e0f4487ae750660ce7e4 README.md
-f0279c023b82eeda388cdc1b9c9f358b7794869360a06684df670cd34d5cab56 artifacts/arm64/CmpAtomModbus_library.precompilecache
+11aee0c6ff01eaff1aac5aa46c470ea8367d5eae655068320869a1bcdce1ef53 README.md
07527262a8efcf9add5554cfcaed22cf927af63b985e431ab5341078a6864667 artifacts/arm64/libCmpAtomModbus.so
14db5bb96e65494eed63da0139b37734dfc08e312a3cb0924ad10b7d9476d442 component-source/Makefile
d91cffa9751bca79f13ae80552d654519333536c894bb13b41a1182c179c53b7 component-source/component/CmpAtomModbus.c
30a8d7d5dfd372d171d4acdafd0b77cedca684e0b6e661ae1ab67e2627d35708 component-source/component/CmpAtomModbusItf.m4
513586eed183bcc53cdf008c483da03feff6b5cb0f3ed3eff17de1462def12c3 component-source/component/CmpFrame.c
0972948a5cc88892421433fb01875f4f51609cda3b0df57ff58f05c61390e1c2 component-source/component/makefile
-c362c04636cb2cfc00eec8800f0aa9631709cd9eba76b66332f61a988823a055 component-source/generated/CmpAtomModbus.c
-fa9b00a24ff9f24b63c9a08b8eba4d585a23f4fd6e19f990ec36dcc70f745427 component-source/generated/CmpAtomModbusItf.m4
78240595fa115d3706cbc7316bdcd4e0101a3269e5faacce98826bc32143e9d9 component-source/src/atom_bridge.c
4a3eaca066d0c06ac7fa95d802ff78b270a1ccdc3fc67c6a072b7e09efba08c0 component-source/src/atom_bridge.h
4f772a0dab94053bfa2f073f6877ec63a8c6b7999d8e3415160705db441f6068 component-source/src/atom_mb.c
@@ -33,16 +30,9 @@ d770393632f9d3d1acddf229f562148648792398a39d90851aa529d2923f8382 component-sour
3af1a5f71d69bae2abda3de9dba31740ad254d7157d702847fb921fc2b64df3d component-source/tests/test_bridge.c
2a4b582bed0404f865f4fa2c905dd251c3dccfc4961f20467723c7349793a7f2 component-source/tests/test_native.py
0cf8f8fefda6376cacf0c56729d24aaa76241e807b0dee0b36001b3ad3cea509 component-source/tests/test_tcp.py
-c1f09f7498453182f7ed88c1cb343b637ca6c6507e728ac71591a826588c0d3a docs/API-REFERENCE.md
-a3cd41084413b1f7c2045e6a7a647b793c8df1c9fa338e146439031b269a1dcb docs/BUILD-AND-USAGE.md
-17d84b44d288b46012d9e52d7c8a247592ad28f3d5c3032fffbab701a8478418 docs/DOCUMENTATION-VALIDATION.md
-3a2d04af7a1fc7f2e39fea1401d12653fda16864cf4cb7d8edfe2d9988091453 docs/USER-GUIDE.md
-fe7df15839ff4bcf3272cbec71cd67a026e514c79df4bd0be829c8a373391f4d docs/VALIDATION.md
-8aa5a11a22263ea04902ce883b14fd31c3de270c711deca13f57889a05b689a0 docs/document_export.py
-87e2f904f08d7ee8c37ba8362989d2453b2860e91336f21623d0ab91eb8a178b library/atMb-Documented-Review.st
-19a979f94b437fc6c523fdfbd24fd8f6038860cb107b45dea2466020e2a319fe library/atMb-Documented.export
-0efb6d1760ea5104331cd0fb13b7324fd468c5ab2ec415f0dd9e38db74961e70 library/atMb-Native-Review.st
-e2223cf6cef8cecb71cd41093c67f095559764eaa52e22f0f31347e3faec7238 library/atMb-Native.export
-1d66a3b8cefa95e39815b12d1e802192b83d416ad281aaca5b8efa8c90ed4f77 library/build_native_export.py
-c3be3f6ee2e065633f8e8e04482c95fe5c30f61e34cf6223d6454500a756dbb2 reference/CmpAtomModbus-AllInOne.export
-5a07da11853e955633a977bdd59a7d1f8f292c594c2116bc220bd63c8edc9329 reference/Working-CmpAtomModbus.export
+ca8eca5c351bcc426676213c162606d1be9ef6a07d017dad74aa10c198e4ea91 docs/API-REFERENCE.md
+43eb385327aa81deb28a55b08068a9b6e565ad290257d2cbd5819d1ab7558ae3 docs/BUILD-AND-USAGE.md
+a0931348b32a336798b7d93a5956fd14bd481597626bc1d40b1597ee6ed5e6a3 docs/CLEANUP.md
+ef14901695852012e92ae7dde304244e441c17f2bc17abd4fb7e7a2e30f2e9df docs/USER-GUIDE.md
+b35e03e6cd3e23719794802a65663ddc22986731dd52f6713ab71b94d1798f53 docs/VALIDATION.md
+be0edea894f02a6f525307da69fd52498d4ff76e4b95728608ff6db8f6877e39 library/CmpAtomModbus.library
diff --git a/artifacts/arm64/CmpAtomModbus_library.precompilecache b/artifacts/arm64/CmpAtomModbus_library.precompilecache
deleted file mode 100644
index 06722cd..0000000
Binary files a/artifacts/arm64/CmpAtomModbus_library.precompilecache and /dev/null differ
diff --git a/component-source/generated/CmpAtomModbus.c b/component-source/generated/CmpAtomModbus.c
deleted file mode 100644
index be3373b..0000000
--- a/component-source/generated/CmpAtomModbus.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "CmpStd.h"
-#include "CmpErrors.h"
-#include "CmpItf.h"
-#include "CmpAtomModbusDep.h"
-
-void CDECL CDECL_EXT atmbcall_cext(atmbcall_cext_struct *p)
-{
-
-}
-
diff --git a/component-source/generated/CmpAtomModbusItf.m4 b/component-source/generated/CmpAtomModbusItf.m4
deleted file mode 100644
index 0f01230..0000000
--- a/component-source/generated/CmpAtomModbusItf.m4
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * CmpAtomModbus
- *
- *
- *
- */
-
-SET_INTERFACE_NAME(`CmpAtomModbus')
-
-/** EXTERN LIB SECTION BEGIN **/
-/* Comments are ignored for m4 compiler so restructured text can be used. changecom(`/*', `*/') */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- *
- * Create FUNCTION atMbCall_cext returning UDINT, paste this declaration.
- * Properties > Build > External implementation must be selected.
- * Library filename and Project Information title: CmpAtomModbus.
- * This declaration is the SINGLE external entry point for the C engine.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
-*/
-typedef struct tagatmbcall_cext_struct
-{
- RTS_IEC_UDINT command;
- RTS_IEC_UDINT handle;
- RTS_IEC_DWORD ipAddress;
- RTS_IEC_UINT port;
- RTS_IEC_BYTE unitId;
- RTS_IEC_BYTE functionCode;
- RTS_IEC_UINT startAddress;
- RTS_IEC_UINT quantity;
- RTS_IEC_WORD *pData;
- RTS_IEC_UDINT dataCapacity;
- RTS_IEC_UDINT *pStatus;
- RTS_IEC_UDINT statusCapacity;
- RTS_IEC_ULINT nowMs;
- RTS_IEC_UDINT connectTimeoutMs;
- RTS_IEC_UDINT responseTimeoutMs;
- RTS_IEC_UDINT retryDelayMs;
- RTS_IEC_UDINT atMbCall_cext;
-} atmbcall_cext_struct;
-
-DEF_API(`void',`CDECL',`atmbcall_cext',`(atmbcall_cext_struct *p)',1,0x709EE65B,0x00020000)
-
-#ifdef __cplusplus
-}
-#endif
-
-/** EXTERN LIB SECTION END **/
-
diff --git a/docs/API-REFERENCE.md b/docs/API-REFERENCE.md
index 34ee4c8..8599947 100644
--- a/docs/API-REFERENCE.md
+++ b/docs/API-REFERENCE.md
@@ -1,6 +1,6 @@
# atMb API reference
-Generated from your working `CmpAtomModbus(1).export`. Documents every code object, including internal methods and property accessors. Runtime implementations, identifiers, declarations and embedded native payloads are preserved in the documented export; additions are comments only.
+Reference based on the last supplied working `CmpAtomModbus(1).export`, with 95 code objects. The current editable/installable library is `library/CmpAtomModbus.library`. This reference includes internal methods and property accessors. The binary library was preserved unchanged but not decoded to independently confirm its current declarations. Update this document against a fresh export when IEC code changes.
## atMbCall_cext
diff --git a/docs/BUILD-AND-USAGE.md b/docs/BUILD-AND-USAGE.md
index 43929eb..21009e0 100644
--- a/docs/BUILD-AND-USAGE.md
+++ b/docs/BUILD-AND-USAGE.md
@@ -1,203 +1,68 @@
-# atMb native TCP + RTU + TCP slave — development revision 0.9
+# Build and deployment
-The IEC export and C implementation have no ModbusFB dependency. All socket/
-serial/frame processing runs in the native component. Public namespace: atMb.
-Standard and SysTime are still required for IEC timers and time measurement.
+## Build native C
-This is a tested host development build, not a compiled CODESYS library or a
-hardware-qualified Pi release. Full CODESYS compilation and physical RTU testing
-remain required. Online-change ownership/pointer relocation is future work.
-
-## Rebuild on the Pi (required)
-
-Extract this bundle on the Pi, preserving component-source and ExtensionSDK
-as siblings. Install build-essential, m4, dos2unix, make and python3 if absent.
+From the repository root on the target Linux machine:
```sh
-cd component-source
-make -C component SDKDIR="$(realpath ../ExtensionSDK)" clean
-make -C component SDKDIR="$(realpath ../ExtensionSDK)" all
-file component/out/libCmpAtomModbus.so
-make test
+sudo apt install build-essential m4 dos2unix python3
+make -C component-source/component SDKDIR="$(realpath ExtensionSDK)" clean
+make -C component-source/component SDKDIR="$(realpath ExtensionSDK)" all
+file component-source/component/out/libCmpAtomModbus.so
+make -C component-source test
```
-The component registration version is now 0.3.0.0. The external atMbCall_cext
-function ABI, signature 0x709EE65B and generated API version 0.2.0.0 are unchanged.
-No regeneration of runtime interface files is required for these extra commands.
-Keep the supplied generated interface; do not regenerate blindly from a changed
-library title/version. No prebuilt Pi binary is included. A strict host compile
-of the component function used the supplied SDK headers and original real
-parameter struct; the full SDK/M4/component frame build must run on your Pi.
+`component-source/component/` is the active SDK build directory. Its
+`CmpAtomModbus.c` includes the protocol source files as one translation unit.
+The removed `generated/` directory contained original unimplemented stubs;
+it was not used by this makefile. Preserve the active `CmpAtomModbusItf.m4` and
+`CmpFrame.c`; they define ABI registration and cleanup.
-## Build the IEC library without legacy objects
+The makefile registers component version 0.3.0.0. The supplied external
+`atMbCall_cext` API retains signature 0x709EE65B and API version 0.2.0.0.
+Do not change the external parameter layout or regenerate it just because the
+library title/version was edited. Full SDK/M4 builds must be checked on the target.
-1. Create a fresh library project saved as CmpAtomModbus.library (or a backup copy
- with the old Modbus master/slave folders removed). Import atMb-Native.export.
- A fresh project is preferred because import does not delete omitted old methods.
-2. Keep Project Information title CmpAtomModbus and default namespace atMb, as
- supplied in the export. This is one combined library, not a wrapper referencing
- a second CmpAtomModbus/atMb library. Remove those self/wrapper references.
-3. Add only Standard and SysTime references needed by this IEC code. Remove the
- ModbusFB reference. Resolve their ordinary dependencies if the IDE requests it.
-4. Add a C Implemented Library object and embed your NEWLY BUILT ARM64
- component/out/libCmpAtomModbus.so for the exact Raspberry Pi 64 SL target.
- Use CmpAtomModbus for the component name. The old TCP-only embedded object was
- deliberately omitted from this export; do not reuse its binary.
-5. Compile, save/install and update references in the Atom library/application.
-6. Perform a full download. Verify runtime loads the new component version.
+## Update the CODESYS library
-For automatic deployment, stop using the old manually preloaded component
-before testing the embedded one: remove only its ComponentManager entry, then
-restart the runtime during maintenance. Alternatively, for a manual bench test,
-stop the runtime and replace /usr/lib/libCmpAtomModbus.so with the new binary.
-Inspect /var/log/codesyscontrol.log. No production install is performed by this kit.
+1. Back up `library/CmpAtomModbus.library` and open it in CODESYS.
+2. Retain Project Information title `CmpAtomModbus` and namespace `atMb`.
+3. Retain the Standard and SysTime references required by the IEC code.
+4. In its C Implemented Library object, update the native binary for the exact
+ device target with the newly built `libCmpAtomModbus.so`. Use the component
+ naming/settings already present in the working project.
+5. Compile the library, save/install it in Library Repository and update application
+ references. Test with a full download for native component changes.
-## TCP client
+The working `.library` is preserved unchanged in this cleanup. Updating a separate
+`.so` file does not automatically update the binary embedded inside the library.
+The standalone artifact is retained for deployment/build comparison; rebuilding it
+does not imply it is identical to the currently embedded implementation.
-Existing atMb.Client and ReqReadHolding/ReqReadInput/ReqReadCoil/ReqReadDiscrete/
-ReqWriteHolding/ReqWriteCoil calls remain. Supported C function codes are
-1,2,3,4,5,6,15,16. Automatic retry continues while enabled; normal Modbus
-exception replies do not force reconnects. The default retry delay is 100 ms.
+## Runtime deployment
-## Native RTU
+Use the established embedded-library deployment or a manual bench installation;
+avoid loading two versions of the same component simultaneously. The earlier Pi
+setup manually loaded `/usr/lib/libCmpAtomModbus.so` with
+`Component.1=CmpAtomModbus` under `[ComponentManager]` in
+`/etc/CODESYSControl_User.cfg`. When switching to embedded deployment, remove only
+that manual preload entry during maintenance and restart the runtime as required.
-```iecst
-VAR
- bus : atMb.ClientRTU;
- read : atMb.ReqReadHolding;
- registers : ARRAY[0..9] OF UINT;
-END_VAR
-```
+For a manual installation, stop the runtime before replacing its component and
+restart afterwards. Check `/var/log/codesyscontrol.log` for the loaded component
+and version; `/var/opt/codesys/codesyscontrol.log` was stale on the development Pi.
+No deployment or runtime restart is performed by this cleanup.
-```iecst
-bus(
- in_device := '/dev/ttyUSB0',
- in_baudRate := 9600,
- in_parity := 0,
- in_dataBits := 8,
- in_stopBits := 1,
- in_timeout := T#500MS,
- in_reconnectDelay := T#100MS
-);
-read(client := bus, in_unitId := 1, in_startAddr := 0,
- in_quantity := 10, in_dataOffset := 0, in_minDelay := T#100MS,
- data := registers);
-```
+## Different Linux targets
-Call client/requests every scan in ONE task. One RTU client owns each serial bus;
-register different unit IDs on that same client, rather than opening multiple
-clients on the same tty. The native open uses exclusive serial access.
+Build natively on the desired CPU or use a matching cross-toolchain. ARM64,
+ARM32 and x86-64 outputs are distinct. SDK, CODESYS runtime interface and libc
+compatibility also matter. A successful host protocol test does not validate native
+component loading into every runtime version. RTU support uses Linux termios/ioctl;
+verify serial permissions, driver behavior and physical timing on the target.
-Use /dev/serial/by-id/... when it fits the 127-byte path limit, or a stable
-short udev symlink. The runtime OS user must have access to the device; check the
-actual service user and device group on your Pi. Stop other serial consumers.
-The old numeric in_port selection was removed; a numeric index is not a portable
-Linux device mapping. in_baudRate is now UDINT so 115200 fits.
+## Further documentation
-Supported baud rates: 1200,2400,4800,9600,19200,38400,57600,115200.
-RTU uses 8 data bits; parity 0 none/1 odd/2 even; stop bits 1 or 2.
-Unit IDs 1..247 are accepted. Broadcast unit 0 is explicitly rejected because
-broadcast completion cannot be reported as an acknowledged write.
-
-For automatic-direction USB RS485 adapters leave in_rs485 FALSE. TRUE requests
-Linux TIOCSRS485 with RTS during transmit; unsupported drivers report an OS error.
-No software GPIO direction control or adapter-specific configuration is included.
-
-CRC, unit/function, length and write echo are validated before accepting replies.
-Faults close/reopen the tty after the configured retry delay. No raw write packet
-is replayed by the engine. The existing scheduler can issue fresh cyclic writes;
-use in_holdUncertainWrites TRUE for commands requiring an application decision.
-Delayed serial replies have no transaction ID: use suitable timeout/retry settings
-for slow devices. Serial silence is conservatively scheduled in milliseconds;
-physical adapter/baud/parity/line-turnaround tests are still necessary. PTY tests
-cannot certify electrical timing, parity generation or RS485 direction behavior.
-
-out_connected on RTU means the tty is open/ready, not proof that a remote unit
-responds. Use per-request online/stale/error status. out_socketError carries the
-OS errno for tty failures too. All existing client status counters are shared.
-
-## Native TCP slave
-
-atMb.ModbusSlave and atMb.SlaveTCP both run the C server (no ModbusFB server).
-Map four BOOL/UINT arrays using aDiscreteInputsMemory/aCoilsMemory/
-aInputRegistersMemory/aHoldingRegistersMemory. Their actual LOWER_BOUND is their
-zero-based protocol starting address; each table is limited to 2000 items and
-must fit within addresses 0..65535. A full 65536-item table is not supported.
-
-Use in_ipAddress DWORD = 0 to bind all addresses, or numeric IPv4 in human octet
-order (16#7F000001 for 127.0.0.1). port defaults to 502. The legacy interfaceName
-field is retained but must be empty; numeric bind IP replaces interface-name
-binding. Nonempty names are reported as parameter errors rather than ignored.
-
-Example: `slave : atMb.ModbusSlave;` with all four arrays passed every scan:
-
-```iecst
-slave(in_enable := TRUE, in_ipAddress := DWORD#0, port := 502,
- aDiscreteInputsMemory := discreteInputs,
- aCoilsMemory := coils,
- aInputRegistersMemory := inputRegisters,
- aHoldingRegistersMemory := holdingRegisters);
-```
-
-FC1/2/3/4/5/6/15/16 are implemented, with exception replies for unsupported
-functions, invalid quantities or unmapped addresses. Four server contexts,
-eight simultaneous peers per server. Requests are bounded and processed in
-order per connection. A server tick accepts at most one peer and performs at
-most one nonblocking I/O action per peer per IEC call. Incomplete frames/send
-stall timeout after 5 seconds; idle peers close after 60 seconds.
-
-The wrapper pushes PLC table snapshots, ticks the engine, then pulls completed
-remote writes in the same scan. C retains no PLC pointers between calls. Application
-writes between calls become the next snapshot. Arrange application order accordingly.
-The fixed server limits and scan-bounded throughput differ from the old ModbusFB
-server; load test your actual client count/polling rates. No RTU slave is provided.
-
-in_enable controls listening, in_reset recreates the context, endpoint changes
-recreate it, and listener failures retry automatically after in_reconnectDelay.
-Outputs: out_running/out_error/out_errorId/out_parameterError/out_socketError,
-out_connectedClients/out_requestsReceived/out_repliesSent/out_exceptionReplies.
-
-## Native lifecycle and API
-
-All bridge/server contexts are fixed-pool, generation-checked and single-task.
-No RETAIN/PERSISTENT handles. release() disables client enable and closes its
-context. STOP alone does not guarantee FB_exit: disable and scan before STOP.
-New full download required; online-change safety is not claimed in this revision.
-
-Own Error and ExceptionCodes DUTs replace the ModbusFB enums. Error retains the
-named compatibility labels used by request statistics. Legacy dynamically
-allocated request methods are removed or become native recreateRequest BOOL.
-Old allocation-alarm outputs/legacy request reset fields were removed because
-these contexts use fixed native pools. A pool-full result is native error 257.
-
-Command 20: open RTU. data contains one device-path ASCII byte per WORD, quantity
-is path length; ipAddress=baud; unitId=parity; functionCode=bits;
-startAddress=stop bits; connectTimeoutMs=kernel RS485 flag (0/1).
-The existing commands 2..11 configure/tick/submit/close this client normally.
-Commands 30..36: server open/close/enable/disable/tick/push/pull. Push/pull use
-functionCode as table 0 coils/1 discrete/2 holding/3 input, startAddress as base
-and quantity as length. Server handles use distinct low-byte tags from clients.
-Server status indices: 0 handle,1 running,2 error,3 result,4 OS errno,5 peers,
-6 requests,7 replies,8 exception replies. Client status layout is unchanged.
-
-## Tests and remaining checks
-
-Run make test on Linux. Includes existing nine TCP scenarios directly and through
-the bridge, pool/handle tests, PTY RTU read/fragment/CRC/timeout/recovery/exception/
-register-write/coil-write/invalid-write-echo recovery tests and native slave FC1/2/3/4/5/6/15/16, nonzero mapping,
-exception/listener-recovery/stale-handle tests. All passed on the development host.
-The CODESYS XML has no ModbusFB identifiers and passes structural checks. It has
-not been compiled in the IDE; hardware Pi/serial and embedded deployment tests
-remain. Do not interpret host tests as target or online-change qualification.
-
-
-v0.9.1 export correction
-------------------------
-Restores ClientBase public diagnostics: msgLastSecondCnt, msgLastSecondTime,
-numMsgSent, numMsgReply, allRequestsOnline and reqStats. The generator now
-checks these declarations and balanced VAR sections. Replace matching objects
-when importing the corrected export. C sources are unchanged from v0.9; this
-correction alone does not require rebuilding an already installed v0.9 component.
-The full native migration still requires the C build and embedding described above.
-Validated XML and declaration checks locally; CODESYS compilation must be checked
-in the IDE.
+- [User guide](USER-GUIDE.md): examples, polling, RTU, slave, timeout and recovery.
+- [API reference](API-REFERENCE.md): all objects from the last supplied working export.
+- [Validation](VALIDATION.md): exact scope of checks performed.
diff --git a/docs/CLEANUP.md b/docs/CLEANUP.md
new file mode 100644
index 0000000..9d2a035
--- /dev/null
+++ b/docs/CLEANUP.md
@@ -0,0 +1,25 @@
+# Repository cleanup
+
+Removed unused files:
+
+- `component-source/generated/`: original empty C stubs; active makefile builds
+ from `component-source/component/`.
+- Both `CmpAtomModbus_library.precompilecache` files: local CODESYS caches,
+ regenerated by the IDE; older duplicate was under artifacts.
+- `docs/document_export.py`: depended on an export already absent from this ZIP.
+- `docs/DOCUMENTATION-VALIDATION.md`: report for an export absent from this ZIP;
+ current validation is consolidated in `VALIDATION.md`.
+
+Rewrote README/build instructions to use the actual working `.library`, removing
+references to deleted exports, migration scripts and first-time Git initialization.
+Retained API/usage details and stated that their baseline is the last supplied export.
+Updated ignore rules and file checksums.
+
+Preserved exact bytes of the `.library`, ARM64 `.so`, active C sources, SDK, tests
+and all existing Git metadata. Git changes are not staged, committed or pushed.
+Old files remain recoverable from Git history where previously committed.
+
+To apply to an existing checkout, replacing files alone will not remove obsolete
+files. Prefer extracting this full snapshot into a separate directory and reviewing
+its existing Git status; alternatively remove the listed obsolete paths explicitly
+while applying updated files, keeping your checkout's own `.git` directory.
diff --git a/docs/DOCUMENTATION-VALIDATION.md b/docs/DOCUMENTATION-VALIDATION.md
deleted file mode 100644
index 8a636a7..0000000
--- a/docs/DOCUMENTATION-VALIDATION.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Documentation validation
-
-Documented 95 code objects.
-
-- All interface executable tokens unchanged after removing comments/whitespace.
-- All XML content outside Interface text identical after parse/serialization.
-- Implementations, GUIDs, native payloads, project information and references unchanged.
-- Documented XML parses successfully.
-- No CODESYS IDE compile performed; this is a comments-only change.
-
-Input SHA256: `5a07da11853e955633a977bdd59a7d1f8f292c594c2116bc220bd63c8edc9329`
diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md
index 806fdb0..c0eb333 100644
--- a/docs/USER-GUIDE.md
+++ b/docs/USER-GUIDE.md
@@ -1,6 +1,10 @@
# atMb usage and behavior
-This guide describes the supplied working export, including its renamed `ClientTCP`. The documented export changes comments only and retains the embedded C Implemented Library object. Import with replacement of matching objects into your existing library project. No C rebuild is needed for these documentation changes.
+This guide describes the last supplied working IEC export, including `ClientTCP`.
+The current repository stores the working file at `library/CmpAtomModbus.library`.
+Use that file in CODESYS. No IEC or C implementation is changed by repository cleanup.
+The binary library format was not decoded to reverify its member declarations;
+when changing IEC code, update this guide against a fresh CODESYS export.
## Choosing the block
@@ -211,6 +215,6 @@ States: 0 disabled, 1 retry wait, 2 connecting, 3 ready, 4 sending, 5 receiving.
## Maintenance and scope
-The documented export preserves the working implementations, metadata and embedded payloads. Internal native fields are sometimes exposed as VAR_INPUT for compatibility; leave them under library control. Several legacy BOOL methods do not assign a return value; the API reference identifies them so callers rely on their side effects.
+The cleanup preserves the supplied working library and standalone native binary. Internal native fields are sometimes exposed as VAR_INPUT for compatibility; leave them under library control. Several legacy BOOL methods do not assign a return value; the API reference identifies them so callers rely on their side effects.
Lifecycle hooks exist, but reliable online-change ownership and pointer relocation remain future work. Documentation adds no behavior changes or online-change guarantee. Use the API reference for every method/property, including internal accessors.
diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md
index 322a86b..1c1476d 100644
--- a/docs/VALIDATION.md
+++ b/docs/VALIDATION.md
@@ -1,14 +1,14 @@
-# Snapshot validation
+# Cleanup validation
-- Export generator completed: 99 objects, no ModbusFB references.
-- Public diagnostics and balanced VAR declaration checks passed.
-- Strict host C compilation passed.
-- Bridge pool/stale handle/configuration/shutdown tests passed.
-- Nine TCP scenarios passed directly and through the native bridge.
-- RTU pseudo-terminal tests passed, including CRC/timeout recovery, partial frames,
- writes, exceptions and invalid write echo recovery.
-- TCP slave FC 1/2/3/4/5/6/15/16, exception, nonzero base, listener recovery
- and stale handle tests passed.
+- Working `.library`, standalone ARM64 `.so`, active C/component sources, tests,
+ SDK and all Git metadata compared byte-for-byte with the uploaded ZIP: unchanged.
+- Removed precompile caches, unused generated stubs and broken generator script.
+- README/build instructions no longer refer to absent migration exports/scripts.
+- Strict host compilation and bridge tests passed after cleanup.
+- Nine direct TCP and nine bridge TCP scenarios passed.
+- RTU frame/write/error/recovery tests passed.
+- TCP slave FC1/2/3/4/5/6/15/16, exception/address and recovery tests passed.
-No CODESYS IDE compile, full ARM64 SDK build, physical serial hardware test,
-or online-change qualification was performed for this repository package.
+No CODESYS compile or full ARM64 SDK build was run. Physical RTU operation and
+online-change behavior were not qualified by these checks. API documentation is
+based on the last supplied working IEC export, not a decoded binary `.library`.
diff --git a/docs/document_export.py b/docs/document_export.py
deleted file mode 100644
index 92b6be8..0000000
--- a/docs/document_export.py
+++ /dev/null
@@ -1,194 +0,0 @@
-from pathlib import Path
-import xml.etree.ElementTree as E
-import re,hashlib,json,zipfile
-B=Path(__file__).resolve().parent
-src=B.parent/'reference/Working-CmpAtomModbus.export'
-r=E.parse(src).getroot();entries=list(r.find('.//List2[@Name="EntryList"]'))
-def meta(e,n):return e.find('./Single[@Name="MetaObject"]/Single[@Name="'+n+'"]')
-names={meta(e,'Guid').text:meta(e,'Name').text for e in entries}
-def path(e):
- n=meta(e,'Name').text;p=e.find('./Single[@Name="ParentSVNodeGuid"]').text
- return names.get(p,''),n
-def blob(e,p):return e.find('./Single[@Name="Object"]/Single[@Name="'+p+'"]//Single[@Name="TextBlobForSerialisation"]')
-summary={
-'ClientBase':'Abstract shared client scheduler and native transport owner. Use ClientTCP or ClientRTU. Holds up to 100 registered requests and runs one transaction at a time. Call the concrete client once per scan, from the same task as its requests.',
-'ClientTCP':'Modbus TCP client with automatic retry after connection or transaction failure. Call every scan. Endpoint or timeout/retry configuration changes close the current context and reopen it on subsequent scans. Requests share this connection and execute sequentially.',
-'ClientRTU':'Modbus RTU client using a Linux serial device. Call every scan. Supports 8 data bits, parity 0 none/1 odd/2 even, and 1 or 2 stop bits. Uses unit IDs 1..247; broadcast 0 is unsupported. Serial-setting changes recreate the context. Automatic recovery proceeds while enabled and scanned.',
-'RequestBase':'Abstract request binding, scheduling and diagnostics. Derived requests register automatically when called with a valid initialized client. Call each instance every scan with stable array storage. Quantity zero disables this request. Actual length is MIN(in_quantity, remaining array capacity).',
-'RequestStats':'Request counters, completion properties, online/offline tracking and 100 ms indicator lights. Normally maintained by RequestBase. Online means a valid response was received, including a Modbus exception; it does not guarantee successful data. Several fields are declared VAR_INPUT for compatibility but are maintained internally.',
-'To_IPAddress':'Returns the four supplied bytes as ARRAY[0..3] OF BYTE. Example: atMb.To_IPAddress(192,168,50,10). This is the ClientTCP address format; the slave bind address instead uses a packed DWORD.',
-'ModbusSlave':'Native Modbus TCP server. Same implementation and interface as SlaveTCP. Call once per scan with all four memory arrays. Array bounds are protocol addresses; each table is limited to 2000 elements and addresses 0..65535. Pushes application memory, performs bounded network processing, then copies native memory back. This is TCP only, not an RTU slave.',
-'SlaveTCP':'Native Modbus TCP server with four separate memory tables. Same implementation and interface as ModbusSlave. FC 1/2/3/4 read the tables; FC 5/6/15/16 write coils/holding registers. Array lower bounds define Modbus addresses. Call every scan and retain array storage. This is TCP only.',
-'ClientStatus':'Aggregate request status used by the RTU monitoring property: noneOk=0, someOk=1, allOk=2. This describes request online flags, not the physical connection. The current toString getter compares onlineCnt with all registered requests and reports allOk for an empty registry.',
-'Error':'IEC error classification. TCP-named socket/timeout members are also used for RTU failures. For the precise native reason inspect out_nativeError/out_lastNativeError; for an OS failure inspect out_socketError.',
-'ExceptionCodes':'Modbus exception response values plus local TIMEOUT=-1. A valid Modbus exception proves communication, but the requested operation failed. In current statistics, non-exception errors can also be classified as TIMEOUT; use native diagnostics to distinguish their actual cause.',
-'atMbCall_cext':'External C ABI entry point used by the wrappers. Application code should normally call the function blocks. Do not change parameter order/types or external implementation settings. Pointers are accessed synchronously by C; provide distinct valid data/status buffers and truthful capacities. Client status requires 24 UDINT elements. All calls must be owned by one IEC task.',
-'addRequest':'Register a non-null RequestBase pointer once. Duplicate pointers are ignored. Capacity is 100 requests per client; overflow sets out_registrationFull. No removal API is provided. Normally called automatically by the request FB.',
-'nativeCall':'Internal adapter to atMbCall_cext. Command 20 packs the ASCII serial path into WORD storage and passes serial settings in ABI fields; other commands use normal client arguments and status buffers. Return is the native command result, 0 for success.',
-'nativeCycle':'Internal per-scan engine: acquire context, tick nonblocking I/O, update diagnostics, copy completed read data, process registered requests, acknowledge completion, select the next request, and publish statistics. Invalid native handles are discarded and reopened on a later scan.',
-'nativeEnsureContext':'Acquire/configure/enable a native context if absent. Returns TRUE when a handle exists or initialization succeeds. A handle does not mean connected; check out_connected. Failure records a native error and closes partially initialized contexts.',
-'nativeRelease':'Close the native context, complete any active request as cancelled, clear selection, set registered requests offline and invalidate cached read data. Returns TRUE. It does not set in_enable FALSE; an enabled scanned client can reopen.',
-'nativeSelectNextRequest':'Select an active, unheld request that meets in_minDelay and was not just completed this scan. Lowest in_priorityCurrent wins; oldest sinceLastExec breaks ties. Positive priorities are decremented when the best selected priority is positive. The selected request is submitted immediately; zero priority is not a prerequisite for execution.',
-'nativeUpdateDiagnostics':'Publish native connection state, last error, errno and reconnect count. States 3..5 count as connected. A connected-to-disconnected transition marks registered requests offline.',
-'nativeUpdateStatistics':'Publish IEC send/reply counters, registered statistics pointers and active-request aggregate online flags. Every elapsed window of at least 1000 ms publishes submitted-request count and successful transaction-duration sum, then restarts the window.',
-'processAllRequests':'Internal loop over registered non-null requests, dispatching processRequest. Returns immediately for an empty or invalid registry. Usually invoked by nativeCycle rather than application code.',
-'recreateClient':'Close/release the current context so the next enabled scan creates a fresh one with current settings. Cancels an active transaction and invalidates cached read data. Abstract on ClientBase; implemented by both concrete clients.',
-'release':'Stop this client by setting in_enable FALSE, then release its native context. Returns the release result. To resume, set in_enable TRUE and keep calling the client. A call that supplies in_enable := TRUE every scan will re-enable it.',
-'setAllRequestsOffline':'Internal helper marking every registered request offline via its statistics FB. Returns TRUE after processing a nonempty valid registry; early return does not explicitly assign the return value.',
-'setupClient':'Returns whether nativeHandle is nonzero. It does not create a context or guarantee transport connectivity. Normal FB scanning performs initialization.',
-'activeIndex':'Get the current active request registry index, or -1 when idle. Setting a valid index sets that request stats.execute TRUE; it does not bypass native scheduler selection or directly submit a transaction.',
-'activeReqCnt':'Private count of registered requests whose stats.active is TRUE. Zero quantity/usable length requests are inactive.',
-'allRequestsComplete':'Private legacy completion check. TRUE only if none of the registered requests has execute, reqDone, reqBusy or reqError set. Empty registry returns FALSE. This is not a network completion pulse.',
-'onlineCnt':'Count registered requests with stats.online TRUE. Includes any registered request with that flag; used for aggregate reporting.',
-'requestExecuting':'Private property returning activeIndex <> -1. Represents selected/active request state maintained by the scheduler.',
-'toString':'ClientRTU monitoring property returning ClientStatus based on onlineCnt versus requestCnt. Reports allOk for an empty registry. RequestStats also has an internal STRING field of this name; these are different values.',
-'busy':'Assign stats.reqBusy from input in. Internal request helper. Although declared BOOL, its implementation does not assign a return value; use the side effect rather than the return.',
-'done':'Set stats.reqDone. When in is TRUE, restore in_priorityCurrent to in_prioritySetpoint for the next scheduler cycle. Successful completion counters are maintained by the stats property setter.',
-'err':'Set stats.reqError and, on TRUE, record errorId/exceptionCode. Set next priority to 10 * MIN(consecutive errors,3)^2. Lower numeric priority wins, so this backs off repeated failures relative to lower-priority-number requests.',
-'invalidateNativeData':'Mark cached data invalid and stale. Does not erase the application array. Called during client release; applications should gate use of cached values with validity and age flags.',
-'nativeFinish':'Complete a request from native result. Map errors, copy errno/write uncertainty, clear busy, update response/counters and successful-read freshness. Modbus exceptions count as replies and communication-online evidence. If enabled, uncertain writes are held pending writeNow().',
-'nativeProcess':'Shared request processing called by derived processRequest. Completes native results or submits a selected request, sets its timeout and records busy/send counters. Updates data age and stale flags during ordinary processing. Completion branches can return before age refresh, so allow a subsequent scan for freshness diagnostics.',
-'replyTimeout':'Protected timeout property expressed internally in microseconds. Request in_timeout is milliseconds and takes precedence, then client TIME in_timeout, then a dataRate formula, then 1 second fallback. Submission rounds up to milliseconds and clamps to at least 1 ms.',
-'setClientOffline':'Clear nativeResponseSeen and consecutive-success count, force online FALSE/offline TRUE. Does not clear data arrays. Declared BOOL but does not assign a return value.',
-'setToString':'Private statistics helper formatting OK:/Er: into STRING(20). Declared BOOL but does not assign a return value.',
-'execute':'Statistics execution property. Setting TRUE starts the execution state only when reqDone and reqError are FALSE; otherwise the setter clears execution. Usually controlled by the scheduler.',
-'reqBusy':'Get/set the underlying request-busy flag. Normally managed by the native wrapper. The scan-held reqBusyLight provides a more visible monitoring indicator.',
-'reqDone':'Get/set completion flag. When TRUE during execution, record duration, increment total/consecutive successes, clear consecutive errors and last error, clear execution and update the monitor string. Do not repeatedly drive this manually.',
-'reqError':'Get/set error flag. When TRUE during execution, increment total/consecutive errors, clear consecutive successes and execution. If lastExceptionCode is success, increment timeoutCnt and set TIMEOUT even for some non-timeout native errors.',
-'recreateRequest':'Clear this request nativeInFlight. If it is the client active request, recreate the whole client connection first. Returns TRUE. May affect other requests sharing the same connection; this is not an independent transport.',
-'writeNow':'Clear uncertain-write hold and out_writeUncertain, then set in_priorityCurrent to 0. Returns TRUE. Requests a prompt opportunity at the next scheduler selection; does not guarantee transmission in this call and does not bypass connection/minimum-delay requirements.',
-'serverCall':'Private adapter for native server commands. Uses separate server status and WORD staging buffers. Returns the command result; 0 means command accepted, not necessarily that the listener has bound.',
-'FB_exit':'CODESYS lifecycle hook releasing owned native resources. Applications should use release/recreateClient rather than call lifecycle hooks manually. Server hooks close the server context; the client hook calls nativeRelease.',
-'FB_reinit':'CODESYS lifecycle hook clearing native handles and in-flight state. ClientBase also clears the request registry for re-registration; RequestBase clears execution/completion flags; servers clear their handle. These hooks alone do not establish qualified online-change support.'}
-for name,fc,kind,limit in [('ReqReadCoil',1,'BOOL coils',2000),('ReqReadDiscrete',2,'BOOL discrete inputs',2000),('ReqReadHolding',3,'UINT holding registers',125),('ReqReadInput',4,'UINT input registers',125),('ReqWriteCoil',15,'BOOL coils',1968),('ReqWriteHolding',16,'UINT holding registers',123)]:
- summary[name]=f'Modbus FC {fc}: '+('write ' if fc>=15 else 'read ')+f'{kind}. Call every scan with a client reference and data array. Protocol start address is zero-based; in_dataOffset is the actual array index. Maximum transaction length is {limit}. Usable length is clamped to array capacity. '+('Values are copied into native storage at submission. This FB uses the multiple-write FC even for one element. Use writeNow() to release a held uncertain write.' if fc>=15 else 'Only a successful validated reply updates the destination slice. Old values remain after failures; check out_validData and out_stale.')
-fields={
-'in_enable':'Enable processing; TRUE by default. FALSE releases transport. Continue scanning to refresh state.',
-'in_timeout':'Reply timeout override. ClientBase: TIME; RequestBase: SYSTIME numeric milliseconds (not microseconds). Zero selects inherited/calculated timeout.',
-'in_resetStats':'Reset request consumed and cleared by nativeCycle. Supplying TRUE on every call resets statistics every scan; pulse once.',
-'in_ipAddress':'ClientTCP: four IPv4 bytes. Slave: packed numeric DWORD, 0 binds all interfaces; e.g. DWORD#16#C0A8321F for 192.168.50.31.',
-'in_port':'Remote TCP port, default 502.', 'in_baudrate':'TCP gateway serial baud-rate hint for calculated reply timeout; 0 uses internal dataRate 105200. Does not configure a serial port.',
-'in_connectTimeout':'TCP connection-attempt deadline, default 2 s; clamped to at least 1 ms.',
-'in_reconnectDelay':'Delay before native recovery attempt, default 100 ms; clamped to at least 1 ms. Effective timing also depends on scan interval and failure detection.',
-'in_holdUncertainWrites':'FALSE allows normal retries after uncertain writes. TRUE holds affected write requests until writeNow(); read requests can continue.',
-'in_device':'Linux serial device path, default /dev/ttyUSB0, at most 127 ASCII characters. Runtime account needs access.',
-'in_baudRate':'Serial baud rate, default 9600. Supplied C source accepts 1200,2400,4800,9600,19200,38400,57600,115200.',
-'in_parity':'0 none, 1 odd, 2 even. Must match the slave.', 'in_dataBits':'Only 8 supported by supplied native implementation.', 'in_stopBits':'1 or 2; must match the slave.',
-'in_rs485':'Request Linux kernel RS485 direction control. Leave FALSE for USB adapters handling direction automatically. Requires driver support.',
-'client':'Reference to the owning ClientBase concrete instance. Initialize/call client before first registration; retain a stable instance.',
-'in_startAddr':'Zero-based Modbus protocol address, not a 40001/30001 display reference. Must fit the transaction into address space.',
-'in_quantity':'Requested item count; actual stats.reqLength is MIN(this, available destination/source capacity). Zero makes the request inactive.',
-'in_dataOffset':'Actual first index in the application array. For ARRAY[1..10], use 1 to start at the first element; not a relative offset.',
-'in_unitId':'Modbus unit/slave ID, default 0. RTU requires explicit 1..247; TCP/gateway values depend on the target.',
-'in_minDelay':'Minimum start-to-start time before scheduler eligibility, default 10 ms. Not a fixed polling period.',
-'in_prioritySetpoint':'Priority restored on success, default 50. Lower values win. Error backoff can replace current priority.',
-'in_priorityCurrent':'Mutable scheduler priority. Lower values win, equal values use age. WriteNow sets 0. Application need not maintain it each scan.',
-'in_staleAfter':'Read data age threshold, default 2 s. out_stale becomes TRUE when age is strictly greater; does not stop polling.',
-'data':'Open array: BOOL for coils/discretes; UINT for registers. Stable VAR_IN_OUT storage. Writes snapshot values at submission; reads replace only their successful slice.',
-'stats':'Per-request RequestStats instance maintained by request processing; inspect rather than overwrite.',
-'out_connected':'Transport is in ready/sending/receiving state. Does not prove a request succeeded or data is fresh.',
-'out_connectionState':'0 disabled, 1 retry wait, 2 TCP connecting, 3 ready, 4 sending, 5 receiving.',
-'out_lastNativeError':'Native last transport error; may persist after recovery. Check current connection and request diagnostics too.',
-'out_nativeError':'Result of the last completed/failed request; 0 success. Precise native code, distinct from IEC Error enum.',
-'out_socketError':'Native Linux errno snapshot as UDINT; may be historical. Used for both serial and sockets.',
-'out_reconnectCount':'Native successful reconnections after the first connection. Context recreation resets its native lifetime counters.',
-'out_registrationFull':'Sticky request registry overflow indicator; max 100 requests/client. Client reinitialization clears it.',
-'out_writeUncertain':'Write may have reached target without a confirmed response. It is not proof of failure or success. Relevant for write requests.',
-'out_validData':'TRUE after a successful read; subsequent read failures do not necessarily clear it. Client release or invalidateNativeData clears it.',
-'out_dataAgeMs':'Age since last successful read in milliseconds. Updated by normal processing; completion early returns can defer refresh by one scan.',
-'out_stale':'TRUE before valid read data or when age exceeds in_staleAfter. Array contents are retained.',
-'out_parameterError':'Array-offset validation for requests; full transaction validation can instead appear in out_nativeError/stats.lastErrorId. Slave: invalid port/interfaceName/table bounds or capacity.',
-'msgLastSecondCnt':'Submitted request count in the last completed window of at least 1000 ms, not necessarily an exact sliding second.',
-'msgLastSecondTime':'Sum of successful transaction durations in that completed window (ms); excludes failed durations.',
-'numMsgSent':'IEC accepted submission count since resetStats; not a count of physical packets.',
-'numMsgReply':'IEC successful or Modbus-exception reply count since resetStats.',
-'allRequestsOnline':'TRUE when at least one active request exists and onlineCnt equals activeReqCnt. Online can include exception replies.',
-'reqStats':'Pointers to registered request statistics by registry index, populated on client scans. Null entries are unused; validate before dereference.',
-'in_reset':'Slave one-shot recreation input. FB clears it internally; supplying TRUE every scan recreates every scan.',
-'interfaceName':'Legacy slave field. Must be empty; nonempty is rejected. Use packed in_ipAddress instead.',
-'port':'Slave listening port, default 502, must be nonzero.',
-'aCoilsMemory':'Read/write BOOL coil table. Array bounds are protocol addresses; FC1 reads, FC5/15 write.',
-'aDiscreteInputsMemory':'Read-only from network BOOL input table; FC2 reads. Application updates it.',
-'aHoldingRegistersMemory':'Read/write UINT holding table; FC3 reads, FC6/16 write.',
-'aInputRegistersMemory':'Read-only from network UINT input table; FC4 reads. Application updates it.',
-'out_running':'Native listener is bound and enabled. Does not mean a peer is connected.',
-'out_error':'Current server error flag when outputs are refreshed; some early returns leave other diagnostics unchanged.',
-'out_errorId':'IEC server error classification: parameter/internal/native socket class. Consult errno for OS detail.',
-'out_connectedClients':'Number of native TCP peers connected (max 8 per server in supplied C source).',
-'out_requestsReceived':'Native request count for current server context.',
-'out_repliesSent':'Native fully transmitted reply count for current context, including exception replies.',
-'out_exceptionReplies':'Number of Modbus exception replies for current server context.',
-'lastErrorId':'Last mapped IEC error; successful completion resets to OK.', 'lastExceptionCode':'Last Modbus exception, success=0; stats may substitute TIMEOUT=-1 for non-exception failures.',
-'lastValidDuration':'Last successful request duration (ms).','longestValidDuration':'Maximum successful duration recorded; resetStats does not clear it.',
-'interval':'Start-to-start execution interval (ms).','offlineCnt':'Count of NOT online rising edges; can include initial not-online state, not only a physical disconnect.',
-'doneCnt':'Total successful completions; resetStats clears.','errorCnt':'Total failed completions; resetStats clears.',
-'doneCntRst':'Consecutive successes; reset on error/offline/resetStats.','errorCntRst':'Consecutive errors; reset on successful completion/resetStats.',
-'sinceLastExec':'Age since last execution start (ms), capped around 60000 by the statistics clock logic.',
- 'timeoutCnt':'Statistics non-exception error count; can include other native failures. Not exclusively reply timeouts; resetStats does not clear it.',
-'reqLength':'Effective transaction length; zero means inactive.', 'online':'Communication status; valid normal/exception response sets evidence. Distinct from valid data.',
-'offline':'Offline status; initialized FALSE, explicitly set on client-offline or repeated failures.', 'active':'TRUE when reqLength is nonzero.',
-'executeLight':'Execution indicator with 100 ms off-delay.','reqDoneLight':'Completion indicator with 100 ms off-delay.','reqErrorLight':'Error indicator with 100 ms off-delay.','reqBusyLight':'Busy indicator with 100 ms off-delay.',
-'executeMbFb':'Legacy retained output; no assignment in current native implementation. Do not use as a trigger.',
-'nativeResponseSeen':'Internal communication-response evidence, maintained by nativeFinish and offline handling.', 'nativeLastSuccessMs':'Internal successful-read timestamp in monotonic milliseconds.',
-'command':'Native command selector. Use wrappers in application code.', 'handle':'Generation-checked native context handle; 0 for open.',
-'ipAddress':'Packed IPv4 for TCP commands; command 20 overloads this field with RTU baud rate.',
-'unitId':'Transaction unit ID; command 20 overloads it with serial parity.', 'functionCode':'Modbus FC; command 20 uses data bits, server push/pull use table ID.',
-'startAddress':'Protocol start; command 20 uses stop bits.', 'quantity':'Item count; command 20 uses serial path byte count.',
-'pData':'WORD buffer; client reads/writes, serial ASCII path, or server table staging.', 'dataCapacity':'Available WORD elements, not bytes.',
-'pStatus':'UDINT status buffer; requires at least 24 elements.', 'statusCapacity':'Available UDINT elements, not bytes.',
-'nowMs':'Monotonic time in milliseconds; wrappers use SysTimeGetUs / 1000.', 'connectTimeoutMs':'TCP connection timeout; command 20 uses kernel RS485 flag.',
-'responseTimeoutMs':'Reply deadline in milliseconds.', 'retryDelayMs':'Native recovery wait in milliseconds.',
-'byte1':'First IPv4 octet.','byte2':'Second IPv4 octet.','byte3':'Third IPv4 octet.','byte4':'Fourth IPv4 octet.',
-'bInCopyCode':'Runtime lifecycle copy-code indicator; current implementation does not branch on it.',
-'in':'New state to assign. Normally used internally by completion helpers.', 'errorId':'Mapped IEC error supplied to the error helper.', 'exceptionCode':'Modbus exception classification supplied to the error helper.', 'result':'Native completion result; 0 success.'}
-original={}
-sections=[];count=0
-for e in entries:
- parent,name=path(e);t=blob(e,'Interface');impl=blob(e,'Implementation')
- if t is None:continue
- old=t.text or '';original[meta(e,'Guid').text]=old
- if name=='resetStats':
- desc=('Reset IEC send/reply/window counters and call each registered stats.resetStats. Does not clear native errno/reconnect counters or all per-request history. No transport recreation.' if parent=='ClientBase' else 'Reset only doneCnt, doneCntRst, errorCnt and errorCntRst. Retains durations, offlineCnt, timeoutCnt and timestamps.')
- elif name=='processRequest':desc=('Derived request dispatch: performs '+parent+' transaction using shared nativeProcess, validates copy bounds and transfers the configured slice. Called by client scheduler; application calls the request FB body to register/bind its data.' if parent!='RequestBase' else 'Abstract internal request dispatch implemented by each concrete read/write block.')
- elif name in ['Get','Set']:desc=f'{name} accessor for {parent}; see the owning property reference for side effects. Runtime/property syntax normally invokes this accessor.'
- else:desc=summary.get(name)
- assert desc,(parent,name)
- header=f'(* atMb API reference: {parent+"." if parent else ""}{name}\n{desc}\n*)\n'
- # Add comments only to declaration lines, never change code or types.
- lines=[];scope=''
- for line in old.splitlines(keepends=True):
- sm=re.match(r'\s*(VAR(?:_INPUT|_OUTPUT|_IN_OUT|_TEMP)?)(?:\s+CONSTANT)?\s*$',line)
- if sm:scope=sm.group(1)
- if re.match(r'\s*END_VAR',line):scope=''
- m=re.match(r'\s*(\w+)\s*:',line)
- if m and m.group(1) in fields:
- lines.append(' // '+fields[m.group(1)]+'\n')
- lines.append(line)
- t.text=header+''.join(lines);count+=1
- sections.append('## '+(parent+'.' if parent else '')+name+'\n\n'+desc+'\n\n```iecst\n'+old.strip()+'\n```\n\n')
- # Parameter table scoped to input/output/open-array sections.
- rows=[];scope=''
- for line in old.splitlines():
- sm=re.match(r'\s*(VAR(?:_INPUT|_OUTPUT|_IN_OUT)?)(?:\s+CONSTANT)?\s*$',line)
- if sm:scope=sm.group(1)
- if re.match(r'\s*END_VAR',line):scope=''
- m=re.match(r'\s*(\w+)\s*:\s*(.*?);',line)
- if m and scope in ['VAR_INPUT','VAR_OUTPUT','VAR_IN_OUT']:
- fn=m.group(1); explanation=fields.get(fn,'Internal wrapper state exposed for compatibility; normally leave under library control.')
- rows.append('| `'+fn+'` | '+scope+' | `'+m.group(2).replace('|','\\|')+'` | '+explanation+' |')
- if rows:sections.append('| Member | Direction | Declaration | Meaning |\n|---|---|---|---|\n'+'\n'.join(rows)+'\n\n')
-# Verify executable tokens and all non-Interface XML content unchanged.
-def without_comments(s):return re.sub(r'\s+','',re.sub(r'//[^\n]*','',re.sub(r'\(\*.*?\*\)','',s,flags=re.S)))
-for e in entries:
- guid=meta(e,'Guid').text
- if guid in original:assert without_comments(original[guid])==without_comments(blob(e,'Interface').text),path(e)
-output=B/'atMb-Documented.export';E.ElementTree(r).write(output,encoding='utf-8',xml_declaration=True)
-check=E.parse(output).getroot();orig=E.parse(src).getroot()
-for root in [check,orig]:
- for e in root.find('.//List2[@Name="EntryList"]'):
- t=blob(e,'Interface')
- if t is not None:t.text='DOCUMENTATION_ONLY'
-assert E.tostring(check)==E.tostring(orig),'Non-documentation content changed'
-(B/'API-REFERENCE.md').write_text('# atMb API reference\n\nGenerated from your working `CmpAtomModbus(1).export`. Documents every code object, including internal methods and property accessors. Runtime implementations, identifiers, declarations and embedded native payloads are preserved in the documented export; additions are comments only.\n\n'+''.join(sections))
-(B/'VALIDATION.md').write_text(f'# Documentation validation\n\nDocumented {count} code objects.\n\n- All interface executable tokens unchanged after removing comments/whitespace.\n- All XML content outside Interface text identical after parse/serialization.\n- Implementations, GUIDs, native payloads, project information and references unchanged.\n- Documented XML parses successfully.\n- No CODESYS IDE compile performed; this is a comments-only change.\n\nInput SHA256: `{hashlib.sha256(src.read_bytes()).hexdigest()}`\n')
-print('Documented',count,'objects; comment-only and native-payload preservation checks passed')