Table of Contents

Indexing Position Tables

Indexing Position Tables is the machine plane's single-brand leaf: the two global position lists a Sinumerik control resolves coded-position words against, edited as drafts and saved whole. It lives on the General Setup page at /general-setup under the Control-Tree id equipment/controller/machine/indexing-positions, and of the five controller brands only Siemens grows it. The tables it edits are machine data of the Siemens machine-data table; the assignment that decides which axis reads which of them is shown here and edited on the sibling leaf, Parameters (Native).

Important

Anatomy makes no claim that any id named here is stable across versions. The migration hop that keeps an older ?tree= value resolving is described in Tree Ids and Routes.

The One Single-Brand Node

The branch builder pushes this leaf behind the hasIndexingTables snapshot flag, and that flag is a pure type probe: it reports whether the runner's brand parameter table is the SiemensMachineDataTable. Nothing about the tables' contents is examined, so the node grows on every Siemens runner whether or not a single position has been entered. Only the Siemens preset carries that table, which is why this leaf is the machine plane's one single-brand row in the Brand Matrix; the program-data plane beside it has several.

The flag and the panel's own read do not ask quite the same question. The flag inspects the first brand parameter table in the resolved dependency list; the panel's reader looks for a Siemens machine-data table anywhere in it. The two agree on every shipped preset, where the Siemens machine-data table is the only parameter table present.

That table is also the sole implementer of IIndexingPositionConfig in the engine, so nothing else in a runner can supply an indexing table and no other brand can grow this node by carrying a different type.

What the Two Tables Are

The leaf edits IndexAxPosTab1 and IndexAxPosTab2 — the general machine data MD10910 and MD10930. They describe axes that take up discrete stations rather than arbitrary positions: Hirth-coupled tables, indexing rotaries, turret-style workholders.

  • They are global, not per-axis. Each is one ordered list shared by every axis assigned to it, so an edit to Table 1 changes every axis whose assignment reads 1.
  • Row order is the position number, and numbering is 1-based. Row 1 is indexing position 1. The used-length machine data beside each table — MD10900 and MD10920 — is not stored: the list count is the used length, which is why the panel has no length field.
  • Values are in the axis' own native units — degrees on a rotary axis, millimetres on a linear one — and the panel prints no unit suffix on the cells, because the unit follows whichever axes read the table.
  • Values must be strictly ascending, and where a modular rotary axis reads the table they must also satisfy 0 ≤ position < 360.
  • At most 60 entries per table, the MD10910 / MD10930 array size. Finer station counts are what the equidistant definition below exists for.

What consumes them

The tables are read at the write stage of the parsing pipeline, through TryGetIndexingPosition(API) and TryFindIndexingAnchor(API), for the Siemens coded-position coordinate functions CAC(), CIC(), CDC(), CACP() and CACN() — the family whose argument is a position number rather than a coordinate. The Siemens per-word coordinate syntax unwraps those verbs only on axes that IsIndexingAxis(API) reports as usable, and the rotary-only members of the family additionally require a rotary axis; the rotary words are then resolved by the ABC write pass and the linear words by the incremental-resolve pass, both through the shared coded-position helper.

An empty table is a real state with a visible consequence. An axis assigned to a table that holds no entries is not a usable indexing axis, so its coded-position words are left unrecognised and surface as unresolved text rather than being resolved against nothing. The engine lookups themselves deliberately do not validate the Siemens constraints — a table that breaks them resolves nonsense positions with no diagnostic — which is why the write endpoint, and this panel with it, is where the rules are enforced.

Machine Data, Not Program Data

The tables belong to the machine plane rather than the program-data plane: they configure the machine's stations, not a part's setup, and they carry no per-workpiece meaning the way a work coordinate or a datum shift does. That is the classification the branch builder gives the node, and it is the reason the node sits beside Machine Limits and Rapid Feedrates rather than beside Work Coordinates.

Their storage half is a separate question, and the answer is the project. The Siemens preset carries a SiemensMachineDataTableProxy, not a table: the proxy holds a fixed machine-config seed, deep-clones it into the project's per-case list only when the project has no Siemens machine-data table yet, and thereafter resolves the project's own table. Three consequences follow, and they are the ones the plane's other project-owned leaves live with — Machine Limits, Rapid Feedrates, Home / G28 Reference, M-Code Declarations and Parameters (Native), all rows of the same per-case table. The plane's runner-owned leaves get the opposite of all three, and which half a leaf falls in is listed on Machine and Controller Plane:

  • Edited positions are stored on the project, serialized with the per-case table as one XML element per entry carrying its table number and its value.
  • Installing another Siemens runner, or re-applying the Siemens brand, leaves them alone: the incoming proxy re-binds to the project's table instead of cloning its seed over it.
  • Saving a controller file captures the seed, not the edited table. A .Controller written after the tables were filled in carries the preset seed they were cloned from.

Switching to any other brand removes the Siemens machine-data table from the project, because no proxy of the incoming runner resolves it, and the positions go with it. Switching back clones a fresh table from the seed rather than restoring the removed one — see Brand Switch.

The Assignment Is Shown Here and Edited Elsewhere

Above the two drafts the panel renders one display-only table: Axis against Indexing assignment (MD30500), the per-axis machine datum that decides what an axis does with the two global lists. Four values are named:

Assignment Label the user reads Meaning
0 Not an indexing axis the axis ignores the coded-position family
1 Table 1 (MD10910) the axis reads the first draft below
2 Table 2 (MD10930) the axis reads the second draft below
3 Equidistant (MD30501–MD30503) positions come from a spacing rule, not from either table

Any other stored value renders as the bare number.

The rows are the axes that carry an MD30500 entry, not the plane's usual axis set. Every other per-axis leaf reads the table's axis-type rows — the set a machine-tool install stamps the chain's axis codes into — while this one reads the keys of the assignment row itself, sorted by axis name. An axis of the machine with no assignment entry does not appear here at all, and an assignment entry written against a name the machine does not have does.

An axis the table reports as modular rotary carries the note (wraps 0–360°) beside its name, and its presence is what turns on the one-revolution rule for whichever table it reads. That report is the machine-axis contract's default — IsModularRotary(API) is not overridden by any parameter table — so on this branch every rotary and every spindle-mode axis counts as modular.

Nothing on this leaf writes an assignment. The panel renders the value as plain text, and the leaf's REST surface exposes a reader for the two tables with their per-axis assignments and a writer for one position table; no endpoint of its own writes an assignment. MD30500 is written where every other raw machine datum is written: on Parameters (Native), as a row of the Axis parameters (integer) section, added through the Section / Parameter id / Axis / Value (raw) footer with the section set to Axis (integer). With no assignment row anywhere on the table this panel says so and points there: "No axis declares an indexing assignment (MD30500) yet — add it as a per-axis integer parameter in Parameters (Native)."

The equidistant definition is edited entirely on that same sibling leaf and has no surface here. Its three machine data — the numerator MD30501, the denominator MD30502 and the offset MD30503 — are ordinary parameter rows, and an axis on assignment 3 consults neither of the two tables this panel edits. On a modular rotary axis the numerator is ignored and the revolution is divided into MD30502 positions; elsewhere the spacing is the numerator over the denominator and the position count is unbounded.

Draft, Validate, Save Whole

This is the branch's one draft-then-save table, and it departs from the shared commit rule that Editing Contract sets for its siblings. Every other table in the branch commits per cell and rolls a failed write back; this one commits nothing until a button is pressed, and keeps a failed edit on screen.

  • Cells bind straight into the draft. Each numeric cell is bound with a two-way model and carries no commit handler, so a cell's commit — which the widget runs on blur and on Enter, never on a keystroke — lands in the draft row and goes no further. The badge, the validation line and the two buttons therefore follow those commits rather than the typing. The field itself still refuses text it cannot parse, with an untranslated message under the box; it carries no minimum and no maximum here, so every rule below is the draft validator's — see Numeric Input.
  • Add and delete are draft operations too. Add Position appends an empty row and is disabled at 60; the row's delete button removes it from the draft with no confirmation and no request.
  • An orange unsaved badge appears beside a table's title while the draft differs from what was last saved, compared row count first and then value by value.
  • Save Table sends the whole list for that one table and is disabled while the draft is clean or while validation fails. Revert restores the draft from the last saved values.
  • The validator mirrors the endpoint's own rules and reports the first violation as a line under the table: the per-table maximum, a fill in position … (or delete its row) line naming an empty or non-finite cell, a strictly-ascending check naming both offending positions with their values, and the 0 ≤ position < 360 range when a modular rotary axis reads that table.
  • A failed save does not roll the draft back. The draft stays dirty and the badge stays up, so the work is not lost — the opposite of every other panel in the branch.
  • Saving an empty table clears it. The endpoint accepts an empty list, and the axes assigned to that table then stop being indexing axes.

The endpoint enforces the same four rules independently, so the panel's validation is live feedback rather than the gate. A save that passes is applied to the live table and the panel does not re-read: it marks the draft saved from what it sent.

What a Freshly Switched Siemens Runner Shows

Default3Axis — the seed the Siemens proxy clones — declares a linear X, Y and Z, a reference position and a velocity for each, a maximum spindle speed and six note-only OEM M-codes. It declares no MD30500 assignment and no entry in either position table. So a project that has just been switched to Siemens grows this node, opens it successfully, and finds it completely empty: the assignment caption in place of the axis table, and two titled tables with headers, no rows and an Add Position button.

This leaf is also the only place the two lists appear. Parameters (Native) shows every row of the machine-data table's three parameter dictionaries, and the two position tables are not in any of them — they are separate list properties, so this panel is the whole editable surface for MD10910 and MD10930.

The panel opens through the branch's two-layer empty gate: the shared "No NC runner — load a project first." from the runner snapshot, then "No Siemens machine-data table on the active runner." from its own read. The second line is also what a failed read leaves on screen, since the presence flag starts false and the failure path only raises a toast.

Layout

  • General Setup Control Tree — the left dock of /general-setup
    • Controller Node Row
      • Machine / Controller Group Row
        • Indexing Position Tables Node Row — equipment/controller/machine/indexing-positions, between Subprogram Folders and Parameters (Native)
  • Editor Row — the panel of the selected node
    • Indexing Position Tables Panel — one column, gutter-spaced
      • Description Caption — "Global indexing position tables for coded-position programming (CAC/CIC/CDC/CACP/CACN). Row order is position-number order — row 1 is indexing position 1. Values are in the axis' native units (degrees for rotary, mm for linear) and must be strictly ascending. Which axis reads which table is MD30500, edited in Parameters (Native); an axis whose table is empty is not an indexing axis (its coded-position words stay unresolved)."
      • Assignment Table — dense, flat, bordered; display-only
        • Header Row — Axis, Indexing assignment (MD30500)
        • Data Row — the axis name in bold, with (wraps 0–360°) beside it on a modular rotary axis, then the assignment's label
        • No-Assignment Caption — replaces the table when no axis carries an assignment
      • Position Table Block — one per table, twice
        • Title Row — Table 1 (MD10910) or Table 2 (MD10930), then either used by and the names of the axes assigned to it or not used by any axis, then an orange unsaved badge while the draft is dirty
        • Table — dense, flat, bordered
          • Header Row — Position #, Value, and an unlabelled action column
          • Data Row — the 1-based position number in bold, the numeric cell, and a delete button that removes the row from the draft
        • Validation Line — the first rule the draft breaks, in the negative colour
        • Button Row — Add Position (disabled at 60 rows), then Revert and Save Table, both disabled while the draft is clean and Save Table also while validation fails
      • No-Table Body — replaces everything above: "No Siemens machine-data table on the active runner."
      • Shared Empty State — replaces the whole body while the snapshot reports no runner: "No NC runner — load a project first."
    • Toast — negative, three seconds, the panel's context followed by the server's own message

Source Code Path

See HiNC App Anatomy for git repository links.

Web Application

HiNC-2025-webservice (Quasar CLI SPA):

  • wwwroot-src/src/components/controlTree/SoftNcIndexingPositionsPanel.vue — this panel: the draft model over the two tables, the dirty comparison behind the badge, the validator that mirrors the endpoint's rules, the display-only assignment table with its four labels and its wrap note, and the save that marks the draft clean without re-reading.
  • wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the node's id, label and label key, and the snapshot flag it is pushed behind, between the subprogram and native leaves.
  • wwwroot-src/src/api/softNcRunner.ts — the reader that parses the two tables and the axis rows, the whole-table replace and its documented refusals, and the snapshot flag the builder gates on.
  • wwwroot-src/src/composables/useSoftNcRunner.ts — the shared runner snapshot the first empty layer reads.
  • wwwroot-src/src/components/widgets/NumericInput.vue — the cell: the two-way binding this panel uses in place of a commit handler, the blur-and-Enter moment that binding emits on, the empty-to-null parse the validator then reports, and the untranslated parse message.
  • wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue — the shared no-runner line.
  • wwwroot-src/src/components/controlTree/SoftNcNativeParamsPanel.vue — the sibling panel that owns the assignment: the integer per-axis section and the footer that adds a row by id and axis.
  • wwwroot-src/src/i18n/en/softNc.ts — the node label, the description caption, the four assignment labels, the wrap note, the table titles, the used-by captions, the four validation messages and the absent-table line quoted above.
  • wwwroot-src/src/i18n/en/common.ts — the shared Axis and Value column headers.
  • Mech/SoftNcRunnerController.cs — the REST surface: the read that pairs the two tables with the per-axis assignments and reports presence from the Siemens table alone, the whole-table replace with its capacity, finite, ascending and one-revolution checks, the integer per-axis parameter write the assignment is edited through, and the brand switch whose sweep removes the table on leaving Siemens.

HiAPI Engine

  • HiMech/NcParsers/Dependencys/IIndexingPositionConfig.cs — the contract: 1-based position numbering, the native-unit and frame rules, the position count, the cyclic test, the number-to- coordinate lookup and the anchor search, and the rule that an axis whose table is empty is not a usable indexing axis.
  • HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTable.cs — the two position lists, their XML round-trip and the statement that the lookups do not validate the Siemens constraints, the MD30500 assignment dictionary, the equidistant spacing resolution over MD30501–MD30503, the five contract implementations, and the default seed that declares none of them.
  • HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTableProxy.cs — the get-or-create proxy: the seed serialized on the runner, the deep clone installed only into a project that has no table, and the deliberate refusal to implement the machine-config interfaces itself.
  • HiMech/NcParsers/Dependencys/IMachineAxisConfig.cs — the axis contract, and the modular-rotary default that makes every rotary and spindle axis subject to the one-revolution rule.
  • HiMech/NcParsers/SoftNcRunner.cs — the Siemens preset that carries the machine-data proxy, and the proxy resolution every read on this leaf goes through.
  • HiMech/NcParsers/Syntaxs/SiemensSyntaxUtil.cs — the syntax list that wires the coded-position producer and its two write-stage consumers into the Siemens pipeline.
  • HiMech/NcParsers/EvaluationSyntaxs/Siemens/SiemensAcIcSyntax.cs — the producer: it unwraps the five coded verbs only on usable indexing axes and stamps the per-word override, leaving the word untouched elsewhere.
  • HiMech/NcParsers/LogicSyntaxs/CodedPositionUtil.cs — the shared resolution: position number to coordinate, the hold-on-failure semantics, and the diagnostics for an invalid number or a table that has gone missing between stages.
  • HiMech/NcParsers/LogicSyntaxs/McAbcSyntax.cs, HiMech/NcParsers/LogicSyntaxs/IncrementalResolveSyntax.cs — the two write-stage consumers, rotary words and linear words.
  • HiMech/NcParsers/LogicSyntaxs/McAbcCyclicPathSyntax.cs — the tail pass that turns the resolved directional approach into a path, and the one other syntax pass that reads the modular-rotary flag directly.

See Also

  • Machine and Controller Plane — the plane this leaf sits on, and which half of the project each of its neighbours is stored in
  • Brand Matrix — the gate behind this node, why it is the machine plane's only single-brand row, and what every other flag probes
  • Editing Contract — the per-cell commit rule the rest of the branch follows and this panel deliberately breaks
  • Native Parameters — where the MD30500 assignment and the equidistant machine data this leaf only displays are actually edited