first commit

This commit is contained in:
2026-09-30 21:17:41 -06:00
commit 07244fc761
57 changed files with 30094 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
# Bridge contract
Return: 0 = accepted, 1..10 = am_error values in atom_mb.h.
256 = invalid/stale handle, 257 = pool full, 258 = insufficient/null buffer,
259 = unknown command. Always inspect return codes. A rejected call is not a
completed Modbus request.
Commands: 1 Open, 2 Close, 3 Enable, 4 Disable, 5 Tick, 6 Submit,
7 CopyRead, 8 Reconnect, 9 Configure, 10 Acknowledge,
11 Set request timeout (responseTimeoutMs only; permitted while not busy).
Configure only while disabled; all three timeouts must be nonzero.
Open receives an IPv4 DWORD in human octet order: 16#C0A80132 = 192.168.1.50.
Open returns its handle in status[0], NOT in the function return value.
Close returns status[0]=0; old handles fail even when their slot is reused.
Capacity values count WORD/UDINT elements, not bytes. Pass separate buffers.
CopyRead copies `quantity` WORDs; coils/discretes are unpacked WORD 0/1.
| Status index | Meaning |
|---|---|
| 0 | Handle |
| 1 | State: 0 Disabled, 1 Retry, 2 Connecting, 3 Ready, 4 Sending, 5 Receiving |
| 2 | Busy |
| 3 | Done |
| 4 | Error |
| 5 | Latest transaction result |
| 6 | Last failure, retained after success |
| 7 | OS socket error |
| 8 | Modbus exception |
| 9 | Write outcome uncertain |
| 10 | Connection attempts |
| 11 | Attempts after first attempt |
| 12 | Completed successful requests |
| 13 | Failed requests |
| 14 | Has successful transaction |
| 15 | Last success timestamp, low 32 bits |
| 16 | Last success timestamp, high 32 bits |
| 17 | Quantity of latest request |
| 18 | Function code |
| 19 | Unit ID |
| 20 | Enabled |
| 21 | Connect timeout milliseconds |
| 22 | Whole-request timeout milliseconds |
| 23 | Retry delay milliseconds |
The PLC wrapper consumes Done/Error then Acknowledge before submitting a new
request. For Done reads, call CopyRead BEFORE Acknowledge. Completed read data
is retained internally but CopyRead requires Done. For writes, do not replay
an uncertain result without an application decision.
All calls to the entire bridge pool must originate from ONE IEC task. Contexts
and the pool are not thread-safe. Handles must not be RETAIN/PERSISTENT. Closing
on program disposal and invalidating on application reset/download remain PLC
wrapper responsibilities. Component unload cleanup alone does not cover an IEC
application stop or download.
+37
View File
@@ -0,0 +1,37 @@
# Linux builds
A binary must match CPU architecture, libc and the CODESYS component interface.
One .so cannot cover every Linux version. Build on the oldest supported target
OS within each architecture, or use its sysroot in a matching cross toolchain.
Native Pi build, from Library:
```sh
sudo apt-get install build-essential make m4 sed dos2unix python3
./tools/build-linux.sh linux-aarch64
```
Native x86-64 Linux build: `./tools/build-linux.sh linux-x86_64`.
32-bit ARM requires a matching ARM hard-float compiler/OS; do not use the ARM64
binary. The target argument labels output; it does not choose a compiler.
Cross-build example, provided a matching compiler and libc sysroot are installed:
```sh
CC=aarch64-linux-gnu-gcc ./tools/build-linux.sh linux-aarch64
```
For a custom compiler/sysroot use a compiler wrapper as CC. Cross builds have
not been validated in this bundle. The supplied SDK's makefile controls linking;
check its options before adding toolchain flags. CC must be one executable path.
Build targets sequentially because component/out is shared and cleaned each run.
The build script accepts an SDKDIR environment override. Preserve the supplied
SDK unchanged and use separate folders for replacement SDK versions. Record
and test compatibility before changing the generated external function ABI.
For ABI changes, regenerate C/M4 from the external CODESYS library and review
tools/prepare_component.py; do not overwrite component implementations blindly.
Build metadata includes compiler, host, SDK file hashes and output architecture.
Host OS/glibc describes the build host, not necessarily a cross-compiler sysroot.
Add the actual sysroot and tested target runtime to build-info.txt before release.
+19
View File
@@ -0,0 +1,19 @@
# Embed the shared object in the IEC library
1. Copy the built libCmpAtomModbus.so to the development PC.
2. Open the CmpAtomModbus library containing atMbCall_cext.
3. In POUs add a C Implemented Library object (C Code Integration functionality).
4. Add an Object file for devices: choose the .so and the exact Raspberry Pi
64 SL device/version. If a component name is requested, use CmpAtomModbus.
5. Save/install the library and update the application's library reference.
6. Perform a full download and verify loading and function resolution.
Add separate object files for other device/architecture targets. CODESYS chooses
the matching device entry; do not assign ARM64 binaries to 32-bit devices.
For automatic deployment testing, remove only the old manually added
CmpAtomModbus ComponentManager entry and restart the runtime before download.
Do this while the PLC application is stopped for maintenance.
Official instructions:
https://content.helpme-codesys.com/en/CODESYS%20Control/_rtsl_extension_extension_sdk.html
https://content.helpme-codesys.com/en/CODESYS%20Development%20System/_cds_obj_c_implemented_library.html
+14
View File
@@ -0,0 +1,14 @@
# Validation
Run `make test` on Linux with a C compiler and Python 3. Tests use a local
socket server and cover normal/fragmented replies, close/reconnect, timeout,
bad transaction IDs, bad MBAP length, Modbus exceptions, uncertain writes and
coils. They run through the direct engine and bridge. Pool/handle tests are
included. These tests do not compile or execute Structured Text.
In CODESYS compile both libraries and start a read-only bench application.
Verify first scan with zero registered requests, then registered requests,
reply timeouts, priorities, data freshness, disconnect/reconnect and disposal.
Test full download/reset and online-change lifecycle separately. Only then test
writes with appropriate device registers. Validate embedded deployment on a
target without the manually configured component.
+27
View File
@@ -0,0 +1,27 @@
# Troubleshooting
On the user's Pi the active runtime log is /var/log/codesyscontrol.log.
/var/opt/codesys/codesyscontrol.log contained old logs. Check timestamps.
```sh
sudo /etc/init.d/codesyscontrol status
sudo tail -n 100 /var/log/codesyscontrol.log
file component/out/libCmpAtomModbus.so
nm -D component/out/libCmpAtomModbus.so
```
Look for CmpAtomModbus, undefined symbol, signature mismatch or load errors.
ComponentEntry and atmbcall_cext must be exported. The observed manual load was
component ID 0xffff2001, version 0.2.0.0. Ensure custom component IDs do not collide.
External function signature: 0x709EE65B, API version: 0x00020000.
A valid component load does not prove the request scheduler or device I/O works.
AccessViolation in processAllRequests: use the current export with zero-count,
bounds and null checks and do a full download. Nonzero stale pointers still need
lifecycle investigation. Keep requests and their data arrays alive for the client
lifetime, and do not change a registered request's client while running.
Use one IEC task for all native clients. Handles must not be retained/persistent.
For STOP/download, disable the client and let a scan run, or call release().
See compat/README.md for lifecycle limitations and uncertain-write handling.