IEC 61131-3 Compliance Traceability¶
Standard: IEC 61131-3 Ed. 3.0 -- Programmable Controllers, Programming Languages Applicability: Procedural sequencing (SFC), step/transition logic (ST), control modules (FBD via cyclic scan runtime)
Overview¶
Cloud-Native DCS implements three of the five IEC 61131-3 programming languages:
| Language | Support | Usage |
|---|---|---|
| SFC (Sequential Function Chart) | Implemented | Procedural templates, recipe procedures |
| ST (Structured Text) | Implemented | Step actions, transition conditions; one of two co-equal editable projections of a control module's network |
| FBD (Function Block Diagram) | Implemented | Control modules (native cyclic scan runtime); the other projection of the same network |
| LD (Ladder Diagram) | Not supported | Out of scope -- not relevant to batch/DCS |
| IL (Instruction List) | Not supported | Deprecated in Ed. 3.0 |
A control module's logic is single-representation: it has exactly
one canonical, executable form (its function-block network), and ST and
FBD are two editable projections of it (ADR 0012).
The "author in the IEC 61131-3 language you know" language-choice claim
is therefore now true for control modules as well as for phase logic
(which interprets ST directly). The claim carries one honest caveat: a
control module's editable ST is the dataflow subset that maps onto a
function-block network: variable declarations, tag I/O, block
instantiations, expressions, function calls, and selection that compiles
to SEL/MUX/EN-gated blocks. General loops (FOR/WHILE/REPEAT),
CASE, and order-dependent sequencing are not part of the subset
(they have no dataflow drawing) and are rejected at author time. Full ST
remains available on the phase / SFC path. This subset boundary is
inherent to the languages (ST is a strict superset of FBD) and is the
same limit every mainstream PLC tool enforces.
Requirements Traceability¶
SFC (Section 6.7)¶
| Requirement | Description | Status | Implementation |
|---|---|---|---|
| 6.7.1 | Step types (initial, regular) | Implemented | InitialStep field on SFCStep; engine activates initial step on start |
| 6.7.2 | Transition conditions | Implemented | ConditionST field evaluated by ST interpreter each scan |
| 6.7.3 | Transition priority (top-to-bottom) | Implemented | Transitions sorted by priority ascending (lower number first); first one whose guard evaluates true fires. See pkg/sfc/engine.go. |
| 6.7.4 | Step activation/deactivation | Implemented | Active step set with activation time tracking |
| 6.7.5 | Action associations (N, P, S, R, L, D, SD, DS, SL qualifiers) | Deliberate deviation | We do not implement IEC 61131-3 action qualifiers. SFC actions in this DCS have temporal extent (multi-scan procedural ST with WAIT, MESSAGE, PROMPT), which the standard's scan-cyclic qualifier model does not describe. We provide a single per-step waitForAction boolean instead. Rationale and full execution model: Procedural SFC Dialect. Decision: #246. |
| 6.7.6 | Selective divergence/convergence | Implemented | SelectiveDivergence with priority-ordered branches |
| 6.7.7 | Simultaneous divergence/convergence | Implemented | SimultaneousDivergence activates all branches; convergence waits for all |
| 6.7.8 | SFC body (nested charts) | Implemented | SubChart field on SFCStep for recursive nesting |
| 6.7.9 | Timeout supervision | Implemented | Per-step TimeoutSeconds with timeout detection |
charge.T >= chargeTime, where chargeTime is a TIME parameter defaulted to T#30s.Structured Text (Section 7.3)¶
| Requirement | Description | Status | Implementation |
|---|---|---|---|
| 7.3.1 | Assignment statement | Implemented | := operator |
| 7.3.2 | IF/ELSIF/ELSE/END_IF | Implemented | Full conditional branching |
| 7.3.3 | CASE/OF/END_CASE | Implemented | Multi-branch integer/enum selection |
| 7.3.4 | FOR/TO/BY/END_FOR | Implemented | Counted loop with optional step size |
| 7.3.5 | WHILE/DO/END_WHILE | Implemented | Conditional loop with iteration limit (default 10000) |
| 7.3.6 | REPEAT/UNTIL/END_REPEAT | Implemented | Post-test loop; body runs at least once; iteration limit (default 10000) #362 |
| 7.3.7 | EXIT statement | Implemented | Breaks the innermost WHILE/FOR/REPEAT loop; runtime error if used outside a loop #362 |
| 7.3.8 | RETURN statement | Implemented | Ends ST program execution; legal at any nesting depth #362 |
| 7.3.9 | Expressions and operators | Implemented | Full operator precedence per Table 68 |
| 6.6.1 | Function call named parameters | Implemented | Func(name := expr) syntax; names stored in CallExpr.ArgNames |
| ext | CALL_SERVICE builtin (smart-device service invocation) |
Implemented | Dispatches an OPC UA Method bound via Unit.spec.serviceBinding; positional unit + service name, named inputs, returns typed result. One AuditRecord per invocation. #346 |
| ext | MTP_COMMAND / MTP_STATE / MTP_COMMAND_ENABLED builtins (MTP module service orchestration) |
Implemented | Drives a VDI 2658-4 module service declared via Unit.spec.serviceBinding: writes a Table 14 command word gated on the live CommandEn, selects a declared procedure, reads the reported state back. One AuditRecord per command; the reads emit none. #1379 |
Data Types (Section 6.3)¶
| Requirement | Description | Status | Implementation |
|---|---|---|---|
| 6.3.1 | BOOL | Implemented | TypeBool with TRUE/FALSE literals |
| 6.3.2 | INT | Implemented | TypeInt (Go int64) |
| 6.3.3 | REAL | Implemented | TypeReal (Go float64) |
| 6.3.4 | STRING | Implemented | TypeString with single-quoted literals |
| 6.3.5 | TIME | Implemented | TypeTime with T# literals (T#5s, T#1m30s) |
| 6.3.6 | DINT, LINT, UINT, etc. | Not supported | Only INT (64-bit signed) |
| 6.3.7 | Arrays, structs | Not supported | Out of scope for embedded ST |
Operator Precedence (IEC 61131-3 Table 68)¶
Implemented following the standard exactly:
| Precedence | Operators | Status |
|---|---|---|
| Highest | () parentheses |
Implemented |
NOT, unary - |
Implemented | |
*, /, MOD |
Implemented | |
+, - |
Implemented | |
<, >, <=, >= |
Implemented | |
=, <> |
Implemented | |
AND |
Implemented | |
XOR |
Implemented | |
| Lowest | OR |
Implemented |
Architecture Integration¶
Recipe (SFC) Procedural (SFC) Control (one network, FBD/ST views)
MasterRecipe Procedure ControlProgram (FB network)
ControlRecipe UnitProcedure FBD view ⇄ ST view (pkg/cmlogic)
Operation DI, DO, AI, AO
Phase PID, AND, OR
| | |
v v v
SFC Engine SFC Engine + ST FB Runtime (cyclic scan) + Drivers
(batch-operator) (procedural-operator) (unit-runtime)
- SFC Engine: Scan-cycle execution (200ms default), manages active steps, evaluates transitions via ST interpreter
- ST Interpreter: Evaluates step actions and transition conditions. I/O via
READ()/WRITE()context functions. Timing viaWAIT(T#duration)andWaitSeconds(n)with named parameter support - FB Runtime: IEC 61131-3 cyclic scan execution. Blocks execute in declared order each scan cycle, and protocol drivers bridge to physical I/O. Output blocks (
DO,AO) carry device-interlock support — anILCKinput /interlockAddressparameter forces the configured safe value while tripped, andPIDoffers aTRKintegrator-hold input plus aTRK_VALback-calculation output-tracking input (wired from theAO'sOUT) for bumpless transfer on interlock release (ADR 0007). Vendor-extension blocks beyond the standard set execute in the same scan — e.g.DEVSTATE, the derived device-state priority encoder (ADR 0018), whoseOUTis a STRING state word. A single block's runtime error degrades the scan without halting it (the faulting block is skipped and flagged, and healthy outputs keep regulating), and deliberate program removal drives outputs to their configured fail state,failState: safeValue(default) orholdLast(IEC 62443 SR 3.6, #972), an active drive in place of a passive freeze (ADR 0009). The interlock supports a first-class, time-boxed bypass evaluated in the scan (auto-expiring on the edge), exposed as theILCK_BYPASSEDoutput and gated/audited at the gateway via theinterlock:bypasspermission (ADR 0010). The full trip-bypass-re-arm lifecycle is on camera in Alarms and Interlocks and on the ISA-88 exception-handling section - Block parameter validation: a parameter absent from a document, or present with an empty value, takes the block's documented default. A parameter carrying a value that does not parse as its declared type refuses the load, so the program never reaches the scan (#1663, ADR 0064). The two used to be answered identically for
AI's engineering range,AO's output range andPID's gains. A mistyped bound or gain became the default, with nothing recording it. An engineering range is also declared whole or left entirely to driver discovery, since one bound alone would leave the runtime enforcing an interval the document does not state
Migration Status (IEC 61499 → IEC 61131-3)¶
| Phase | Scope | Status |
|---|---|---|
| Phase 1 | Replace FBNetwork / FBBlockType CRDs with ControlProgram / FunctionBlockType; cyclic-scan runtime; ~30 blocks ported; remove ECC/event-driven helpers from runtime |
Complete |
| Phase 2 | Cut controllers, unit-runtime adapter, gateway, and CLI over to the new types; drop dead legacy fallbacks and event/ECC DTOs; consolidate TagMapEntry.NetworkRef into ProgramRef |
Complete (#360) |
| Phase 3 | Unit-runtime HTTP API cutover to ControlProgram/FunctionBlockType shape | Complete (#361) |
| Phase 4 | ST language completeness (REPEAT/EXIT/RETURN, user-defined function blocks) | REPEAT/EXIT/RETURN complete (#362); user-defined function blocks still pending |
Phase 2 notes:
- Gateway-facing UI/CLI URL paths (
/api/v1/sites/{site}/fbnetworks,/api/v1/fbblocktypes,fbNetworkRefJSON tag) keep their pre-migration vocabulary so existing UI and CLI clients work unchanged. Only Go identifiers and CRD-internal field names moved to the IEC 61131-3 lexicon. dcs_cm_fb_network_runningPrometheus metric name preserved for dashboard continuity. The underlying gauge is nowmetrics.CMControlProgramRunningGauge.
Phase 3 notes:
- The internal runtime HTTP API (control-operator → unit-runtime) was
cut over to ControlProgram terminology:
/api/v1/controlprograms, wire fieldconnections(wasdataConns), persisted state filelast-program.json(waslast-network.json). Seedocs/architecture.md§ "IEC 61131-3 Phase 3 cutover" for the migration procedure and one-shot legacy filename fallback. - The legacy oneshot routes (
POST /api/v1/fbnetwork,/status,/stop) were dropped. They were unused outside of legacy tests.
Gap Analysis¶
Implemented¶
- Core SFC execution with steps, transitions, divergence/convergence
- ST with all basic data types, operators, and control structures
- FBD via native cyclic scan runtime
- Composite (derived) function block types. A
FunctionBlockTypedeclares a sub-network of blocks behind named data ports, and the runtime flattens it into the program when it loads (ADR 0065) - A parameter interface on a composite type.
spec.parametersdeclares each configuration value an instance may set, and an inner block reads one as{{.params.<name>}}. A type that wraps I/O therefore serves any number of devices (#1660) - Scan-cycle timing, hold/resume, abort, timeout
- Validation for both ST expressions and SFC chart structure
- CLI commands for control API group:
dcs create/delete/get controlprogram,dcs create/delete/get functionblocktype
Planned¶
- User-defined function blocks in ST
- Online change (modify running SFC)
- SFC diagnostic and monitoring per Section 6.7.10
Out of Scope¶
- Ladder Diagram (LD) -- not relevant to batch/DCS applications
- Instruction List (IL) -- deprecated in IEC 61131-3 Ed. 3.0
- Derived data types (arrays, structs, enums)
- Multiple integer widths (DINT, LINT, UINT, etc.)
- Function/function block declaration in ST (control-module ST is the dataflow projection of the FB network and no place to declare functions)
Deliberate deviations¶
These are places where we knowingly diverge from IEC 61131-3 because the standard's model does not fit the DCS's procedural-SFC use case. Captured here so auditors and recipe authors can find the rationale in one place.
-
Action qualifiers (§6.7.5 / §2.2.4.4). We do not implement N, P, S, R, L, D, SD, DS, or SL qualifiers. Our SFC actions are multi-scan procedural ST programs with
WAIT,MESSAGE, andPROMPTbuiltins. The standard's scan-cyclic action model does not describe such programs. We replaced the qualifier letters with a single per-stepwaitForActionboolean that honestly describes what the engine does. Decision recorded in issue #246. Full execution model: Procedural SFC Dialect. -
Timer and counter presets are configuration. The standard declares
PTonTON/TOF/TPandPVonCTU/CTDas input variables of the function block, so a conforming implementation re-reads them on every invocation and a preset may be driven from elsewhere in the program. The blocks inpkg/fbruntime/blocksreadptandpvonce, when the block is created, and never from the data bus. A preset is therefore fixed for the life of a deployed program, and changing one is a template edit and a redeploy. The ST authoring path enforces the restriction where it is written: a literal preset is recorded as a parameter, and a variable bound toPTorPVis rejected with a located diagnostic. Before issue #1655 it compiled to a data connection the block never read, which left the preset at zero with no diagnostic anywhere. A wait that has to be computed belongs on the phase or SFC path, which interprets ST directly.