This commit is contained in:
2026-09-09 17:35:23 +08:00
parent 2a98ae7556
commit 161af68fe3
1271 changed files with 58251 additions and 98639 deletions
@@ -0,0 +1,452 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>M-Code Declarations | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="M-Code Declarations | HiAPI-C# 2025 ">
<link rel="icon" href="../../../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../../../public/docfx.min.css">
<link rel="stylesheet" href="../../../../public/main.css">
<meta name="docfx:navrel" content="../../../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../../../index.html">
<img id="logo" class="svg" src="../../../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Anatomy-ControllerMCodes">
<h1 id="m-code-declarations">M-Code Declarations</h1>
<p>M-Code Declarations is the leaf that gives a machine's own M-codes a meaning the parser can act on —
what each machine-specific (OEM or PLC) code does — and it carries beside them the tool-change
trigger mode that decides whether a bare <code>T</code> word changes the tool by itself. It lives on the
General Setup page at <code>/general-setup</code> under the Control-Tree id
<code>equipment/controller/machine/m-codes</code>, grown while the runner snapshot reports a brand controller
parameter table. Both the declaration map and the trigger flag are stored on that one table, so this
leaf appears and disappears together with
<a class="xref" href="native-parameters.html">Parameters (Native)</a>, and the rows declared on it travel
with the project rather than with the runner file, which carries only the preset seed a fresh
project's table is cloned from.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p>Anatomy makes no claim that any id named here is stable across versions. The migration hop that
keeps an older <code>?tree=</code> value resolving is described in
<a class="xref" href="../../../platform/tree-ids-and-routes.html">Tree Ids and Routes</a>.</p>
</div>
<h2 id="the-one-object-behind-both-halves">The One Object Behind Both Halves</h2>
<p><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.ControllerParameterTableBase.html">ControllerParameterTableBase</a> implements
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IMCodeDeclarationConfig.html">IMCodeDeclarationConfig</a> and
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IToolChangeTriggerConfig.html">IToolChangeTriggerConfig</a> over its own storage, so the table every
brand carries supplies the whole leaf: the declaration map keyed on the code as parsed, and the
single trigger boolean. A third face, <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.ISpindleControlConfig.html">ISpindleControlConfig</a>, reads
the same map for spindle direction alone rather than keeping a second one, which is why one code is
never half-recognized by two separate dictionaries.</p>
<p>The tree gate and the panel's own second empty layer probe the same type. The branch builder grows
the node while the snapshot's <code>hasNativeTable</code> flag is set, and the read answers a presence flag
computed from the same resolved parameter table; every shipped brand preset carries one, so in
practice the leaf is unconditional and the <em>&quot;No controller parameter table on the active runner.&quot;</em>
line is reachable only on a runner assembled by hand or loaded from XML. Which brand satisfies which
gate is <a class="xref" href="../brand-matrix.html">Brand Matrix</a>.</p>
<p>Because the map is a member of the brand parameter table, and that table is the project's per-case
copy rather than the runner's, declarations survive installing another runner file of the same brand
— see <a class="xref" href="index.html">Machine and Controller Plane</a> for which half of a project each
value on this plane is written into.</p>
<h2 id="what-a-declaration-carries">What a Declaration Carries</h2>
<p>One row is one <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html">MCodeEffects</a>, and a real OEM code is frequently
composite, so the row records every effect the code performs rather than a single meaning.</p>
<table>
<thead>
<tr>
<th>Column</th>
<th>Effect</th>
<th>What the code expands to</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Tool change</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html#Hi_NcParsers_Dependencys_MCodeEffects_IsToolChange">IsToolChange</a></td>
<td><code>M06</code></td>
</tr>
<tr>
<td><strong>Spindle</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html#Hi_NcParsers_Dependencys_MCodeEffects_SpindleDirection">SpindleDirection</a></td>
<td><code>M03</code> for CW, <code>M04</code> for CCW, <code>M05</code> for STOP</td>
</tr>
<tr>
<td><strong>Coolant</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html#Hi_NcParsers_Dependencys_MCodeEffects_CoolantMode">CoolantMode</a></td>
<td><code>M07</code> for Mist, <code>M08</code> for Flood, <code>M09</code> for Off</td>
</tr>
<tr>
<td><strong>Not-simulated note</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html#Hi_NcParsers_Dependencys_MCodeEffects_UnmodeledNote">UnmodeledNote</a></td>
<td>nothing — it raises one informational diagnostic per occurrence</td>
</tr>
</tbody>
</table>
<p>The two pickers each open on a dash, which is the null option: a declaration that touches neither
the spindle nor the coolant carries neither. The note is free text and is itself an effect — a code
whose real behaviour is a chip conveyor or a door interlock is declared with the note alone, and
every occurrence then reports <code>DeclaredMCode--UnmodeledEffects</code> at message severity instead of the
unknown-code warning. A declaration with no effect and no note is the fourth legal state and means
<em>consume this code silently</em>, which the panel's hint says in as many words: <em>&quot;A declaration with
nothing set consumes its code silently.&quot;</em></p>
<p>That fourth state is what a freshly declared row is. <strong>Declare</strong> writes a row whose tool-change box
is clear, whose two pickers sit on the dash and whose note is empty, so the act of naming a code
already silences it; the fields are then filled in against a live row.</p>
<h2 id="how-a-declared-code-is-read">How a Declared Code Is Read</h2>
<p><a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.MCodeExpansionSyntax.html">MCodeExpansionSyntax</a> rewrites the declared flag into the canonical
ISO flags the ordinary consumers already understand, and it runs ahead of them:
<a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.SpindleSpeedSyntax.html">SpindleSpeedSyntax</a>,
<a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.CoolantSyntax.html">CoolantSyntax</a> and
<a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.ToolChangeSyntax.html">ToolChangeSyntax</a> each then see the flag they know. Expanding once,
early, is what lets a single composite code feed several consumers without any of them fighting over
which removes the original flag.</p>
<p>Three rules of the rewrite are visible in a program:</p>
<ul>
<li><strong>The expansion sits at the declared flag's own position</strong>, and a repeat of the same declared code
later in the block is dropped. Textual order therefore keeps deciding last-wins conflicts exactly
as it did before any declaration existed — a composite code followed by a raw <code>M05</code> still ends
with the spindle stopped.</li>
<li><strong>A canonical flag that also appears raw and undeclared in the same block is not emitted twice.</strong>
The raw occurrence keeps its position, so the expansion cannot reorder what the block already said.</li>
<li><strong>Undeclared codes are untouched.</strong> One that no other syntax consumes then reaches
<a class="xref" href="../../../../api/Hi.NcParsers.InspectionSyntaxs.UnconsumedCheckSyntax.html">UnconsumedCheckSyntax</a>, which reports it as
<code>Parsing--Unconsumed</code> — the warning this leaf exists to answer.</li>
</ul>
<h3 id="the-spindle-only-row-takes-a-different-path">The spindle-only row takes a different path</h3>
<p>A declaration whose sole content is a spindle direction is deliberately <strong>not</strong> expanded.
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.MCodeEffects.html#Hi_NcParsers_Dependencys_MCodeEffects_IsSpindleDirectionOnly">IsSpindleDirectionOnly</a> marks it, the expansion skips
it, and <a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.SpindleSpeedSyntax.html">SpindleSpeedSyntax</a> resolves it in place through
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.ISpindleControlConfig.html#Hi_NcParsers_Dependencys_ISpindleControlConfig_TryResolveDirection_">TryResolveDirection</a><small>(API)</small>.
What separates the two paths is mechanism, not reach. The resolver is consulted <strong>before</strong> the
built-in ISO mapping, so a spindle-only row overrides a canonical code where the code stands, with
no rewrite at all — declaring <code>M03</code> as CCW makes <code>M03</code> turn the spindle counter-clockwise. Add any
second effect to the same row and it leaves that path for the expansion, which arrives at the same
place by rewriting: the declared flag is replaced by the ISO flags its effects name, so declaring
<code>M08</code> as Mist makes the block emit <code>M07</code> instead. On either path a declaration over a canonical code wins against that
code's built-in meaning.</p>
<p>The split also reaches the project file. A spindle-only row serializes as the legacy
<code>&lt;SpindleMCode&gt;</code> element so an older reader still resolves it; every other row serializes as
<code>&lt;MCode&gt;</code> with one attribute per effect that is set. A row with nothing set writes an <code>&lt;MCode&gt;</code>
element carrying only its code, so the silent-consume state round-trips.</p>
<h3 id="what-the-writer-refuses">What the writer refuses</h3>
<p>The declare endpoint validates before it stores. An empty code is answered unsuccessfully; so is a
spindle direction that is not <code>CW</code> / <code>CCW</code> / <code>STOP</code> and a coolant mode that is not <code>Mist</code> / <code>Flood</code> /
<code>Off</code>, and those two answers quote the rejected value back alongside the set that was expected. A
typo therefore cannot degrade into a declaration that consumes a code silently. The panel's two
pickers cannot produce such a value; the guard is there for the other writers of the same table.</p>
<p>A coolant mode that names no known mode can still arrive from a project file, because the XML reader
keeps the attribute raw rather than normalizing it and write-then-read stays an identity. The
expansion is where that surfaces: it reports <code>DeclaredMCode--UnknownCoolantMode</code>, skips the coolant
half, and emits the rest of the declaration.</p>
<h2 id="the-tool-change-trigger-mode">The Tool-Change Trigger Mode</h2>
<p>The toggle above the table reads <em>&quot;T word performs the tool change itself (turret / lathe)&quot;</em> and
writes <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IToolChangeTriggerConfig.html#Hi_NcParsers_Dependencys_IToolChangeTriggerConfig_ToolWordTriggersChange">ToolWordTriggersChange</a>. It defaults
off, which is machining-centre behaviour: a <code>T</code> word only pre-selects, the magazine rotates without
moving a feed axis, and the trigger M-code performs the change.</p>
<p>Turned on, <a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.ToolChangeSyntax.html">ToolChangeSyntax</a> treats a block carrying a <code>T</code> word and
no tool-change flag as the change itself and records <code>T</code> as the triggering term. The test is per
block: a block carrying both a <code>T</code> word and a tool-change flag is unaffected — the flag wins and
<code>M06</code> is recorded — so no single block is counted twice. Where the two words sit in different blocks
— a <code>T</code> pre-select first, an <code>M06</code> later — the mode counts the <code>T</code> block as a change on its own, and
the <code>M06</code> block then records a second one, its tool number arriving modally. The toggle therefore
belongs on a machine whose <code>T</code> word really performs the change; on a machining centre it turns every
pre-select into a change of its own.</p>
<p><strong>On the Siemens machine-data table the flag is not a field of its own.</strong> That table binds the
property to its tool-change-mode row,
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensMachineDataTable.html#Hi_NcParsers_Dependencys_Siemens_SiemensMachineDataTable_MdToolChangeMode">MdToolChangeMode</a>: present, the row
decides — a stored zero means the <code>T</code> word changes the tool — and the toggle writes back into it as
0 or 1 rather than into the brand-neutral field; absent, the table behaves like every other brand.
The write is skipped when the effective value already matches, so copying a table never rewrites a
raw machine-data value of 2 down to 1. The same row is visible and editable by number on
<a class="xref" href="native-parameters.html">Parameters (Native)</a>, and the two forms are one storage.</p>
<h2 id="the-rows">The Rows</h2>
<p>The read returns the declarations sorted by code as <strong>text</strong>, case-insensitively, not by numeric
value. <code>M106</code> therefore sorts ahead of <code>M12</code>, and <code>M6</code> lands after <code>M331</code>.</p>
<p>Keys are matched case-insensitively too, so <code>m13</code> and <code>M13</code> are one declaration and cannot both
exist; re-declaring a code in a different spelling replaces its effects and leaves the spelling
already stored on display. The <strong>Code</strong> cell is plain bold text with no editor — a code is changed
by declaring the new one and deleting the old.</p>
<p>Only one brand's default parameter table pre-declares anything. The Siemens machine-data default
seeds six auxiliary codes — <code>M12</code>, <code>M13</code>, <code>M22</code>, <code>M23</code>, <code>M330</code> and <code>M331</code> — each carrying no effect
and the same note, <em>&ldquo;machine-specific auxiliary function (OEM/PLC); the exact behavior depends on
the machine&rdquo;</em>. Those recur often enough in real Siemens programs to be worth silencing with an
explanation rather than a warning, and a machine table that knows their actual effects overrides the
seeded note. On the other four brands the table opens empty.</p>
<h2 id="editing-adding-and-removing">Editing, Adding and Removing</h2>
<p>Every cell commits on its own, and the write is the whole declaration: the handler merges the edited
field into the row and sends all four values, so an edit rewrites the row from what the panel is
currently showing. The checkbox and the two pickers commit on the click or the pick; the note cell
commits through its field's native change event, which is this branch's third text-commit wiring and
is recorded as such in <a class="xref" href="../editing-contract.html">Editing Contract</a> — that page also
carries the optimistic-write, rollback and toast rules these cells share with the rest of the branch.</p>
<p>The footer holds a single field labelled <strong>M-code</strong>, hinted <code>M106</code>, and a <strong>Declare</strong> button. Enter
in that field submits, which no other add-row footer in the branch does. A blank code raises the
toast <em>&quot;M-code must not be empty.&quot;</em> locally and never reaches the server. A successful declare clears
the field and re-reads the whole table, so the new row appears in sort position rather than at the
end.</p>
<p>Removal is the trash button at the end of each row. It carries no confirmation dialog, and the row
leaves the list only after the server has answered — the delete is not optimistic. The removed code
returns to what it was before the declaration: <code>Parsing--Unconsumed</code> wherever a program uses it,
unless a shared or brand syntax already knew the code, in which case it goes back to that built-in
meaning.</p>
<h2 id="what-this-table-does-not-show">What This Table Does Not Show</h2>
<p>The stored map is not the whole of what a machine honours, and three families of M-code behaviour
live outside it.</p>
<p><strong>The canonical ISO codes.</strong> <code>M06</code>, <code>M03</code> / <code>M04</code> / <code>M05</code> and <code>M07</code> / <code>M08</code> / <code>M09</code> are consumed by
the shared syntaxes with no declaration at all; this table exists for the codes those consumers do
not already know. Declaring a canonical code is still legal and still honoured — a note-only
declaration on <code>M08</code>, for instance, consumes the raw <code>M08</code> for its own declaration while a composite
code's flood half continues to emit <code>M08</code>.</p>
<p><strong>A brand's own M-function dialect.</strong> The Heidenhain preset's
<a class="xref" href="../../../../api/Hi.NcParsers.LogicSyntaxs.Heidenhain.HeidenhainMFunctionSyntax.html">HeidenhainMFunctionSyntax</a> owns <code>M126</code> / <code>M127</code>
(shortest-path rotary traverse) and <code>M140</code> (tool-axis retract) as brand meanings, not as
declarations, so none of them is a row here. That preset's syntax list places the expansion <strong>ahead</strong>
of the brand syntax precisely so a machine that redefines one of those codes can say so: a
declaration for <code>M126</code> is expanded and consumed before the brand meaning is reached, and the
declaration wins.</p>
<p><strong>The Siemens tool-change M function.</strong> The Siemens machine-data table's
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensMachineDataTable.html#Hi_NcParsers_Dependencys_Siemens_SiemensMachineDataTable_MdToolChangeMCode">MdToolChangeMCode</a> row names the
M function that performs a tool change, and the table overlays a tool-change declaration for it onto
the view the parsers resolve — merged into a clone of any explicit declaration on the same code, so a
note or coolant half is kept, and never written into the stored map. <strong>The panel reads the stored
map, so that overlaid row is not on screen.</strong> A Siemens machine whose machine data names a
non-standard trigger honours it in every program while this table lists nothing for it; the value
lives on <a class="xref" href="native-parameters.html">Parameters (Native)</a> as the machine-data row, in
the raw form an operator reads off the real controller. The overlay's own rules matter when the two
views are compared: the raw number is zero-padded to the parsed flag form, so 6 becomes <code>M06</code> and
106 becomes <code>M106</code>; a value that is not a positive whole number overlays nothing; and a code already
declared as a tool change here is left exactly as stored.</p>
<p>The trigger toggle above the table does <strong>not</strong> share that blind spot. It is read through the
property the Siemens table overrides, so it shows the machine data's answer, while the rows beside it
show only what was declared. The asymmetry is the single most useful thing to know about this leaf:
the mode is the effective value, the table is the stored one.</p>
<p>One further consequence of the overlay is invisible in both views. Spindle-only resolution also runs
against the overlaid view, so a code that the machine data names as the tool-change trigger and that
is <em>also</em> declared here with a spindle direction alone stops being spindle-only: it leaves the
in-place resolver and is expanded instead, emitting both the tool change and the direction.</p>
<h2 id="layout">Layout</h2>
<ul>
<li><strong>General Setup</strong> Control Tree — the left dock of <code>/general-setup</code>
<ul>
<li><strong>Controller</strong> Node Row
<ul>
<li><strong>Machine / Controller</strong> Group Row
<ul>
<li><strong>M-Code Declarations</strong> Node Row — <code>equipment/controller/machine/m-codes</code></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Editor Row — <strong>M-Code Declarations</strong> Panel
<ul>
<li>No-Runner Line — <em>&quot;No NC runner — load a project first.&quot;</em>, the branch's shared empty state, shown
while the snapshot reports no runner</li>
<li>No-Table Line — <em>&quot;No controller parameter table on the active runner.&quot;</em>, shown when the read
itself reports no table</li>
<li><strong>T word performs the tool change itself (turret / lathe)</strong> Toggle</li>
<li>Hint Caption — <em>&quot;Declares machine-specific M-codes: a tool-change trigger other than <code>M6</code>,
composite OEM codes (e.g. <code>M13</code> = spindle CW + flood coolant), or known-but-unsimulated codes
(note only, one info message per occurrence). A declaration with nothing set consumes its code
silently. Undeclared codes keep the unconsumed warning.&quot;</em></li>
<li>Declaration Table — dense, flat and bordered, one row per declared code
<ul>
<li>Header Row — <strong>Code</strong>, <strong>Tool change</strong>, <strong>Spindle</strong>, <strong>Coolant</strong>, <strong>Not-simulated note</strong>, and
an unlabelled action column</li>
<li><strong>Code</strong> Cell — bold plain text, not editable</li>
<li><strong>Tool change</strong> CheckBox</li>
<li><strong>Spindle</strong> Select — a dash, <strong>CW (M03)</strong>, <strong>CCW (M04)</strong>, <strong>STOP (M05)</strong></li>
<li><strong>Coolant</strong> Select — a dash, <strong>Mist (M07)</strong>, <strong>Flood (M08)</strong>, <strong>Off (M09)</strong></li>
<li><strong>Not-simulated note</strong> Field — placeholder <em>e.g. chip conveyor forward</em></li>
<li>Delete Button — a trash icon, no confirmation</li>
</ul>
</li>
<li>Add Row Footer
<ul>
<li><strong>M-code</strong> Field — placeholder <code>M106</code>; Enter submits</li>
<li><strong>Declare</strong> Button</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The panel mounts against one node and takes nothing from it: unlike the per-axis leaves it serves a
single tree id, so it reads no role off the node's path.</p>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../../../index.html">HiNC App Anatomy</a> for git repository links.</p>
<h3 id="web-application">Web Application</h3>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/SoftNcMCodesPanel.vue</code> — this panel: the two empty layers,
the trigger toggle, the two option lists with their dash entry, the whole-declaration write behind
every cell, the change-event note cell, the Enter-submitting add footer and the
confirmation-free delete.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue</code> — the shared no-runner line the panel
opens with.</li>
<li><code>wwwroot-src/src/components/controlTree/softNcItemTypes.ts</code> — the node id, its label and label key,
the snapshot flag it is grown behind, and the item type that binds it to the panel.</li>
<li><code>wwwroot-src/src/api/softNcRunner.ts</code> — the declaration row and snapshot shapes, the reader that
coerces an empty string to a null field, the whole-declaration writer, the delete, and the trigger
setter.</li>
<li><code>wwwroot-src/src/composables/useSoftNcRunner.ts</code> — the shared runner snapshot the first empty layer
reads.</li>
<li><code>wwwroot-src/src/i18n/en/softNc.ts</code> — the node label, the toggle label, the hint, the column
headers, the two option label sets, the note placeholder, the empty-code toast and the two empty
strings quoted above.</li>
<li><code>Mech/SoftNcRunnerController.cs</code> — the REST surface: the read with its presence flag and its
case-insensitive text ordering, the declare endpoint's direction and coolant validation, the
delete, the trigger write, and the shared helper that answers a missing dependency with an
unsuccessful body rather than an error status.</li>
</ul>
<h3 id="hiapi-engine">HiAPI Engine</h3>
<ul>
<li><code>HiMech/NcParsers/Dependencys/IMCodeDeclarationConfig.cs</code> — the declaration contract: the map, the
lookup that returns false for an undeclared code, and the declare and remove mutators whose stored
effects are copied rather than aliased.</li>
<li><code>HiMech/NcParsers/Dependencys/MCodeEffects.cs</code> — the four effects, the empty and spindle-only
predicates that partition the two consumption paths, and the coolant-mode normalizer.</li>
<li><code>HiMech/NcParsers/Dependencys/IToolChangeTriggerConfig.cs</code> — the trigger contract and the
magazine-versus-turret distinction it encodes.</li>
<li><code>HiMech/NcParsers/Dependencys/ISpindleControlConfig.cs</code> — the narrower spindle face over the same
storage, and the resolver the spindle-only rows take.</li>
<li><code>HiMech/NcParsers/Dependencys/ControllerParameterTableBase.cs</code> — the storage every brand inherits:
the case-insensitive map, the overridable effective view, the virtual trigger property, and the
XML round trip that writes a spindle-only row as the legacy element.</li>
<li><code>HiMech/NcParsers/Dependencys/Siemens/SiemensMachineDataTable.cs</code> — the two machine-data rows that
change this leaf's meaning: the tool-change mode bound to the trigger property, the tool-change
M function overlaid onto the effective view with its zero-padding rule, and the six auxiliary
codes the default table pre-declares.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/MCodeExpansionSyntax.cs</code> — the rewrite: in-place expansion, the
duplicate and raw-twin guards, the spindle-only skip, and the two diagnostics a declaration can
raise.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/ToolChangeSyntax.cs</code> — the consumer of the expanded tool change and
of the trigger mode, and the term it records for each.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/SpindleSpeedSyntax.cs</code> — the consumer that tries the machine map
before the ISO defaults, which is what lets a spindle-only row remap a canonical code.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/CoolantSyntax.cs</code> — the consumer of the three expanded coolant
flags.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/Heidenhain/HeidenhainMFunctionSyntax.cs</code> — the brand meanings a
declaration can pre-empt on that preset.</li>
<li><code>HiMech/NcParsers/InspectionSyntaxs/UnconsumedCheckSyntax.cs</code> — the warning an undeclared code
keeps, and the one a declaration removes.</li>
<li><code>HiMech/NcParsers/Syntaxs/FanucSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/SiemensSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/SyntecSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/MazakSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/HeidenhainSyntaxUtil.cs</code> — where the expansion sits in each brand's
syntax list, and why the Heidenhain list anchors it earlier than the rest.</li>
<li><code>HiMech/NcParsers/Keywords/Generic/IsoKeywords.cs</code> — the canonical flag spellings the expansion
emits, <code>M06</code> among them.</li>
<li><code>HiMech/NcParsers/Keywords/ICoolantDef.cs</code> — the three coolant constants the picker's values map
to.</li>
<li><code>HiGeom/Numerical/SpindleDirection.cs</code> — the direction enum behind the spindle column.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="index.html">Machine and Controller Plane</a> — the plane this leaf sits on, and which half of a project the
declaration map is written into</li>
<li><a class="xref" href="../brand-matrix.html">Brand Matrix</a> — the flag that grows this node, and why it is never false on
a shipped brand preset</li>
<li><a class="xref" href="../editing-contract.html">Editing Contract</a> — the fetch, commit, rollback and toast rules this panel
shares with the branch, and the two places it is recorded as departing from them</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>