# atMb native TCP + RTU + TCP slave — development revision 0.9 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. 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. ```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 ``` 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. ## Build the IEC library without legacy objects 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. 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. ## TCP client 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. ## Native RTU ```iecst VAR bus : atMb.ClientRTU; read : atMb.ReqReadHolding; registers : ARRAY[0..9] OF UINT; END_VAR ``` ```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); ``` 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. 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. 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.