Skip to content

docs: structures, enumerations and arrays in Python and C++ function blocks - #15

Closed
thiagoralves wants to merge 1 commit into
mainfrom
docs/DOPE-584-native-block-composite-types
Closed

docs: structures, enumerations and arrays in Python and C++ function blocks#15
thiagoralves wants to merge 1 commit into
mainfrom
docs/DOPE-584-native-block-composite-types

Conversation

@thiagoralves

Copy link
Copy Markdown
Contributor

Adds two pages covering the types DOPE-584 unlocked for native blocks, and corrects what the existing pages got wrong. The docs still described the old world — base types and flat arrays only — while structures, enumerations, multi-dimensional arrays and arrays of structures all work now.

New pages

  • Python Data Types — structures, enumerations, arrays (including the lower-bound trap), arrays of structures, strings, temporal types, function block instances
  • C++ Data Types — the same ground on the C++ side, where almost every spelling differs

Everything here was run on hardware

Not written from reading the source. Each example was compiled and uploaded to an SLM-RP4 (Runtime v4) with openplc-cli, and the outputs read back through the debugger — 35 C++ patterns and 26 Python checks. Several of the findings contradict what I would have written from the code alone:

Finding Why it matters
Member spelling is opposite. Python keeps the Variables Table spelling (mot.speed); C++ sees the compiler's uppercase (mot.SPEED). Getting it wrong in Python is an AttributeError at runtime, not a build error. I hit this writing the examples.
Python lists use IEC indices. ARRAY [1..2] is a list of length 3 whose index 0 is None. for row in grid: hands you a None first.
grid(i, j), not grid[i][j] for multi-dimensional arrays in C++. [i][j] does not compile.
A scalar enum pin needs MODE m = mode; first. mode.get() returns a wrapper that will not cast to int. An array element is already the raw enum and skips the step — the two differ.
A function block instance must be VAR to be driven from Python. Declared as Input, all four pins still arrive and reads work, but writes never reach the PLC — a TON sits at zero with nothing to explain why. Verified both ways.
DATE is days; TIME/TOD/DT are nanoseconds. Confirmed on device: D#1970-01-1110, T#2s2000000000.

Also documents a failure mode that lies about itself: drop one of the four required imports and the block exits reporting "PLC runtime has stopped." while the PLC is plainly still running. The wrapper's liveness check calls os.kill, os was never imported, and the NameError is reported as a stopped runtime. Easy to hit, since the imports look unused.

Correction to an existing page

cpp-structure.md said ordering comparisons on STRING need .get() on both sides. They work directly on the variables; verified by compiling both forms.

Overlap with #14 — please read

#14 is open and touches two of the same files. It documents shared globals and function block instances, and its C++ instance section is correct — including that ton0(); is what makes the timer advance, which my hardware run confirms independently.

This branch is cut from main, so it does not include #14. Consequences:

Not covered

  • STRING[n] (a declared length) is still the transport's 126-character budget, so the docs state the cap rather than the declared length. Deferred to strucpp by DOPE-584.
  • Negative array bounds (ARRAY [-10..10]) are legal IEC 61131-3 but rejected project-wide by both the parser and the variables table, so they are not documented as usable.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UaSZK4LqFWtZpERcqnZ8uQ

DOPE-584 gave native blocks full IEC type parity, and the docs still described
the old world: base types and flat arrays only. Two new pages cover what a
structure, an enumeration and an array actually look like on each side, because
the two languages do not agree and the differences are silent when you get them
wrong.

Every example here was compiled and run on an SLM-RP4 (Runtime v4) through
openplc-cli, with the values read back over the debugger. The findings that
would not have survived guesswork:

- Member spelling is opposite between the two languages. Python keeps the
  spelling from the Variables Table (`mot.speed`); C++ sees the compiler's
  uppercase (`mot.SPEED`). Getting this wrong in Python raises
  AttributeError at runtime, not at build time.
- A Python list is indexed by the IEC index, so `ARRAY [1..2]` is a list of
  length 3 whose element 0 is None. Iterating it naively hands you a None.
- A multi-dimensional array is `grid(i, j)` in C++, not `grid[i][j]`.
- A scalar enumeration pin in C++ needs assigning to the raw enum first;
  `mode.get()` returns a wrapper that will not cast to int. An array element
  is already the raw enum and needs no such step.
- A function block instance must be declared under VAR to be driven from
  Python. Declared as an Input its pins still arrive, but writes never reach
  the PLC, so a TON sits at zero with nothing to explain why.
- DATE is a count of days while TIME, TOD and DT are nanoseconds.

Also documents the missing-import failure mode, which reports itself as
"PLC runtime has stopped." while the PLC is plainly still running: the
wrapper's liveness check calls os.kill, `os` was never imported, and the
NameError is reported as a stopped runtime.

Corrects one claim on the existing C++ page: ordering comparisons work
directly on STRING variables, without going through .get().

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01UaSZK4LqFWtZpERcqnZ8uQ
@thiagoralves

Copy link
Copy Markdown
Contributor Author

Folded into #14 — the two overlapped on cpp-structure.md and python-restrictions.md, and #14 already covered function block instances correctly (including that the C++ ton0() call is what makes a timer advance, which my hardware run confirmed independently).

Everything from this branch is now on #14 as 260504b, with the duplicate instance sections trimmed to links rather than kept twice. One PR, as asked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant