Cleanud up
This commit is contained in:
@@ -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
|
||||
+16
@@ -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
|
||||
@@ -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.
|
||||
|
||||
+8
-18
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* <interfacename>CmpAtomModbus</interfacename>
|
||||
* <description></description>
|
||||
*
|
||||
* <copyright></copyright>
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* <description>
|
||||
* 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.
|
||||
* </description>
|
||||
* <element name="atMbCall_cext" type=OUT></element>
|
||||
* <element name="command" type=IN></element>
|
||||
* <element name="handle" type=IN></element>
|
||||
* <element name="ipAddress" type=IN></element>
|
||||
* <element name="port" type=IN></element>
|
||||
* <element name="unitId" type=IN></element>
|
||||
* <element name="functionCode" type=IN></element>
|
||||
* <element name="startAddress" type=IN></element>
|
||||
* <element name="quantity" type=IN></element>
|
||||
* <element name="pData" type=IN></element>
|
||||
* <element name="dataCapacity" type=IN></element>
|
||||
* <element name="pStatus" type=IN></element>
|
||||
* <element name="statusCapacity" type=IN></element>
|
||||
* <element name="nowMs" type=IN></element>
|
||||
* <element name="connectTimeoutMs" type=IN></element>
|
||||
* <element name="responseTimeoutMs" type=IN></element>
|
||||
* <element name="retryDelayMs" type=IN></element>
|
||||
*/
|
||||
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 **/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+51
-186
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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`
|
||||
+6
-2
@@ -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.
|
||||
|
||||
+12
-12
@@ -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`.
|
||||
|
||||
@@ -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:<doneCnt>/Er:<errorCnt> 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')
|
||||
Reference in New Issue
Block a user