Table of Contents

Namespace Hi.NcParsers.LogicSyntaxs.Siemens

Classes

SiemensCircularMotionSyntax

Siemens variant of CircularMotionSyntax (replaces it in the Siemens preset — do not run both): writes McArc motion for G02/G03 blocks from I/J/K center offsets or the Siemens signed radius CR= (captured as Parsing.CR by an equals-form FloatTagValueSyntax), with the helix turn count from TURN= (Parsing.TURN).

Differences from the Fanuc/ISO parent, per the corpus-driven plan:

  • CR replaces R — same math (ResolveCenterFromSignedRadius(Vec3d, Vec3d, int, bool, double); negative CR selects the >180° arc), but a CR full circle (start ≈ end on the plane) is invalid on Sinumerik and the chord collapse would produce a NaN center — rejected with Arc-CR--ClosedChord, params left visible.
  • TURN=N means N additional full circles: AdditionalCircleNum = TURN + (closed ? 1 : 0)no −1 (the legacy HardNc path treated TURN like Fanuc L and silently undercounted Siemens helices by one turn; deliberately not ported). The closed-loop +1 stacks on the same closure heuristic used when TURN is absent, because the downstream angle wrap yields 0 rad for closed arcs and the whole loop count must come from AdditionalCircleNum.
  • No L and no K-as-pitch reading — Siemens L{n} is a subprogram call and helix travel is endpoint + TURN driven.
  • Per-word absolute center: an I=AC(...) / J=AC(...) / K=AC(...) wrapper (unwrapped by SiemensAcIcSyntax into a numeric Parsing value plus a PositioningOverride entry) switches that one component from the default incremental offset-from-start to an absolute center coordinate (ResolveCenterFromMixedIjk(Vec3d, int, double, double, double, bool, bool, bool)); components without an entry — and IC()-wrapped ones — keep the incremental reading. Blocks without the section take the legacy ResolveCenterFromIjk(Vec3d, int, double, double, double) path byte-for-byte.

Must be placed before LinearMotionSyntax (shared Group 01 motion slot).

SiemensCoordinateOffsetSyntax

Siemens Sinumerik: resolves work coordinate offset from G54–G57 (ISO-compatible), G505–G599 (extended Siemens), and G500 (cancel — machine coordinate mode). Reads from Flags, looks up IsoCoordinateTable dependency, composes into ProgramToMcTransform.

SiemensCutCompModeSyntax

Consumes the Siemens CUT3DC flag (3D circumferential cutter compensation mode, used with TRAORI) from Flags and records a non-modal block-root CutCompMode section. The offline RadiusCompensationSyntax only models the 2D plane modes, so a SiemensCutComp–Unsupported warning is emitted: a later G41/G42 in this program simulates as plane compensation, not as the control's 3D surface-normal offset — recognized, visibly not simulated, never a half-guess.

Capture side: CUT3DC is a bare word collected by the Siemens preset's FlagSyntax word list.

SiemensCycle800TiltSyntax

Siemens CYCLE800 (swivel cycle): resolves the tilted work plane from the positional arguments captured by SiemensCycleCallSyntax and composes it into ProgramToMcTransform as the shared TransformSource entry — the Siemens sibling of IsoG68p2TiltSyntax its XmlDoc promises. Unlike Fanuc G68.2 (plane only), CYCLE800 also positions the rotary axes implicitly (the G53.1 half): with IMachineKinematics wired, the tilt normal is solved to machine ABC and written into MachineCoordinateState, and the block gets a non-modal rapid MotionEvent with Term = “CYCLE800” (mirroring G53p1RotaryPositionSyntax).

Argument layout (HardNc reference NcArgCycle800): CYCLE800(FR, TC, ST, MODE, X0, Y0, Z0, A, B, C, X1, Y1, Z1, DIR [, FR_I, DMODE]) — 15- and 16-arg post variants both occur in the corpus. MODE is bit-coded: bits 7-6 select the swivel mode (00 axis-by-axis, 01 solid angle, 10 projection angle, 11 direct rotary), bit pairs 1-0/3-2/5-4 select each angle's axis (01=X, 10=Y, 11=Z). The motion-convention matrix is T(X1,Y1,Z1) · R · T(X0,Y0,Z0) (row-vector; the post-rotation zero offset applies innermost). ST units digit 1 composes additively onto the current programmable frame; FR/FR_I retraction and DIR solution preference are recorded in the section but not simulated (DIR = 0 suppresses the rotary positioning, per the control's frame-only variant).

Cancel forms — bare CYCLE800, empty parentheses, the single-argument CYCLE800(0), or swivel-data-record name TC = "0" — reset the tilt to the shared inactive sentinel (Term = "G69" + identity entry, HardNc's convention). An in-between argument count (1–9 with a live TC) is treated as a truncated/unmodeled capture, not a cancel — warning + visible residue, so a mis-parsed call can never silently drop an active swivel. The rotary axes are not re-positioned on cancel: the retract/re-orient behavior depends on the machine's swivel data record, which does not exist offline; corpus programs follow the cancel with explicit G0 A.. C.. moves anyway.

Fail-soft: a non-numeric argument (machine-runtime variable) leaves the Parsing.CYCLE800 residue visible and applies no transform (Coord-Tilt--003); an IK failure keeps the euler tilt and skips positioning (Coord-Tilt--004); a rotating CYCLE800 on a machine without kinematics/rotary axes keeps the tilt and warns (Coord-Tilt--005).

Must run before SiemensProgrammableFrameSyntax (which owns the once-per-block TiltTransform modal carry and composes additive AROT/ATRANS onto this cycle's fresh matrix) and before the coordinate-offset syntaxes (chain order: frame entry ahead of CoordinateOffset).

SiemensFixedPointReturnSyntax

Consumes the Siemens G74 (reference-point approach) / G75 (fixed-point approach) statement captured into Parsing.G74 / Parsing.G75 by the Siemens preset's dedicated ParameterizedFlagSyntax instance, and emits a one-shot machine-coordinate move for the participating axes.

Siemens semantics honored here: non-modal; only the axes written in the block participate; the numeric axis value is a dummy (conventionally 0) and is discarded; the motion happens in MACHINE coordinates ignoring every active frame; the F word in the block does not change the modal feed (the machine travels at its own rapid). The frame bypass reuses the MachineCoordSelectSyntax mechanism — write MachineCoordinateState directly and back-derive ProgramXyz through the inverse of the composed ProgramToMcTransform — so a G54/G505 offset or programmable frame shifts the recovered program coordinate, never the machine target.

Target position: G74 (reference-point approach) reads the per-axis machine reference from GetHomePosition(string) (MD34010 on a Siemens table; 0 when the axis has no configured home). G75 (fixed-point approach) reads the fixed-point table MD30600 $MA_FIX_POINT_POS via GetFixPointPosition(string), falling back per axis to the same reference position when no fixed point is configured — so machines whose fixed point differs from the reference retract to the right place. Only fixed point 1 is modeled; a FP= word in the block emits Coord-FixPoint--003 and uses fixed point 1. Non-participating linear axes keep the previous machine position; rotary axes participate only when written and configured rotary (their target lands in the shared MC section, wrapped shortest-path later by McAbcCyclicPathSyntax).

Placement: after ReferenceReturnSyntax (the G28 slot) — behind every coordinate-offset / frame syntax so the composed transform is complete for the ProgramXyz back-derivation, and before McXyzSyntax / LinearMotionSyntax (the stamped MotionEvent makes the motion syntaxes skip the block; a G0/G1 word on the block is claimed into the modal MotionState exactly like MachineCoordSelectSyntax does). Without an IHomeMcConfig dependency the statement stays in Parsing and surfaces as unconsumed residue.

SiemensModalCycleSyntax

Maps Siemens MCALL CYCLE8x(…) modal drilling calls onto the shared canned-cycle machinery — the “setup half” of the Fanuc G66-style modal pattern; the “expansion half” needs no new code because CannedCycleResolveSyntax's previous-block modal lookback already re-triggers the armed cycle at every subsequent block carrying X/Y words, exactly Sinumerik's MCALL semantic.

  • MCALL CYCLE81/82(RTP,RFP,SDIS,DP,DPR[,DTB]) → an armed CannedCycle section (Term G81/G82) with Params.R = RFP + |SDIS|, Params.Z = DP (or RFP − DPR), dwell P = DTB for G82.
  • MCALL CYCLE83(…,FDEP,FDPR,DAM,DTB,DTS,FRF,VARI,…) → G83 (VARI≠0, full retract) or G73 (VARI=0, chip-break) with Q = |RFP − FDEP| or |FDPR|. The FDEP/DAM decreasing peck chain is approximated by that constant first-peck depth.
  • MCALL CYCLE85(…,DTB,FFR,RFF) → G89 (DTB>0, dwell) or G85, feed-in F = FFR; the separate retract feed RFF has no slot in the shared expansion (retract reuses F).
  • bare MCALL → the G80 cancel sentinel (WriteCannedCycleCancel(JsonObject, string)).

The MCALL block itself must NOT execute the cycle (Sinumerik arms only), so no Parsing.G8x section is written here — the armed section rides the ModalCarrySyntax CannedCycle tracked key to the following motion blocks. Return plane: ReturnMode = G98 (previous-block Z); RTP has no slot in the shared expansion — programs that park at RTP before the first trigger get exactly RTP back, the corpus shape. Fail-soft paths (consume + structured warning + no arm): non-literal arguments (R-parameter args — cycle args bypass the P2 evaluator), missing RFP / depth / peck values, and any callee outside the CYCLE8x map (MCALL L123 modal subprogram calls are not simulated). Pipeline placement: before CannedCycleResolveSyntax in the Siemens Logic bundle.

SiemensPathSmoothingSyntax

Records the Siemens path-control / smoothing modal registers into the brand-invariant PathSmoothing section (fields per ISiemensPathSmoothingDef): the G-code groups G60/G64/G641/G642 (path control) and G601/G602 (exact-stop criterion) from Flags, the bare modal words FNORM / SOFT / BRISK / FFWON / FFWOF / COMPCAD / COMPON / COMPOF / UPATH / SPATH (captured by the preset's FlagSyntax word list), and the Parsing.CYCLE832 call sub-object (captured by SiemensCycleCallSyntax) whose first argument arms the high-speed tolerance (0 / empty parentheses cancel it).

Record-only — simulation does not alter the tool path (same contract as the Fanuc G05.1 sibling FanucPathSmoothingSyntax, which this class replaces in the Siemens preset: that one reads only the Parsing["G05.1"] sub-object no Siemens capture produces). IsEnabled is derived — true while a CYCLE832 tolerance is armed or the path-control group sits on a continuous-path mode (G64/G641/G642).

Modal behavior: a block touching any group starts from a clone of the previous block's section, applies the touched groups and rewrites the section; untouched blocks write nothing and ModalCarrySyntax (whose TrackedKeys already contain PathSmoothing) carries the previous section forward. The stream's first block stamps a conservative { IsEnabled: false } default — the actual delivered state of a real control is machine-data dependent, so no term is invented for it.

SiemensPivotTransformationSyntax

Siemens pivot gate over the shared engine (PivotTransformUtil): writes the PivotTransformSource entry on blocks where commanded XYZ needs the Pn→MC kinematic rigid transform — active TRAORI RTCP (SiemensTraoriSyntax's ToolHeightCompensation.Term), an active swivel/tilt (CYCLE800, or a mixed-dialect G68/G68.2 term), or a Dynamic chain entry. The Siemens-specific exclusion: a plain geometric frame (TRANS/ATRANS/ROT/AROT, IsPlainGeometryFrame(string)) transforms coordinates only and implies no physically positioned rotaries, so it must not open the gate — a corpus TRANS X0 Y0 Z0 reset would otherwise leave the modal term folding the pivot on every later plain-mode block.

The ISO/Fanuc sibling gate is PivotTransformationSyntax; both write the identical JSON vocabulary through the shared engine, and only one of them is registered per brand pipeline. Same chain-position contract: after all Pn-frame writers, so the PivotTransform entry lands last.

SiemensProgrammableFrameSyntax

Siemens programmable frame (TRANS/ATRANS/ROT/AROT incl. RPL=, plus the solid-angle forms ROTS/AROTS): consumes the structured Parsing.<keyword> sub-objects captured by SiemensFrameStatementSyntax, accumulates the programmable-frame matrix across blocks, and composes it into ProgramToMcTransform as the shared TransformSource entry — the same Source CYCLE800 writes, so the two stay mutually exclusive via AddOrReplaceTransform's in-place replacement (on a real Sinumerik, CYCLE800 itself writes the programmable frame chain, so single ownership mirrors the control).

Semantics follow the Sinumerik programmable-frame rules (HardNc reference: HardNcLine.ParseSiemensFrameTransform + NcArgSiemensFrame): the absolute forms TRANS/ROT reset the whole programmable frame and set only their own component; the additive forms ATRANS/AROT compose onto the current frame with the new operation applied first (M = M_op · M_prev, row-vector convention — an AROT after a TRANS rotates inside the translated frame). A bare keyword (any of the four) resets the programmable frame entirely — written as the shared inactive sentinel Term = "G69" plus an identity chain entry (the same convention HardNc's CYCLE800 reset uses). Multi-axis rotation in one statement applies the Sinumerik RPY order (intrinsic Z → Y′ → X″, i.e. row-vector Rx·Ry·Rz); RPL rotates about the active G17/G18/G19 plane normal and composes after the axis angles.

The solid-angle forms ROTS/AROTS follow the Sinumerik rules (Programming Manual Fundamentals 03/2010 §12.5, "ROTS and AROTS behave in the same way as ROT and AROT"): at most two solid angles orient a plane, composed first-named axis first with the second rotation about the original (extrinsic) axis — the pair X,Y keeps the new X axis in the old Z/X plane (row-vector Rx·Ry), Y,Z keeps the new Y axis in the old X/Y plane (Ry·Rz), Z,X keeps the new Z axis in the old Y/Z plane (Rz·Rx). A single angle is identical to ROT/AROT; RPL= alone rotates in the active plane. Three angles, or RPL mixed with axis angles, fall outside the documented grammar: the statement is left unapplied with a SiemensFrame--SolidAngleInvalid warning plus the visible Parsing--Unconsumed residue — never a guessed frame.

CROTS/SCALE/ASCALE/MIRROR/AMIRROR (zero corpus occurrences; CROTS references the control's frame database which has no offline counterpart, SCALE/MIRROR would inject non-rigid matrices whose remaining breakages are the radius-compensation magnitude, the program-space path length feeding durations, and the writeback Euler decomposition) are consumed recognized-but-not-simulated with a SiemensFrame--Unsupported warning and zero transform effect. A structured keyword whose capture fell back to the verbatim Statement shape, or whose value is an unevaluated variable expression, is left in Parsing — the VariableExpression--Unevaluated diagnostic plus the visible Parsing--Unconsumed residue is the correct fail-soft (P2 acceptance doctrine); the frame is not partially applied.

Must run after SiemensCycle800TiltSyntax (this syntax owns the once-per-block TiltTransform modal carry: it carries only when no earlier syntax authored the section on this block) and before the coordinate-offset syntaxes, so the frame entry lands ahead of CoordinateOffset in the chain (McXyz = ProgramXyz · M_frame · M_offset · … — the programmable frame applies to program coordinates first, then the settable G54 frame, matching the Sinumerik frame chain).

SiemensStopreSyntax

Consumes the Siemens STOPRE flag (stop preprocessing — the control's look-ahead buffer sync) from Flags and records a non-modal block-root Stopre section. STOPRE has no effect in offline simulation (there is no preprocessing buffer to flush), so an Stopre–NoOp Unsupported Message is emitted: recognized, intentionally not simulated, safe offline.

Capture side: STOPRE is a bare word collected by the Siemens preset's FlagSyntax word list.

SiemensToolOffsetSyntax

Siemens cutting-edge tool offset activation: consumes a standalone D word (D1 activates edge 1 of the active tool, D0 cancels compensation), resolves the effective length via TryGetToolHeightOffset_mm(int, int, out double) ($TC_DP3, geometry + additive wear) for the (active tool, D) pair — a pair without a $TC_DP row falls back to the generic IToolOffsetConfig height for the tool number (with a SiemensToolOffset–TcdpRowMissing configuration warning), so an unfilled per-case table follows the ToolHouse-fed source instead of silently machining with offset 0 — and writes the same downstream state as the ISO sibling ToolHeightOffsetSyntax: the IToolHeightCompensationDef section (with Term = “D”) plus the ToolHeightCompensation entry in the ProgramToMcTransform chain — sharing the transform Source keeps the two brands' compensation mutually exclusive via AddOrReplaceTransform's in-place replacement.

The active tool number comes from the block's (or previous block's) ToolChange section; a string tool name resolves through FindToolNumberByName(string). Modal ownership follows the same yield protocol as the ISO sibling: blocks without a D word re-resolve only when the previous section's Term is ours ("D"); an ISO term (G43/G44/G49) leaves the section to ToolHeightOffsetSyntax — real Siemens files mix both dialects (G43H1 headers next to D1 blocks). Must therefore be placed after ToolHeightOffsetSyntax (and after ToolChangeSyntax) in the Logic bundle, and before the brand pivot gate (SiemensPivotTransformationSyntax in the Siemens list) so the pivot entry stays at the chain tail.

Consuming Parsing.D here (Logic) intentionally precedes RadiusCompensationSyntax (PostLogic): on Siemens, D selects the cutting edge — it is not the Fanuc G41 D5 radius argument, and radius state derives from the same (T, D) edge ($TC_DP6; wiring the radius value is a follow-up).

SiemensTraoriSyntax

Siemens TRAORI/TRAFOOF (orientation transformation = RTCP): the Siemens sibling of G43p4RtcpSyntax. While TRAORI is active, the IToolHeightCompensationDef section carries Term = “TRAORI” and the ToolHeightCompensation chain 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 single signal that routes the block to ClLinear per-step IK.

Tool length ownership stays with the (T,D) machinery: on real Sinumerik, TRAORI uses the active D edge's length. Activation adopts the compensation the D edge (or a mixed-dialect ISO G43) has already resolved — SiemensToolOffsetSyntax runs earlier in the bundle, so an explicit D1 on any TRAORI-modal block first resolves Term = "D" and this syntax re-takes the section with the fresh Offset_mm. The adopted owner is recorded in PriorTermKey; TRAFOOF hands the section back to it (default "D"), because plain length compensation survives TRAORI deactivation on the control — TRAFOOF only ends the orientation-following. A TRAFOOF with no active TRAORI (the corpus' ubiquitous defensive preamble) is consumed silently.

Must run after ToolHeightOffsetSyntax / SiemensToolOffsetSyntax / the coordinate-offset syntaxes (mirroring G43p4RtcpSyntax's Fanuc slot) and before SiemensPivotTransformationSyntax, whose gate recognizes the TRAORI term and folds the kinematic pivot. Silently degrades to a plain UnitZ · offset translation when IMachineKinematics is absent.