Auto: focas-f1c — Modal codes + overrides

Closes #259

Adds Modal/ + Override/ fixed-tree subfolders per FOCAS device, mirroring the
pattern established by Status/ (#257) and Production/ (#258): cached snapshots
refreshed on the probe tick, served from cache on read, no extra wire traffic
on top of user-driven tag reads.

Modal/ surfaces the four universally-present aux modal codes M/S/T/B from
cnc_modal(type=100..103) as Int16. **G-group decoding (groups 1..21) is deferred
to a follow-up** — the FWLIB ODBMDL union differs per series + group and the
issue body explicitly permits this scoping. Adds the cnc_modal P/Invoke +
ODBMDL struct + a generic int16 cnc_rdparam helper so the follow-up can add
G-groups without further wire-level scaffolding.

Override/ surfaces Feed/Rapid/Spindle/Jog from cnc_rdparam at MTB-specific
parameter numbers (FocasDeviceOptions.OverrideParameters; defaults to 30i:
6010/6011/6014/6015). Per-field nullable params let a deployment hide overrides
their MTB doesn't wire up; passing OverrideParameters=null suppresses the entire
Override/ subfolder for that device.

6 unit tests cover discovery shape, omitted Override folder when unconfigured,
partial Override field selection, cached-snapshot reads (Modal + Override),
BadCommunicationError before first refresh, and the FwlibFocasClient
disconnected short-circuit.
This commit is contained in:
Joseph Doherty
2026-04-25 14:26:48 -04:00
parent ae7cc15178
commit 3c2c4f29ea
6 changed files with 563 additions and 1 deletions

View File

@@ -99,6 +99,19 @@ internal static class FwlibNative
[DllImport(Library, EntryPoint = "cnc_rdtimer", ExactSpelling = true)]
public static extern short RdTimer(ushort handle, short type, ref IODBTMR buffer);
// ---- Modal codes ----
/// <summary>
/// <c>cnc_modal</c> — read modal information for one G-group or auxiliary code.
/// <paramref name="type"/>: 1..21 = G-group N (single group), 100 = M, 101 = S,
/// 102 = T, 103 = B (per Fanuc FOCAS reference). <paramref name="block"/>: 0 =
/// active modal commands. We only consume types 100..103 today (M/S/T/B); the
/// G-group decode is deferred to a follow-up because the <c>ODBMDL</c> union
/// varies by group + series (issue #259).
/// </summary>
[DllImport(Library, EntryPoint = "cnc_modal", ExactSpelling = true)]
public static extern short Modal(ushort handle, short type, short block, ref ODBMDL buffer);
// ---- Structs ----
/// <summary>
@@ -151,6 +164,22 @@ internal static class FwlibNative
public int Msec;
}
/// <summary>
/// ODBMDL — single-group modal read buffer. 4-byte header + a 4-byte union which we
/// marshal as a fixed byte array. For type=100..103 (M/S/T/B) the union holds an
/// <c>int aux_data</c> at offset 0; we read the first <c>short</c> for symmetry with
/// the FWLIB <c>g_modal.aux_data</c> width on G-group reads. The G-group decode
/// (type=1..21) is deferred — see <see cref="Modal"/> for context (issue #259).
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ODBMDL
{
public short Datano;
public short Type;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Data;
}
/// <summary>ODBST — CNC status info. Machine state, alarm flags, automatic / edit mode.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ODBST