Table of Contents

Enum BareG28Behavior

Namespace
Hi.NcParsers.LogicSyntaxs
Assembly
HiMech.dll

Writes ICompoundMotionDef section for G28 reference point return. Reads intermediate XYZ from Parsing.G28 (written by G28Syntax) and converts to machine coordinates via ResolveProgramXyz(JsonNode, LazyLinkedListNode<SyntaxPiece>, ISentenceCarrier, NcDiagnosticProgress).

Must be placed after LinearMotionSyntax in the syntax chain. Removes the IMotionEventDef section written by LinearMotionSyntax (G28 handles its own motion). Overwrites root MachineCoordinateState and ProgramXyz with reference position for subsequent block lookback.

public enum BareG28Behavior
Extension Methods

Fields

Alarm = 0

Emit Coord-RefReturn–003 validation error and consume the bare G28 without emitting motion.

AllAxesHome = 1

Interpret bare G28 as if every configured axis were listed at its current modal value, so item 0 (intermediate) is a no-op and item 1 sends each configured axis to its home. Requires an IMachineAxisConfig dep; without one the syntax falls back to Alarm.

Examples

All cases hardcode a TestDeps.HomeMc with X/Y home at 0 and Z home at 100 (typical mill where Z-home is above the table) and leave the ProgramToMcTransform chain at identity so the final ProgramXyz equals MachineCoordinateState. The G28 pattern emits a 2-item CompoundMotion: item 0 is the intermediate point in ProgramXyz, item 1 is the final position in MachineCoordinateState. Axes not present in the G28 block keep the previous-block MC value rather than going home.

G91 G28 X0 Y0 Z0 with a #Previous: block carrying MachineCoordinateState=(50,60,70) — all three axes go home, so the final MC is the configured home (0,0,100):

#Previous:
{ "MachineCoordinateState": { "X": 50, "Y": 60, "Z": 70 } }
#BeforeBuild:
{ "Parsing": { "G28": { "X": 0, "Y": 0, "Z": 0 } } }
#AfterBuild:
{
  "CompoundMotion": {
    "Term": "G28",
    "Items": [
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "ProgramXyz": { "X": 0, "Y": 0, "Z": 0 }
      },
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "X": 0, "Y": 0, "Z": 100 }
      }
    ]
  },
  "ProgramXyz": { "X": 0, "Y": 0, "Z": 100 }
}
G91 G28 Z0 — only Z goes to its home; X/Y inherit from the previous block's MC. Item 0's intermediate ProgramXyz takes X/Y from the inherited program XYZ (= previous MC under identity transform) and Z from the literal 0 in the G28 block: #Previous:
{ "MachineCoordinateState": { "X": 50, "Y": 60, "Z": 70 } }
#BeforeBuild:
{ "Parsing": { "G28": { "Z": 0 } } }
#AfterBuild:
{
  "CompoundMotion": {
    "Term": "G28",
    "Items": [
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "ProgramXyz": { "X": 50, "Y": 60, "Z": 0 }
      },
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "X": 50, "Y": 60, "Z": 100 }
      }
    ]
  },
  "ProgramXyz": { "X": 50, "Y": 60, "Z": 100 }
}
No IHomeMcConfig dep on the dependency list — the syntax early-returns and the G28 sub-section stays in Parsing for an upstream consumer or downstream syntax to handle: #BeforeBuild:
{ "Parsing": { "G28": { "X": 0, "Y": 0, "Z": 0 } } }
#AfterBuild:
{ "Parsing": { "G28": { "X": 0, "Y": 0, "Z": 0 } } }

Rotary cases below add TestDeps.AxisConfig declaring B as rotary and extend HomeMc with the conventional B home at 0°. Each rotary block uses literal B = 45° so item 0's intermediate (45°), item 1's home (0°), and #Previous: modal B (30°) are pairwise distinct — a test that swaps any two values for any other is caught by the assertion. The wrap pass (McAbcCyclicPathSyntax) is a different syntax, so these per-SUT conformance assertions show only the raw literal / canonical-home values written by this syntax, before any cyclic normalization runs.

G91 G28 B45. — pure rotary G28. Emits a 2-item CompoundMotion whose items carry only ABC keys in MC; no XYZ ProgramXyz and no XYZ MC because the block doesn't reference X/Y/Z (and the conformance harness doesn't run McXyzSyntax downstream — in the full pipeline that syntax fills root MachineCoordinateState's XYZ from root ProgramXyz, but with no XYZ in the block there's nothing to fill anyway). Root MC.B holds the canonical home for modal carry-forward; root ProgramXyz is not written: #BeforeBuild:
{ "Parsing": { "G28": { "B": 45 } } }
#AfterBuild:
{
  "MachineCoordinateState": { "B": 0 },
  "CompoundMotion": {
    "Term": "G28",
    "Items": [
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "B": 45 }
      },
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "B": 0 }
      }
    ]
  }
}
G28 X0. B45. mixed XYZ + rotary. Both axis kinds occupy the same two items: item 0 carries the XYZ intermediate ProgramXyz alongside the rotary literal in MC; item 1 carries the final XYZ MC alongside the rotary home in MC. Root MachineCoordinateState here holds only the rotary modal value (B = 0, the home); the XYZ portion of root MC would be filled by the downstream McXyzSyntax in the full pipeline (out of scope for this per-SUT conformance). Root MachineCoordinateState appears first because the rotary-home write happens before CompoundMotion / ProgramXyz are inserted. #Previous: carries B = 30 so the prev rotary modal is distinct from both the literal (45) and the home (0): #Previous:
{ "MachineCoordinateState": { "X": 50, "Y": 60, "Z": 70, "B": 30 } }
#BeforeBuild:
{ "Parsing": { "G28": { "X": 0, "B": 45 } } }
#AfterBuild:
{
  "MachineCoordinateState": { "B": 0 },
  "CompoundMotion": {
    "Term": "G28",
    "Items": [
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "ProgramXyz": { "X": 0, "Y": 60, "Z": 70 },
        "MachineCoordinateState": { "B": 45 }
      },
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "X": 0, "Y": 60, "Z": 70, "B": 0 }
      }
    ]
  },
  "ProgramXyz": { "X": 0, "Y": 60, "Z": 70 }
}

Bare G28 — no axis specifiers — exercises the configurable BareG28 policy. Default Alarm emits Coord-RefReturn--003 and consumes the G28 without motion (the diagnostic surfaces through the NcDiagnosticProgress sink, not the block JSON, so the canonical #AfterBuild is just an empty object):

#BeforeBuild:
{ "Parsing": { "G28": {} } }
#AfterBuild:
{}
Bare G28 with BareG28 set to AllAxesHome: the syntax synthesises a literal at the inherited program position for every configured linear axis and the previous modal angle for every configured rotary axis (here X/Y/Z taken from the #Previous: MC under the identity ProgramToMcTransform, B taken from the prev modal). Item 0's intermediate therefore equals current (no motion in stage 1) and item 1 sends each axis to its home: #Previous:
{ "MachineCoordinateState": { "X": 10, "Y": 20, "Z": 30, "B": 45 } }
#BeforeBuild:
{ "Parsing": { "G28": {} } }
#AfterBuild:
{
  "MachineCoordinateState": { "B": 0 },
  "CompoundMotion": {
    "Term": "G28",
    "Items": [
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "ProgramXyz": { "X": 10, "Y": 20, "Z": 30 },
        "MachineCoordinateState": { "B": 45 }
      },
      {
        "MotionEvent": { "Form": "McLinear", "IsRapid": true },
        "MachineCoordinateState": { "X": 0, "Y": 0, "Z": 100, "B": 0 }
      }
    ]
  },
  "ProgramXyz": { "X": 0, "Y": 0, "Z": 100 }
}