Skip to content

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.

One stored network, two editable projections held side by side: the interlocked-speed Function Block Diagram and the Structured Text view of the same logic.
The subset boundary enforced at author time: out-of-subset Structured Text is refused with a located error, and block execution order renumbers in place.

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
6.7.2 and 6.3.5: a transition condition authored against the standard's own vocabulary, charge.T >= chargeTime, where chargeTime is a TIME parameter defaulted to T#30s.
6.7.6 and 6.7.7: the divergence bar auto-created grouping both branches, born Simultaneous, then flipped to Selective with a condition per branch.

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 via WAIT(T#duration) and WaitSeconds(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 — an ILCK input / interlockAddress parameter forces the configured safe value while tripped, and PID offers a TRK integrator-hold input plus a TRK_VAL back-calculation output-tracking input (wired from the AO's OUT) 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), whose OUT is 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) or holdLast (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 the ILCK_BYPASSED output and gated/audited at the gateway via the interlock:bypass permission (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 and PID'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
The cyclic scan running: live block I/O values overlaid on the interlocked-speed network, the device interlock ARMED, and every declared tag streaming beneath it.

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, fbNetworkRef JSON 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_running Prometheus metric name preserved for dashboard continuity. The underlying gauge is now metrics.CMControlProgramRunningGauge.

Phase 3 notes:

  • The internal runtime HTTP API (control-operator → unit-runtime) was cut over to ControlProgram terminology: /api/v1/controlprograms, wire field connections (was dataConns), persisted state file last-program.json (was last-network.json). See docs/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 FunctionBlockType declares 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.parameters declares 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, and PROMPT builtins. The standard's scan-cyclic action model does not describe such programs. We replaced the qualifier letters with a single per-step waitForAction boolean 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 PT on TON/TOF/TP and PV on CTU/CTD as 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 in pkg/fbruntime/blocks read pt and pv once, 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 to PT or PV is 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.