# atMb 0.4 user guide ## Thread and PLC calls One C worker progresses all TCP/RTU client transactions and TCP slave connections. It owns no pointers into IEC memory: request values, replies and slave tables live in fixed C storage. The external call copies buffers synchronously and serializes state access using a priority-inheritance engine mutex. No network wait or sleep is performed while that mutex is held. Serial driver calls can still take time; this is not a hard real-time or lock-free PLC interface. Continue calling each client/request and slave every PLC scan. Client request selection is still performed by the IEC scheduler. A transaction can finish while the PLC is not scanning, and its result waits for the next scan; the worker does not independently cycle through the PLC request registry. TCP slaves respond from the last copied memory snapshot between scans. ## Optional worker configuration and a separate core ```iecst VAR commWorker : atMb.Worker; END_VAR // Example only: CPU 2 must be online and permitted on this PLC. commWorker(in_cpu := 2, in_interval := T#1MS, in_watchdog := T#2S); ``` Use only one Worker configuration instance for the component. Clients/servers start the worker automatically with defaults even without this FB. Default CPU -1 uses the thread creator's inherited affinity mask; it is not a promise of all CPUs. A nonnegative value pins the worker to that Linux logical CPU ID. CPU affinity does not reserve an exclusive core or move the PLC task: choose a CPU outside the PLC task's configured affinity where the runtime allows it. Changes affect this worker only. Failure is visible in `out_errorCode` and `out_osError`; no silent fallback. The worker uses normal OS scheduling and explicitly avoids inheriting a PLC task's real-time priority. Sleep interval is 1..20 ms, default 1 ms; scheduling jitter can make actual intervals longer. Very short reply deadlines must account for worker interval and transaction framing. `out_cycles` helps monitor worker progress. ## Scan-loss watchdog Each client/server refresh call renews its own lease; another client's scans do not keep a stopped client alive. Default expiry is 2 s, configurable 100 ms..60 s. If scanning stops, the worker closes that context's connection/listener. In-flight requests finish as cancelled; potentially transmitted writes retain uncertainty. Handles/storage remain allocated for recovery. The next client/server refresh resumes connection attempts using the same context. Explicit release frees it. Choose a watchdog longer than the worst expected PLC scan gap. This bounds how long a stopped PLC's server can respond with its last memory snapshot; it is not an immediate CODESYS application-stop hook. Component exit stops and joins the worker before freeing connections. Repeated thread shutdown/start is tested. ## TCP read ```iecst VAR mb : atMb.ClientTCP; readHolding : atMb.ReqReadHolding; values : ARRAY[0..9] OF UINT; END_VAR mb(in_ipAddress := atMb.To_IPAddress(192,168,50,10), in_port := 502, in_enable := TRUE, in_timeout := T#500MS, in_reconnectDelay := T#100MS); readHolding(client := mb, in_unitId := 1, in_startAddr := 0, in_quantity := 10, in_dataOffset := 0, data := values); ``` Keep one IEC task as owner of the related FB instances and arrays. Call the client before request registration on startup; polling starts after registration. The C entry point is serialized but that does not make concurrent IEC FB access safe. TCP addresses are four BYTEs; slave bind addresses are packed DWORDs. RTU uses `ClientRTU(in_device := '/dev/ttyUSB0', in_baudRate := 9600, in_parity := 0, in_dataBits := 8, in_stopBits := 1, in_rs485 := FALSE)` and the same request FBs. RTU IDs must be 1..247. The runtime account needs serial permissions. Kernel RS485 direction control requires a supported driver. USB automatic-direction adapters generally use FALSE. Supported baud rates: 1200,2400,4800,9600,19200,38400, 57600,115200. Physical timing/driver validation remains necessary. ## Requests, data and priorities | Block | Function | Array | Maximum quantity | |---|---|---|---| | ReqReadCoil | 1 | BOOL | 2000 | | ReqReadDiscrete | 2 | BOOL | 2000 | | ReqReadHolding | 3 | UINT | 125 | | ReqReadInput | 4 | UINT | 125 | | ReqWriteCoil | 15 | BOOL | 1968 | | ReqWriteHolding | 16 | UINT | 123 | Protocol addresses are zero-based; `in_dataOffset` is the actual array index, not a relative offset. Effective length is MIN(quantity, remaining array capacity). Zero length disables a request and now retains its statistics history. Arrays and FB instances must stay valid. There are 16 shared TCP/RTU client slots, 100 IEC requests per client, one in-flight transaction per client and four TCP server slots. Lower `in_priorityCurrent` wins; oldest start age breaks ties. A request need not reach zero to run. Success restores `in_prioritySetpoint`; errors use 10/40/90 priority backoff. `in_minDelay` is start-to-start eligibility, not a fixed period. Successful reads update the destination slice. Errors retain previous data; use `out_validData AND NOT out_stale`. Data age includes time the completed reply waited for a PLC scan. Client release invalidates cached data but does not erase arrays. An exception reply indicates communication, but does not produce valid read data. Writes snapshot their source slice at submission. The worker never automatically replays a request. The IEC scheduler still polls write FBs cyclically. Set client `in_holdUncertainWrites := TRUE` to pause an uncertain write after a failure; `writeNow()` clears the hold and sets priority zero once the application decides retrying is appropriate. It does not bypass min-delay/connection conditions. ## Timeouts and reconnects Request `in_timeout` is numeric milliseconds (SYSTIME); client `in_timeout` is TIME. Nonzero request timeout wins, then client timeout, then the existing baud/data-rate formula. TCP's calculated default is about 38 ms, so an explicit timeout is clearer. The C worker uses CLOCK_MONOTONIC for deadlines, independent of PLC-provided time. `in_reconnectDelay` defaults to 100 ms. Recovery proceeds without PLC ticks while the scan lease is valid. Actual downtime includes failure detection, retry delay, worker scheduling and remote-device readiness. Idle TCP disconnects are detected; there is no zero-downtime guarantee. TCP_NODELAY reduces small-message coalescing. `recreateClient()` closes/recreates a context and cancels any active request. `release()` also sets `in_enable := FALSE`; a subsequent call explicitly passing TRUE re-enables it. Closing a context clears C lifetime counters. ## Client statistics Both clients expose `stats : ClientStats` and a public string property `toString`. The monitor display and `stats.toString` use `OK:/Er:`. For example, requests with 10/2 and 7/1 completions/errors show `OK:17/Er:3` on the client. | Client member | Aggregation | |---|---| | doneCnt / errorCnt | Sum of registered request successes/failures | | sentCnt / replyCnt | Sum of accepted submissions / normal or exception replies | | exceptionCnt / timeoutCnt | Sum of exception replies / result 5 or 6 timeouts | | offlineCnt | Sum of request online-to-offline transitions | | requestCount | Registered requests, including disabled ones | | activeCount | Nonzero effective-length requests | | onlineCount / offlineCount / unknownCount | Active request communication state | | busyCount | Active requests executing | | staleCount | Active read requests with stale data | | heldWriteCount | Active write requests paused after uncertain delivery | | totalValidDuration | Sum of successful transaction duration totals, ms | | averageValidDuration | Weighted mean: totalValidDuration / doneCnt, integer ms | | longestValidDuration | Maximum successful duration across requests | | online / offline | Nonempty active set, all online / all explicitly offline | Historical counters include registered inactive requests; state counts include only active requests. An empty client is neither online nor offline. Aggregate counters are ULINT. Per-request counters retain their existing types and saturate rather than wrap; request offline counts saturate at UINT max. Successful duration accumulation stops when the associated success counter saturates to keep the mean consistent. There is no misleading aggregate of consecutive-error streaks or unrelated start intervals. `numMsgSent`/`numMsgReply` remain as saturated UDINT mirrors of aggregate totals. The one-second window fields remain scan-published counts/duration totals. Request `lastValidDuration` now measures C submit-to-completion, excluding the PLC pickup delay. `resetStats()` resets totals, duration history, timeout and offline counts consistently, while retaining connection state and data freshness. Resetting during a transaction allows its eventual completion to be counted after reset. `out_errorCode` is the request result; `out_lastErrorCode` is the client's last engine error. OS errno is `out_socketError`. Historical last errors may persist after recovery. Result 260 means worker/affinity setup failed. A non-timeout failure no longer increments timeoutCnt. See the API reference for all declarations. ## TCP slave memory exchange `SlaveTCP` and `ModbusSlave` provide the same TCP server behavior. Supply four arrays: `aCoilsMemory`, `aDiscreteInputsMemory`, `aHoldingRegistersMemory`, `aInputRegistersMemory`. Their lower/upper bounds are Modbus addresses within 0..65535; max 2000 per table. FC1/2/3/4 read; FC5/6/15/16 write coils/holding registers. Bind IP 0 means all interfaces; interfaceName must remain empty. Up to eight peers per server. Remote changes are marked dirty in C. An old PLC push cannot overwrite dirty values before pull acknowledges them. Multiple remote writes before a scan expose the latest value, not an event history. After pull, a later application push may intentionally override those values. Other tasks must not race the array exchange. Table bounds/length changes require `in_reset := TRUE` to recreate the server; a changed mapping is rejected rather than silently discarding pending writes. Online-change pointer ownership and physical hardware certification remain future work. This release needs a full download and on-target validation.