LinuxCNC context diagram — as published vs corrected

docs/src/getting-started/images/LCNC_Architecture_C1.drawio.svg, merged by PR #3781 on 2026-03-01. The working base of this page is their work: the diagram zz912 drew, shaped in review by smoe, c-morley and BsAtHome in that thread, and merged by andypugh. Both states are redrawn here from the same code, so the only differences between them are the corrections. The three actor boxes — operator, developers, integrator — have been dropped from both views, along with the thirteen arrows that started from them. The third view is not that drawing at all: it is rebuilt from the source, cross-checked against the findings file, and its structure differs because the published structure does not match the code. Third sheet of the audit — the verification passes behind it, and the corrections they forced on this page itself, are recorded in the closing notes.

First two: same drawing, changes in red. Third: redrawn from scratch.
Embedded Tabs andPanels GUIGmoccapy / Axis / Qt LinuxCNC Core Runtime Motion controller Trajectory planner Kinematics Task controller G-code interpreter Status & command IPC HAL Interface Boundary Pins . Signals . Threads . Functions INI Configuration HAL Configuration (.hal files, loadrt, nets) Integrator-defined topology HAL Modules (drivers, counters, stepgens, logic) HAL Components - Library HAL Components - Custom WizardsPNCconf / Stepconf Machine Hardware (Panels, buttons,potentiometers) Machine Hardware(axes, spindle, IO, safety) Terminal halcmd / halshow / linuxcncrsh linuxcncrsh halcmd / halshow attach to HAL, not to the core 1 2 signals and components must be used for using LCNC signals and components are optional (LCNC can be used without them)
scheduling boundary — SCHED_FIFO threads inside rtapi_app, not a kernel boundary NON-REALTIME — ordinary Linux processes, no timing guarantee rtapi_app — the realtime domain Wizardspncconf / stepconf INI file[KINS] · periods limits · which GUI HAL filesloadrt · addf net · setp GUI Axis / Gmoccapy / QtVCP embedded tabs & panels export HAL pins linuxcncrshNML over the network halcmd / halshow HAL clients — hal_init() they never touch NML NML — three channels emcCommand 8192 queued · emcStatus 20480 overwritten emcError 8192 queued linuxcncsvr — its own process; owns the three NML channels milltask — the task process task controller · rs274ngc · iocontrol HAL pins (no separate EMCIO) emcmot shared segment — key 100 one command slot + mutex, commandNum → commandNumEcho, 1 s timeout status seqlock (head / tail) · error ring 32 × 1024, newest lost when full HAL — 2 MiB shared memory, key 0x48414C32 pins · signals · parameters · functions · threads servo-thread — servo_period_nsec motion-command-handler motion-controller tpmod · homemod one of 19 *kins separate modules (loadrt), called from motmod's functs both exported by motmod via hal_export_funct() pid.N.do-pid-calcs encoder · stepgen.capture-position members, not execution order — the pass opens with the driver read (addf order) base-thread created only when servo_base_ratio > 1 stepgen.make-pulses hardware drivers, in these same threads hostmot2 (Mesa) · lcec (EtherCAT) parport · and the rest Machine hardware drives · encoders · limit and home switches · spindle · field I/O

1  The terminal tools sit on the wrong side of the boundary

As published, one box holds halcmd / halshow / linuxcncrsh and draws a single link — to the Core Runtime. Two of those three attach to HAL instead:

halcmd.c:107 calls hal_init(comp_name) — halcmd is a HAL component. halshow's man page: "a GUI interface to view and interact with a running HAL session", and it drives halcmd internally (halshow.tcl:825, 1224). Only linuxcncrsh commands the core — "text-mode interface for commanding LinuxCNC over the network".

This was raised in review and never resolved. smoe wrote: "The Devs may also use command line variants as a HAL interface … Examples are linuxcncrsh or halcmd." The reply added a Developers→Terminal arrow; the link to HAL was never drawn.

2  Embedded tabs and panels have no link to HAL

Their entire purpose is to export HAL pins — pyvcp_widgets.py:205,209 and gladevcp/hal_widgets.py:44-45 call newpin(). As published they connect only to the GUI. On a diagram whose central organising line is the HAL Interface Boundary, leaving out the HAL link of the one component that exists to cross it is a real gap.

Left alone on purpose — debatable, not wrong

Kinematics and Trajectory planner inside "Core Runtime". Both are RT modules loaded by loadrt (loadrt trivkins, chosen by [KINS]KINEMATICSaxis.ini:140) — that is, by what the diagram itself files under HAL Configuration (.hal files, loadrt, nets). A defensible functional grouping, but inconsistent with its own labelling.

"HAL Components – Library / Custom" feeding "HAL Modules". LinuxCNC calls both components; the split invents a hierarchy. Readable as source-versus-loaded, so confusing rather than false.

"Machine Hardware" labels two different boxes — panels and buttons on one side, joints and spindles on the other.

"Machine Hardware (axes, spindle, IO, safety)". The moving parts of a machine are joints; "axes" here is the conflation the findings' erratum 6 documents elsewhere. At context level, debatable — left as published.

The caption added during review also matters: "It is not intended to help you understand the functionality of LinuxCNC." That covers the simplifications above. It does not cover a wrong connection — showing who talks to what is precisely what this diagram sets out to do.

What dropping the three actor boxes changes

Operator, Developers/Testers and Integrator were the actors of a C4 level-1 context diagram — a system in its scope, with its users and neighbouring systems. Removing them, and the thirteen arrows fanning out from them, turns this into something else: a map of the parts and how they are wired. Nothing is orphaned by their removal; every remaining box still has at least one connection.

That is a legitimate second diagram, and close to what c-morley kept asking for on both threads — "Keep it simple as it was and then build a different purpose built diagram for interrogators [sic] or users or what ever your target audience is." But it no longer answers the question the original was built to answer. zz912's stated aim was "to show how developers, integrators and operators are involved in the project. That's all." Judged as a technical map this version is clearer; judged as what it was drawn to be, the actors were the content.

Worth keeping straight if any of this ever goes upstream: the two red corrections are defects in the published figure, and this removal is a change of purpose. They should not travel in the same sentence.

What changed, and why — every point checked against the source

The motion controller moved down, inside HAL. It was drawn above the HAL boundary, as a peer talking across it. It is a HAL function: motion.c:1030,1037 export motion-controller and motion-command-handler through hal_export_funct(), and the config file does addf motion-controller servo-thread. It does not talk across HAL — it runs inside it. tpmod, homemod and the kinematics module are called from within that function, so they moved with it. Homing was missing altogether and is now shown: homemod.c:23 has its own rtapi_app_main.

The scheduling boundary is drawn. The published figure has none, and puts task and motion in one box. They are different processes in different domains. The label says scheduling, not kernel: on the default uspace build over PREEMPT_RT, "realtime" components are SCHED_FIFO user threads inside rtapi_app. That distinction is erratum 9 of the findings file.

The two IPC mechanisms are separated. One label — "Status & command IPC" — covered both. Above the boundary, NML: three channels, emcCommand 8192 queued, emcStatus 20480 overwritten, emcError 8192 queued. Across the boundary, something else entirely: the emcmot segment at key 100 — a single command slot under a mutex, with a commandNumcommandNumEcho handshake and a 1 s timeout, a seqlock for status, and a 32 × 1024 error ring that refuses the newest message when full. Not a queue, and not NML.

The terminal tools are split. halcmd and halshow attach to HAL and never touch NML; only linuxcncrsh speaks NML. Its line runs from userspace straight down into the HAL block, which also shows something the original hid: HAL shared memory is reachable from ordinary processes.

Smaller ones. linuxcncsvr now appears — and as its own process, which it is: the start script launches it before realtime is loaded (scripts/linuxcnc.in:803, under the comment "it owns/creates the NML buffers", :795) and task separately later (:824); the kill list names linuxcncsvr milltask side by side (:678). The milltask box states that iocontrol's pins live there and that no separate EMCIO process exists. The base thread carries its real condition, servo_base_ratio > 1, not a non-zero period. HAL's label includes parameters, which the original omitted.

Everything here traces to the findings file — errata 3, 5, 6, 8, 9, 29, 31, 32, 33, and the §2 material on the shared segment, the seqlock and the servo cycle. Nothing was drawn from a memory of how LinuxCNC ought to work.

Corrections to this page — 2026-08-06

A verification pass — four passes, separate oracles: the cited lines re-read in the pinned clone, the published .drawio's edge graph extracted, adversarial greps on the gates, the review-thread quotes re-read verbatim with gh — confirmed every code claim above except one, and caught three fidelity slips. Recorded here rather than silently repaired:

1. The rebuilt view drew linuxcncsvr inside "The LinuxCNC task process". It is a separate process — the start script runs it at step 4.3.1 ("it owns/creates the NML buffers", scripts/linuxcnc.in:795) and task at 4.3.7, and the kill list names linuxcncsvr milltask side by side (:678). The same class of error this page criticises — a process boundary drawn wrong. Now two boxes.

2. The c-morley quotation silently corrected his "interrogators" to "integrators". Restored verbatim with [sic] — when quoting, the words bind.

3. The as-published view wrote "(joints, spindles, IO, safety)" where the merged file says "(axes, spindle, IO, safety)" — an unmarked correction, contradicting this page's own promise that the only A/B differences are the flagged ones. Published wording restored; the joints question moved to the "left alone" list.

4. Wizard names: the A/B views now match the published PNCconf / Stepconf; the rebuilt view uses the command names pncconf / stepconf (src/emc/usr_intf/pncconf/Submakefile:3). Two wording fixes besides: tpmod/homemod/kins are "separate modules (loadrt), called from motmod's functs" — "linked into" was loose — and the servo-thread box now says its contents are members, not execution order.

Redrawn from the published SVG's own coordinates, so the layout matches closely enough to compare by flipping. It is a faithful redraw, not a pixel copy — open the original alongside if precision matters: docs/src/getting-started/images/LCNC_Architecture_C1.drawio.svg. Everything else in the figure checked out: the role structure, the wizard flows, operator ↔ GUI solid against operator ↔ physical panel dashed, integrator → hardware, HAL Modules ↔ Machine Hardware, Core ↔ HAL boundary, and the solid/dashed legend applied consistently throughout. Verified line by line against the pinned clone (caa13ca6ae) and corrected on 2026-08-06 — see the last note.