Namespace Hi.NcParsers.LogicSyntaxs.Heidenhain
Classes
- HeidenhainCannedCycleSyntax
Bridges the klartext machining-cycle vocabulary onto the shared ISO canned-cycle machinery. Owns the self-carrying MachiningCycleDef store (single-step lookback + rewrite on every block — the P1 datum-shift pattern) and the call-once vs modal split:
- Definition (
Parsing.MachiningCyclefrom HeidenhainMachiningCycleSyntax): mapped to ISO slots at definition time — 200 → G81/G82/G83 (peck when Q202 < |Q201|), 232 → G81 (start point Q225/Q226/Q227, end Q386, feed Q207), 251/252/253 → G81/G83 (surface Q203, clearance Q200, depth Q201, plunge feed Q206, step-down Q202). A definition never executes by itself. Unsupported numbers (19, …) are recognized-but-not-simulated: consumed whole withHeidenhainCycl--Unsupported, stored unarmable so a later call warns instead of moving. Required parameters that are missing or non-literal make the store unarmable withHeidenhainCycl--ParamsNotLiteral. - Call-once (
CYCL CALL [POS]record from HeidenhainCyclCallSyntax, or anM99flag on a positioning block — the TNC block-wise call, unrelated to the Fanuc return M99): writes the mapped cycle as a directParsing.G8xsub-section on this block, which CannedCycleResolveSyntax resolves and the shared cycle syntaxes expand into a CompoundMotion. POS coordinates override the stored X/Y; the POS Z is a pre-position, recorded but never fed into the hole-bottom slot. The ISO modal-lookback branch is deliberately bypassed: it has no positioning gate, so an armed CannedCycle would re-execute on flag-only blocks — wrong for klartext. - Modal (
M89): sets Modal; each subsequent block carrying root axis words (and noCArcstatement) fires the same direct-section path with the block's X/Y consumed into the cycle.M99fires once and clears the modality; a newCYCL DEFreplaces the store. - Seal: on every non-firing block whose previous block
carries an active CannedCycle term, a
G80flag is injected (the P0 G00/G01 injection pattern) so CannedCycleResolveSyntax writes the cancel sentinel — the one-shot execution never leaks into ISO modal repetition.
Known divergences (recorded, corpus-benign): the cycle's mapped feed enters the modal Feedrate section during expansion (ISO semantics; the Siemens MCALL precedent accepts the same leak); the final retract plane is the ISO G98 initial level, not Q204's second set-up clearance (Q204 is recorded in the definition store only).
Must run after the tilt/RTCP family and immediately before CannedCycleResolveSyntax.- Definition (
- HeidenhainCircleCenterSyntax
Heidenhain-specific: turns the
Parsing.CCrecord into the modalHeidenhainCircleCenter { X, Y, Z? }section (absolute program coordinates). Self-carrying every block (PlaneSelect pattern — detected ?? previous), so the arc syntax's single-step read always works without ModalCarry involvement; a CC with partial axes merges the missing components from the previous center. Must run before HeidenhainCircularMotionSyntax.
- HeidenhainCircularMotionSyntax
Heidenhain circular motion — the Klartext half of the brand's two arc syntaxes. The shared CircularMotionSyntax (with IsIjkAbsolute set) runs right after it for the DIN/ISO dialect: the two gates are per-block exclusive (a klartext arc has
CArcand no I/J/K/R; an ISO arc the reverse) and both honor the single Group 01 MotionEvent slot. Gated by theParsing.Cstatement marker (klartext arcs carry no G02/G03 and no modal arc continuation): the endpoint comes from the block's resolvedProgramXyz, the center from the modal HeidenhainCircleCenterSyntax section (implicit center = current position when no CC was ever given), and the direction fromDR-(CW → G02) /DR+(CCW → G03). A closed arc on the active plane is a full circle. A missing DR warns (Arc-DR–Missing) and degrades to the modal linear move to the endpoint (chord).
- HeidenhainCoordinateOffsetSyntax
Heidenhain-specific: resolves coordinate offset from CYCL DEF 247 (Datum Preset) and CYCL DEF 7 (Datum Shift).
CYCL DEF 247 Q339=N: selects datum preset table entry N — written to the shared CoordinateOffset section (kept alive modally by IsoCoordinateOffsetSyntax via HeidenhainDatumTable synthetic-id resolution).
CYCL DEF 7 (
For DIN/ISO compatibility (G54–G59), use IsoCoordinateOffsetSyntax in addition to this syntax in the Heidenhain syntax list. Uses replace-by-source so both syntaxes coexist without double-composing.#Ntable row or direct X/Y/Z) is additive on top of the active preset (TNC semantics; HardNc oracle composes-preset + shift): it is written to its ownDatumShiftsection with a separateProgramToMcTransformentry (DatumShiftTransformSource) so preset and shift compose in the transform chain instead of replacing each other. The shift is carried modally by this syntax itself: on blocks without a CYCL DEF, a numbered row re-resolves from the table and a direct shift carries its values forward. Cancelling is a zero shift (CYCL DEF 7.1 X+0 Y+0 Z+0).
- HeidenhainCyclePrePositionSyntax
Lifts the expanded cycle's initial plane to the recorded TNC pre-position Z. A
CYCL CALL POS … Z±n(and an M99/M89 positioning block's own Z word) positions the spindle BEFORE the cycle runs; the shared ISO expansion instead anchors its initial plane — the first rapid and the G98 final retract — on the PREVIOUS block's Z. Left unlifted, a call that climbs to a safe Z before drilling would be simulated traversing at the stale old Z (phantom collisions through fixtures) and G98 would plunge the tool back to that stale Z after the hole.Mechanics: when the HeidenhainCyclCall record carries a numeric
Zand a CompoundMotion was expanded, the first item (the initial-plane rapid — both shared cycle syntaxes emit it first) and, under G98, the final item and the block's finalProgramXyzare re-anchored to the pre-position Z. G99 finals (R-plane) are untouched. Runs after the shared cycle syntaxes and before HeidenhainCycleRetractSyntax (whose appended M140 retract builds on the lifted final point).
- HeidenhainCycleRetractSyntax
Consumes the
Parsing.M140record that HeidenhainMFunctionSyntax deferred on a may-fire-cycle block — aCYCL CALL [POS]host (… M140 MB+nis a real house.H shape), anM99/M89flag block, or any block under armed M89 modality. WriteCompoundMotion(JsonObject, string, JsonArray, Vec3d) destroys any pre-written MotionEvent, so the retract is appended after the cycle expansion instead:- Cycle expanded — a rapid item to (final X, final Y, retract Z)
is appended to the CompoundMotion items and the block's
final
ProgramXyzis lifted to the retract plane. The MB math is ResolveRetractTargetZ(JsonObject, Vec3d, List<INcDependency>, ISentenceCarrier, NcDiagnosticProgress) verbatim. The real TNC runs M140 at block start (retract, then position + cycle); appending it is a transient-only divergence — the endpoint chain re-anchors on the next command point (the P3 PLANE MOVE precedent) and the appended order is the safer trajectory. AnFon the M140 is recorded on the item but the appended retract stays rapid (corpus M140-on-call blocks are all F-less). - Cycle did not expand (call consumed without motion) — the plain HeidenhainMFunctionSyntax retract behavior runs here unchanged, so a fail-soft call never silently drops the retract.
- Cycle expanded — a rapid item to (final X, final Y, retract Z)
is appended to the CompoundMotion items and the block's
final
- HeidenhainMFunctionSyntax
Heidenhain-specific M-function semantics for the near-universal corpus family:
M126/M127— shortest-path rotary traverse on/off. Writes the modalRotaryWrap { Shortest }section consumed by McAbcCyclicPathSyntax (absent = shortest, the shared default); the Heidenhain preset's Logic ModalCarry tracks the section.M128/M129— owned by HeidenhainRtcpSyntax since P3 (full RTCP on theToolHeightCompensationsection); this syntax no longer touches them.M140 MB— tool-axis retract. Executes a machine-coordinate move along +Z (the corpus machines are table-tilting, so the tool axis stays machine +Z; a head-machine generalization is a recorded P6 backlog item):MB+nretracts by n mm,MB MAXretracts to the positive Z stroke limit (IStrokeLimitConfig; unresolvable limit warnsM140--NoStrokeLimitand skips). The retract runs at the modal feed (the statement's F is recorded on the MotionEvent asRetractFeedrate, not folded into the modal feedrate).
- HeidenhainMirrorTransformSyntax
Simulates the Heidenhain DIN/ISO
G28MIRROR IMAGE function (the CYCL DEF 8 twin): consumes the statement list HeidenhainMirrorImageSyntax recorded underParsing.MirrorImage, keeps the modal mirror set in the root SectionKey section (each statement REPLACES the set — course 62192's four-quadrant idiom relies onG28 YafterG28 X Yleaving only Y mirrored; bareG28resets), and writes the sign-flip matrix into ProgramToMcTransform as the TransformSource entry.Must run before every other transform writer (HeidenhainPlaneTiltSyntax downward) so the mirror entry is the chain's first — the mirror flips program coordinates about the current datum inside the active working plane, i.e. innermost: tilt, tool-height and coordinate-offset entries compose after it and are never themselves mirrored. Because every motion semantic resolves contours in program coordinates and maps each interpolated point through the composed chain (CreateProgramPosToMcFunc(LazyLinkedListNode<SyntaxPiece>, IMachineAxisConfig)), the arc-handedness flip (G02↔G03) and the radius-compensation side flip (G41↔G42) a real control performs under a single-axis mirror emerge from the pointwise mapping — no re-tagging of IsCcw or the compensation side happens, and none is needed.
Two statement shapes stay recognized-but-not-simulated: a rotary axis letter (RotaryUnsupportedId — a rotary mirror is not representable in the XYZ transform chain; the letter is dropped from the set, the statement still replaces) and the Fanuc-shaped valued form (ValuedUnsupportedId — the manual's mirror idiom is bare letters, so
G91 G28 X0 Y0 Z0in a mislabeled.Ifile must not arm a full-XYZ mirror; the statement is consumed with zero effect).
- HeidenhainMotionModeSyntax
Heidenhain-specific: maps the klartext
Lstatement marker (written by HeidenhainLSyntax) onto the shared ISO motion-mode vocabulary. AnLblock carrying the one-shotFMAXflag becomes a rapid (G00) block; every otherLblock is a feed move (G01) driven by the modal feedrate. The injected G00/G01 flag is consumed downstream exactly like a DIN/ISO block — by LinearMotionSyntax on ordinary moves and by MachineCoordSelectSyntax on machine-coordinate (M91) moves — so no shared syntax needs Heidenhain-specific behavior.FMAX is one-shot on the real TNC: because every klartext motion is an
Lstatement and this syntax stamps a mode per statement, the rapid mode never leaks into the next block — the followingLwithout FMAX is stamped G01 again.FAUTO(feed from cycle) is consumed as a feed move. Must be placed at the top of the Logic bundle, before MachineCoordSelectSyntax and LinearMotionSyntax.
- HeidenhainPathSmoothingSyntax
Heidenhain-specific: consumes the structured CYCL DEF 32 TOLERANCE record (HeidenhainToleranceCyclSyntax) into the shared modal
PathSmoothingsection (tracked by the Logic ModalCarry): a positive tolerance arms smoothing ({IsEnabled:true, Term:“CYCL DEF 32”, Tolerance, HscMode?, Ta?}); a bare or zero-tolerance cycle cancels it. Untouched blocks are left to ModalCarry; the stream's first block seeds a conservative{IsEnabled:false}(Siemens sibling shape). Replaces the deadFanucPathSmoothingSyntaxin the Heidenhain list (it readParsing[“G05.1”], which no Heidenhain capture produces).
- HeidenhainPivotTransformationSyntax
Heidenhain pivot gate over the shared engine (PivotTransformUtil): writes the PivotTransformSource entry on blocks where commanded XYZ needs the Pn→MC kinematic rigid transform — an active tilted plane (HeidenhainPlaneTiltSyntax's
PLANE SPATIALterm, or a mixed-dialect G68/G68.2 term), an active RTCP modal (RtcpTerms on the ToolHeightCompensation section — the term check covers RTCP blocks whose rotary state is stable, which the Dynamic-entry branch alone would miss), or a Dynamic chain entry.The third sibling gate after PivotTransformationSyntax (ISO/Fanuc) and SiemensPivotTransformationSyntax; all write the identical JSON vocabulary through the shared engine and only one gate is registered per brand pipeline. Heidenhain has no plain-geometry-frame exclusion (klartext datum shifts use their own chain sources, never TiltTransform). Same chain-position contract: after all Pn-frame writers, so the
PivotTransformentry lands last.
- HeidenhainPlaneTiltSyntax
Heidenhain PLANE consumer — the Heidenhain sibling of IsoG68p2TiltSyntax (Fanuc G68.2) and SiemensCycle800TiltSyntax both XmlDocs promise.
- PLANE SPATIAL — composes the tilted work plane
Rx(SPA)·Ry(SPB)·Rz(SPC)(row-vector, degrees; the HardNc oracle'sHeidenhainPlaneSpatialArgmatrix verbatim) into ProgramToMcTransform as the shared TransformSource entry withTerm = "PLANE SPATIAL". - MOVE / TURN — the implicit rotary positioning (the
CYCLE800 "G53.1 half"): with IMachineKinematics wired
the plane orientation is solved to machine ABC (full-orientation IK
first so a pure in-plane
SPCunder TABLE ROT still turns the table; tool-axis-normal fallback for machines with fewer rotary DOF; no identity short-circuit — the explicit zero-anglePLANE SPATIAL SPA+0 SPB+0 SPC+0 TURNis the klartext idiom for returning the rotaries to 0, oracle parity) and written into MachineCoordinateState plus a non-modal MotionEvent withTerm = "PLANE SPATIAL". MOVE'sDIST(tool retract radius during the swivel) and the TCP-preserving XYZ compensation are recorded but not simulated — the machine XYZ stays at the previous position like TURN, a transient-only divergence from the HardNc oracle (endpoints re-anchor at the next commanded point); MOVE'sFis recorded on the event asMoveFeedrate. - COORD ROT is honored only when the plane rotates purely about the tool axis (ToolAxisDirection, TNC manual rule; HardNc parity): the coordinate system rotates and the rotaries stay. Any other rotation — or TABLE ROT, or neither word — positions the rotary axes on MOVE/TURN.
- SEQ± is recorded in the section; when the IK solution's
master rotary (first declared rotary axis) violates an explicit SEQ
preference the preference is not applied and
Coord-Tilt--007warns (solution-family selection is not modeled; the HardNc ±2π window wrap would be undone by McAbcCyclicPathSyntax's shortest-cyclic tail pass, and the corpus never exercises SEQ with MOVE/TURN). - PLANE RESET — the shared inactive sentinel
(
Term = "G69"+ identity entry). The rotary axes are not re-positioned on reset (CYCLE800 cancel precedent; corpus programs follow with explicit rotary moves). - PLANE VECTOR / PROJECTED / EULER / POINTS / RELATIV /
AXIAL — recognized-but-not-simulated: consumed,
HeidenhainPlane--Unsupportedwarns, and the previous tilt state carries unchanged (the HardNc oracle instead reuses a stale spatial arg here — SoftNc deliberately exceeds it).
Owns the once-per-block TiltTransform modal carry for the Heidenhain list (CarryForwardFromPrevious(LazyLinkedListNode<SyntaxPiece>, JsonObject)). Must run before ToolHeightOffsetSyntax / HeidenhainToolOffsetSyntax (their translation follows the tilt entry's normal — the oracle's tool-normal-tiltable rule) and before McAbcSyntax / the coordinate-offset syntaxes (chain order: tilt entry ahead of
CoordinateOffset, mirroring the Siemens frame slot; implicit MC rotary values must land before McAbc's per-axis lookback).- PLANE SPATIAL — composes the tilted work plane
- HeidenhainProgramHeaderSyntax
Heidenhain-specific: consumes the
Parsing.PGMrecord (BEGIN|END PGM name MM|INCH) — the unit word is pushed intoParsing.Flagsfor the UnitModeSyntax instance configured withInchCodes=[“INCH”], MetricCodes=[“MM”](which must run after this syntax), andEND PGMwrites the shared one-shotProgramEndsection (existence-checked by its consumers exactly like M30). Consuming PGM also removes the program-header unconsumed noise every klartext file used to emit.
- HeidenhainRadiusCompSyntax
Heidenhain-specific: maps the klartext radius-compensation words captured by HeidenhainLSyntax (
RL/RR/R0boolean Parsing-root records) onto the shared vocabulary consumed by the radius-compensation pass:RL → Parsing.G41 {D: toolId},RR → G42,R0 → G40flag. The offset id is the current tool number (klartext has no D word;IToolOffsetConfigdocuments the offset id as the Heidenhain tool number), resolved by walking back to the most recentToolChangesection. A missing or non-numeric tool id degrades to mode-only injection (radius 0 — the compensation pass records the state but applies no geometric offset) with anRadiusComp–ToolUnresolvedwarning.Must run before the PostLogic radius-compensation pass (any Logic position works — PostLogic sees completed Logic output) and after HeidenhainToolChangeSyntax so a same-block TOOL CALL is visible.
- HeidenhainRtcpSyntax
Heidenhain RTCP (M128/M129, FUNCTION TCPM/FUNCTION RESET TCPM): the Heidenhain sibling of G43p4RtcpSyntax and SiemensTraoriSyntax. While RTCP is active the IToolHeightCompensationDef section carries the activating term (M128Term or TcpmTerm) and the
ToolHeightCompensationchain entry becomes a tool-normal · offset translation at the block endpoint ABC (MakeToolHeightMat(IMachineKinematics, Vec3d, double)), tagged KindDynamic when the rotary state changes across the block — the signal that routes the block to ClLinear per-step IK.Tool length ownership stays with the TOOL CALL machinery (HeidenhainToolOffsetSyntax — table height + DL, which runs earlier in the bundle): activation adopts the compensation already resolved on this or the previous block and records the adopted owner in PriorTermKey; a TOOL CALL during the modal re-takes the section with the fresh offset; M129 / FUNCTION RESET TCPM hands the section back to the recorded owner (default Term — klartext tool-length compensation survives RTCP deactivation). The TOOL CALL
Delta_mm(DL) rides along so the hand-back restores it. A deactivation with no active RTCP (the corpus' ubiquitous program-headM129) is consumed silently. Same-block contradiction (M128 with M129): the off state wins conservatively (the P1 rule, kept for continuity).The M128 feed limit (
M128 F6000., or an FQn token the evaluator could not resolve) is recorded on the section as FeedLimitKey — recorded, not simulated. FUNCTION TCPM behavior arguments are recorded by the parsing syntax and warnTcpm--ArgsNotSimulatedon activation.Must run after ToolHeightOffsetSyntax / HeidenhainToolOffsetSyntax and the coordinate-offset syntaxes (mirroring the Fanuc G43.4 / Siemens TRAORI slot) and before HeidenhainPivotTransformationSyntax, whose gate recognizes the RtcpTerms and folds the kinematic pivot. Silently degrades to a plain
UnitZ · offsettranslation when IMachineKinematics is absent.
- HeidenhainStockDeclarationSyntax
Heidenhain-specific: consumes the
Parsing[“BLK FORM”]record (workpiece blank declaration, present in virtually every klartext file) into the brand-neutralStockDeclarationsection — recognized and recorded, not simulated. The simulation stock always comes from the project's own workpiece setup, mirroring the HardNc oracle which recognizes-and-skips the same lines; the structured record keeps the declared blank readable for a future stock consumer without feeding geometry today.
- HeidenhainToolChangeSyntax
Heidenhain-specific: consumes the
Parsing[“TOOL CALL”]record (written by HeidenhainToolCallSyntax) into the shared SectionName section so ToolChangeSemantic fires the tooling act. A klartextTOOL CALLalways performs the change — no separate M06 trigger exists — so IsChangeKey is alwaystruewithTerm = “TOOL CALL”.The spindle-speed word (
S) is relocated to the root of Parsing so the shared SpindleSpeedSyntax — which must run after this syntax in the Logic bundle — records it modally. Numeric tool ids are written as ints (the act chain is int-keyed); non-numeric ids stay strings and resolve (or warn) at the semantic layer.P0 limits recorded as diagnostics: non-Z tool axis (
ToolChange--AxisUnsupported), non-zero DL/DR deltas (ToolChange--DeltaUnsupported; zero deltas are consumed silently), and a TOOL CALL without a tool id (ToolChange--MissingToolId, e.g. a variable tool number the parser could not capture).Known P2 limitation: a quoted tool NAME that happens to spell a Q token (
TOOL CALL "Q1" Z) loses its quotes at capture, so the evaluator substitutes the Q parameter's value and the numeric branch below treats it as a tool number. Corpus-zero (real names are"B40R"-style); fixing it needs the capture to preserve the quoted-ness, which would change the P0-pinned record shape.
- HeidenhainToolOffsetSyntax
Heidenhain-specific: klartext TOOL CALL always applies tool-length compensation (there is no cancel word — HardNc compensates unconditionally). On TOOL CALL blocks the effective height = GetToolHeightOffset_mm(int)(tool id) + the TOOL CALL's DL delta; the shared
ToolHeightCompensationsection is written (Term =“TOOL CALL”, OffsetId = tool id — the offset id is documented as the Heidenhain tool number) and the translation composes into the transform chain via the sharedToolHeightCompensationsource (mutual exclusion with the ISO G43 sibling by same-source replace).Modal: on following blocks the section is re-resolved per block from the table (mirroring the Siemens D sibling — give-way when a same block ISO term took ownership; carry Term/OffsetId/Delta_mm otherwise). Must sit after ToolHeightOffsetSyntax (the ISO anchor — last writer wins on mixed-dialect blocks) and after HeidenhainToolChangeSyntax (reads its ToolChange section), before the pivot/tilt syntaxes.