Complete sim config boundary coverage

This commit is contained in:
2026-06-11 06:12:06 +08:00
parent 5bd8f12872
commit 1ab5571ae1
76 changed files with 18975 additions and 146 deletions

274
text2.txt Normal file
View File

@@ -0,0 +1,274 @@
新下一步执行计划
生成时间2026-06-09 14:20 CST
本计划接替 `text.txt`。后续执行以本文件为准。
项目纪律:
- 数控/G-code/remap/tool/parameter/planner/kinematics/user-M 语义必须来自
LinuxCNC upstream 或 vendored LinuxCNC C/C++ source。
- 本项目允许写的代码范围是构建、source sync、runtime shim、filesystem
staging、OPFS、WASM/browser boundary、测试胶水、文档。
- 不通过修改 G-code 语义、JS 解释逻辑、或 standalone `Interp::...` 实现来让
测试通过。
- 需要 INI/tool table/parameter file/SUBROUTINE_PATH/USER_M_PATH/remap-NGC
上下文的程序,必须带上下文运行,不能脱离配置单独判断。
- browser 不能依赖目录枚举。browser/Node 共享 staging 时,优先使用
`tools/source-manifest.txt` + INI 文本生成计划。
当前已完成基线:
- 规划 iG-code run_step 状态输出已完成第一阶段。
已输出当前行号、statement_uri、进度相关 step、X/Y/Z/A/B/C/U/V/W 位置。
UI 已优先解析 run_stepfallback 到 canonical event。
- 规划 ii基础 G-code smoke 已固化代表集。
`nc_files/3D_Chips.ngc` 已按 tool-table context 运行,裸跑缺 tool 的负向边界
已明确。
- configs/sim 代表 runtime edge 已覆盖:
`axis/foam` U/V axis mask、bridge-mill W/remap path、`axis/geometry` M110、
`external_offsets` M111 和 subroutine staging 已在 native/WASM/browser
representative smoke 中验证。
- 文件上下文 staging 规则已抽成通用 SDK helper
`planIniFileContextStaging()` 负责 generic INI-context manifest-based plan
`planSimConfigStaging()` 是 `configs/sim` wrapper
Node 和真实 browser smoke 已覆盖 INI、OPEN_FILE、TOOL_TABLE、PARAMETER_FILE、
multi-directory SUBROUTINE_PATH、USER_M_PATH、executable user-M、remap-NGC 和
wasmPath 输出。
- 测试分层文档已补齐:
`docs/compatibility-validation.md` 已记录 4 层测试的入口、当前结果、
LinuxCNC-owned behavior、host/WASM adapter allowance 和 expected-failure
policy。
当前验证口径:
- Layer 1: `wasm-port/tests/native/verify_nc_files.sh`
当前基线total 107, pass 101, expected_fail 6, unexpected_fail 0。
- Layer 2: `wasm-port/tests/native/verify_sim_configs.sh`
当前基线total 159, pass 151, expected_fail 8, unexpected_fail 0。
- Layer 3: `wasm-port/tests/native/verify_native_probes.sh`
当前应通过,包含 source sync、no-standalone-semantics、native fixture
baseline、sim-config 和 nc_files checks。
- Layer 4: `wasm-port/tests/host/verify_host_smokes.sh`
当前应通过,包含 Node WASM、OPFS、browser interpreter 和 browser INI panel
representative smoke。
新执行顺序:
1. 先稳定当前大批改动,不继续扩大测试面
目标:
- 对当前累计改动做一次完整一致性验证。
- 确认 vendor manifest、native probes、Node/browser smoke 都仍处于可提交状态。
- 在继续新增 upstream tests 前,先把当前批次变成一个清晰、可审查的工作集。
执行:
```bash
git diff --check
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tests/wasm/node/verify_interp_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
wasm-port/tests/native/verify_native_probes.sh
```
通过条件:
- `git diff --check` clean。
- `vendor sync validation complete`。
- `interp_wasm_node_smoke=ok`。
- `sim_configs_wasm_node_smoke=ok`。
- `browser_interp_smoke=ok`。
- `host_wasm_opfs_browser_smokes=ok`。
- native summaries 中仍为:
`sim-configs total 159 pass 151 expected_fail 8 unexpected_fail 0`
`nc_files total 107 pass 101 expected_fail 6 unexpected_fail 0`。
不做:
- 不新增 upstream fixture。
- 不改 LinuxCNC vendored 文件内容。
- 不把 expected failure 改成 pass除非 runtime edge 已经通过 vendored source
路径证明。
2. 整理当前大批改动的提交/审查边界
目标:
- 把当前累计改动按逻辑拆成可审查批次。
- 如果不提交,也至少在文档里列出可拆分边界,方便后续 review。
建议拆分边界:
- Batch A: run_step 状态输出和 UI/browser/Node 断言。
- Batch B: nc_files 代表 smoke 和 `3D_Chips.ngc` tool-table context。
- Batch C: upstream `tests/interp/*`、`tests/ccomp/*` selected fixture 扩展。
- Batch D: G92 parameter persistence、tool table、G10/G52/G71/G72/G76 等
interpreter regression coverage。
- Batch E: generic INI-context staging helper 和 Node/browser synthetic coverage。
- Batch F: 文档分层、source reuse map、compatibility validation、tracker 更新。
执行:
```bash
git status --short
git diff --stat
git diff --name-only
```
输出要求:
- 记录每个 batch 对应文件。
- 标明哪些新增 `wasm-port/vendor/linuxcnc/...` 文件必须由
`tools/source-manifest.txt` 和 `verify_vendor_sync.sh` 覆盖。
3. 收敛 configs/sim 剩余 expected failure不改语义
目标:
- 继续分析 Layer 2 中 8 个 expected_fail。
- 明确哪些只是 upstream `rs274` 缺 task/user-M/runtime context
哪些已经由 Layer 3/4 runtime representative smoke 覆盖;
哪些仍需要新的 runtime adapter 或 blocked entry。
重点对象:
- `axis/foam/foam.ngc`
已有 U/V axis mask runtime coverage。确认 Layer 2 expected_fail 是否只属于
native upstream standalone context 限制。
- `axis/vismach/5axis/bridgemill/5axisgui.ngc`
已有 bridge-mill W/remap representative coverage。确认 expected_fail 是否只
属于 native full sim/task/HAL boundary。
- `axis/geometry/xyzc.ngc`
已有 M110 USER_M_PATH deterministic boundary。确认 native expected_fail 与
runtime coverage 对齐。
- `axis/external_offsets/*.ngc`
已有 M111 deterministic boundary 和 `opa_demo.ngc -> circles.ngc`
SUBROUTINE_PATH staging。确认剩余 expected_fail 的具体原因。
- `incremental_repetition_g533.ngc`
保留 upstream demo expected failure。禁止通过修改 G-code 语义或 runner
语义让它 pass。
执行:
```bash
wasm-port/tests/native/verify_sim_configs.sh
cat wasm-port/build/native/sim-configs/summary.tsv
```
产出:
- 更新 `docs/compatibility-validation.md` 或
`docs/linuxcnc-test-porting-tracker.md`,逐条记录 8 个 expected_fail 的当前
层级归因。
- 如果某项已由 Layer 3/4 覆盖,写明对应验证命令和 smoke assertion。
- 如果某项未覆盖,加入明确 blocked dependency 或下一步 runtime boundary。
4. 将 generic INI-context staging helper 用到更多手写 staging 点
目标:
- 减少 Node/browser 测试中手写 `TOOL_TABLE`、`PARAMETER_FILE`、
`SUBROUTINE_PATH`、`USER_M_PATH` 和 remap files 的重复。
- 只迁移“已经 vendored 且 manifest 完整”的测试,不扩大功能面。
候选:
- `tests/wasm/node/verify_interp_wasm.mjs` 中带 `test.ini`、`test.tbl`、
`startup.var`、`subs/*.ngc` 的 upstream regression staging。
- `tests/browser/interp_smoke.html` 中与 Node 同构的 upstream regression
staging。
- 不急于迁移 five-axis 专用 staging除非能保持 `executionMode:
"fiveAxisRemap"` 现有路径清晰。
执行原则:
- 先抽小 helper`loadPlannedVendorFiles(plan)` 或测试局部 helper。
- 保持 `planIniFileContextStaging()` 只返回 plan不读文件、不 fetch。
- Node 侧从 filesystem 读 `vendor/linuxcnc/${sourceRel}`。
- Browser 侧 fetch `../../vendor/linuxcnc/${sourceRel}`。
- 每次迁移后跑:
```bash
wasm-port/tests/wasm/node/verify_interp_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
```
5. 继续 upstream `tests/interp/*` intake但必须小批量
前置条件:
- 第 1 步完整验证通过。
- 第 2 步当前工作集边界清楚。
- 第 3 步 expected failure 归因没有新疑点。
候选优先级:
- 纯 interpreter file execution。
- 不需要 Python remap。
- 不需要 full task/motion/HAL process。
- 需要 tool table/parameter/subroutine context 的测试,必须通过 INI-context
staging 运行。
- 有 upstream expected output 或可稳定断言 canonical event/error text。
候选方向:
- `tests/interp/oword-unwind`
可能适合 continue-on-error runner先 native probe 验证,再 Node/browser。
- `tests/interp/g6164`
先确认是否纯 interpreter、是否需要额外 machine/runtime context。
- `tests/interp/compile`
先判断它是 compile/source test 还是 runtime interpreter test不要误归类。
- `tests/interp/mdi-*`、`oword-mdi-*`
默认视为 MDI/UI/full-process 候选,先加入 blocked table除非能证明存在
NGC-only subpath。
- `tests/interp/pymove`、`python-self`
默认 blockedPython O-word/remap boundary 未实现。
每个 intake 必须执行 checklist
- 记录 upstream path。
- byte-for-byte vendor 原始文件。
- 更新 `tools/source-manifest.txt` 和 vendor sync。
- 确认 LinuxCNC source ownership。
- 先 native harness/probe再 Node WASM再 browser。
- 更新 `docs/source-reuse-map.md`、
`docs/compatibility-validation.md`、
`docs/linuxcnc-test-porting-tracker.md`。
- 如 blocked加入 blocked-test table 并写清 dependency。
6. 不做事项
- 不继续扩大 `configs/sim` 全量 WASM/browser 执行面,除非某个 expected failure
已经有明确 runtime boundary 价值。
- 不引入 JS G-code parser 或 JS remap/tool/parameter semantics。
- 不编辑 `linuxcnc/` upstream 工作树。
- 不修改 `wasm-port/vendor/linuxcnc/` vendored 文件内容;只能 byte-for-byte copy
upstream 文件。
- 不绕过 `tools/verify_no_standalone_cnc_semantics.sh`。
推荐下一次立即执行:
1. 运行第 1 步完整一致性验证。
2. 如果通过,执行第 2 步,整理当前工作集 batch 边界。
3. 然后再进入第 3 步,逐条归因 configs/sim 8 个 expected_fail。

386
text3.txt Normal file
View File

@@ -0,0 +1,386 @@
configs/sim 全面测试下一步实施计划
生成时间2026-06-09 15:00 CST
本计划接替 `text2.txt`。后续 `configs/sim` 相关工作以本文件为准。
目标定义:
- 这里的“全部完成全面测试”不等于“让 `linuxcnc/configs/sim` 下所有 `.ngc`
在 standalone `bin/rs274` 下全部 PASS”。
- 正确目标是:
1. 对 `configs/sim` 下所有 `.ngc` 建立完整 inventory
2. 每个文件都被归入明确类别;
3. 每个类别都有正确入口点和验证层;
4. 能在 standalone native/WASM/browser 中运行的,必须补齐覆盖;
5. 不能在 standalone 路径中真实复现的,必须记录为 blocked并写清依赖
6. 不通过修改 G-code 语义、JS 解释逻辑、或 project-owned standalone
interpreter 语义让测试“看起来通过”。
项目纪律:
- CNC 语义来源只能是 LinuxCNC upstream 或 vendored LinuxCNC source。
- `configs/sim` 程序必须在完整上下文下判断INI、tool table、parameter file、
`SUBROUTINE_PATH`、`USER_M_PATH`、remap-NGC、Python remap、task/runtime
边界都要按 LinuxCNC 真实归属处理。
- browser 不能依赖目录枚举Node/browser staging 继续优先使用
`tools/source-manifest.txt` + INI 文本生成计划。
- 不为了“全面测试”而把 full-process / HAL / UI / linuxcncrsh / Python binding
误降级为 standalone interpreter file execution。
当前真实基线:
- Layer 2: `wasm-port/tests/native/verify_sim_configs.sh`
当前基线:`total 159, pass 151, expected_fail 8, unexpected_fail 0`。
- Layer 3: `wasm-port/tests/native/verify_native_probes.sh`
当前通过,已经覆盖代表性 runtime edge
`axis/foam` U/V、bridge-mill W/remap、`axis/geometry` M110、
`axis/external_offsets` M111、`opa_demo.ngc -> circles.ngc`。
- Layer 4:
`wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`、
`wasm-port/tests/browser/verify_interp_browser.sh`、
`wasm-port/tests/host/verify_host_smokes.sh`
当前通过,但只覆盖 representative subset不是全量 `configs/sim`。
当前已知剩余 expected failure
- `axis/foam/foam.ngc`
native upstream standalone `rs274` 缺 U/V axis reader上层 runtime 已覆盖。
- `axis/vismach/5axis/bridgemill/5axisgui.ngc`
native upstream standalone `rs274` 缺 W axis reader上层 runtime 已覆盖。
- `axis/geometry/xyzc.ngc`
native upstream standalone `rs274` 缺 `USER_M_PATH` M110 注册,上层 runtime 已覆盖。
- `axis/external_offsets/dyn_demo.ngc`
- `axis/external_offsets/eoffsets.ngc`
- `axis/external_offsets/jwp_z.ngc`
- `axis/external_offsets/opa_demo.ngc`
native upstream standalone `rs274` 缺 `USER_M_PATH` M111 注册,上层 runtime 已覆盖;
其中 `opa_demo.ngc` 还依赖 `SUBROUTINE_PATH` `circles.ngc`,上层 runtime 已覆盖。
- `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc`
保持 upstream demo expected failure禁止通过修改 G-code 或 JS 解释逻辑让它 PASS。
全面测试还缺哪些工作:
1. 完整建立 `configs/sim` 程序级覆盖矩阵
当前问题:
- 我们有 harness summary但还没有一份“每个 `.ngc` 的归属矩阵”:
哪些是 `main`、哪些是 `macro_load`、哪些是 `remap_subroutine`、
哪些只是 LinuxCNC native baseline、哪些已经进入 Layer 3、哪些已经进入 Layer 4、
哪些仍 blocked。
需要产出:
- 一份 tracked matrix建议新增
```text
wasm-port/docs/sim-configs-coverage-matrix.md
```
矩阵至少包含列:
- `path`
- `class`
- `native_rs274_status`
- `expected_failure_reason`
- `layer3_runtime_probe`
- `layer4_node`
- `layer4_browser`
- `blocked_dependency`
- `notes`
通过条件:
- `wasm-port/build/native/sim-configs/summary.tsv` 中所有 159 条记录都能映射到 matrix。
- matrix 中不能有“未分类”行。
2. 明确“全部”里的 blocked 边界,而不是继续误扩面
当前问题:
- `configs/sim` 下面并不是所有 `.ngc` 都应该被强行推进到 browser full execution。
- 还缺一份 `configs/sim` 专属 blocked policy用来区分
- pure interpreter / remap / INI-context 可移植程序;
- task/user-M/runtime edge 程序;
- Python remap/full-process/HAL/UI 依赖程序;
- demo edge / upstream malformed demo。
需要明确加入 blocked 的类:
- 任何本质依赖 linuxcncrsh、GUI driver、HAL process、实时 motion 状态反馈、
外部 userspace component、或 Python binding API 的 sim-config path。
- `mdi-*`、UI action、或只能通过 full task process 触发的配置流。
- 不能通过 NGC-only subpath 提纯的 Python/full-process config family。
执行:
- 从 `verify_sim_configs.sh` summary 和 `configs/sim` 路径结构出发,
逐目录补 blocked classification。
- 先补 family-level blocked再细化到 program-level。
产出:
- 更新 `docs/linuxcnc-test-porting-tracker.md` blocked table
- 更新 `docs/compatibility-validation.md` 的 `configs/sim` 边界说明;
- 在新 matrix 中写出每个 blocked 程序或目录的 dependency。
3. 把 representative coverage 扩展成 class coverage而不是盲目追求全量 browser
当前问题:
- Layer 4 现在只覆盖 representative subset
`foam`、`geometry`、`external_offsets`、bridge-mill。
- 这还不足以支撑“全面测试完成”的说法,因为 `configs/sim` 还包含多种 machine class
- plain INI/tool-table/main program
- Python remap main program
- remap subroutine only
- five-axis switchkins / TWP / TDR / TRT
- macro-only config families
- on_abort / macro load / tool-change style files。
实施原则:
- 不是把 159 个程序都复制进 browser smoke。
- 是每种独立 runtime class 至少补一个 native + Node + browser representative
并且 class 到 program 的归因在 matrix 中完整记录。
最低还要补齐的 representative class
- TWP `table-rotary_spindle-rotary-nutating`
当前 native baseline 已有 14/15 passing inventory但 Layer 4 还没有代表性 TWP
runtime smoke。
- gmoccapy Python remap family
native inventory 已通过,但 Layer 4 还没有任何 gmoccapy representative。
- axis/laser Python remap family
native inventory 已通过,但 Layer 4 还没有任何 laser representative。
- generic `macro_load` family
当前 Layer 4 基本聚焦 main programs缺少“宏文件只验证 load/parse不伪造 main”
的 shared assertion。
- `on_abort` / deterministic user-action macro family
当前 native inventory大量 PASS但 Node/browser 尚未有独立 representative class。
通过条件:
- 每个 runtime class 在 `docs/sim-configs-coverage-matrix.md` 中都能对应至少一个
Layer 3/Layer 4 representative。
- 不要求 159 个程序全部进入 browser smoke
但要求每个 class 都有代表 sample且每个非代表 sample 都有“为什么不需要单独进
browser”的记录。
4. 补 `configs/sim` 专属全量 Node inventory runner
当前问题:
- Node 侧现在只有 representative smoke没有一个“只跑能在 standalone/WASM
路径中合理成立的 `configs/sim` 全量 inventory”。
需要新增:
```text
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
```
职责:
- 读取 native `summary.tsv` 或同等来源;
- 只挑选:
- native PASS 条目;
- 以及 Layer 2 expected_fail 但 Layer 3/4 已知有 runtime adapter coverage 的条目;
- 跳过已标记 blocked 的 full-process/HAL/UI-only family
- 对 Node WASM 做 inventory run
- 输出 Node 侧 summary.tsv。
重要限制:
- 不把 browser 作为 first target
- 不新增 JS CNC 语义;
- 不把 Python/full-process family 强行塞进 Emscripten除非已存在 LinuxCNC-owned
runtime path。
通过条件:
- Node inventory summary 可重跑、可对比、可纳入 CI
- unexpected failure 为 0
- expected skip / blocked 有明确计数。
5. 再决定 browser inventory而不是直接上全量 browser
当前问题:
- browser 环境成本高,且不能依赖目录枚举。
- 如果先做 browser 全量 inventory会把大量问题混在 host boundary、
asset staging、Emscripten runtime、Playwright orchestration 里,定位价值低。
实施顺序:
- 先完成 Node inventory
- 从 Node inventory 中挑出最有价值的 browser representative 扩展;
- browser 保持 focused class smoke不追求一次性全量 159。
可以进入 browser 扩展候选的 class
- TWP representative
- gmoccapy Python remap representative
- axis/laser representative
- one deterministic macro-only family
- one toolchange / on_abort family。
通过条件:
- browser 侧 class coverage 明确,不再只是 `foam/geometry/external_offsets/bridgemill`
- 仍然保持稳定、可复现、非目录枚举。
6. 把 `verify_sim_configs.sh` 从 inventory 提升为 coverage source-of-truth
当前问题:
- native `summary.tsv` 已经是事实来源,但还缺少稳定的 machine-readable 统计,
用来支撑 docs、Node inventory 和后续 CI 对账。
需要增强:
- 保持 `summary.tsv` 不变;
- 增加稳定派生 artifact建议
```text
wasm-port/build/native/sim-configs/class-summary.tsv
wasm-port/build/native/sim-configs/path-matrix.tsv
```
最少字段:
- `path`
- `class`
- `status`
- `expected_failure`
- `ini`
- `tbl`
- `runtime_family`
- `blocked`
注意:
- 如果不想提交 generated artifact就由脚本生成并由 docs 读取规则描述;
- 但字段模型要先定下来。
7. 清理 `configs/sim` 文档的“完成”定义
当前问题:
- 现有 `docs/sim-configs-completion-plan.md` 更多描述了“把当前大块 runtime edge
打通”的完成,不是“全面测试完成”的完成。
需要文档调整:
- 新增一节:`Definition of Done for Full configs/sim coverage`
- 明确:
- inventory complete
- blocked table complete
- native source-of-truth complete
- Node inventory complete
- browser class coverage complete
- every expected failure justified
- no accidental standalone semantic ownership
8. 最后再谈“还能不能把 Layer 2 的 8 个 expected_fail 变少”
原则:
- `foam` / `bridgemill` / `M110` / `M111` 这些 expected_fail 不是当前首要问题;
它们已经由 Layer 3/4 runtime path 证明。
- 只有当能够通过 vendored LinuxCNC source path 合法地把 native strict baseline
改造成更贴近 runtime 的入口点时,才讨论减少 expected_fail。
- 在那之前,不改 `verify_sim_configs.sh` 的语义口径,不把 expected_fail 硬改成 PASS。
优先级排序:
1. coverage matrix
2. blocked table
3. Node inventory
4. browser class expansion
5. docs done-definition
6. 再评估 Layer 2 baseline 是否需要新入口点
推荐执行顺序:
1. 先建立 coverage matrix
执行:
```bash
wasm-port/tests/native/verify_sim_configs.sh
cat wasm-port/build/native/sim-configs/summary.tsv
```
产出:
- 新增 `wasm-port/docs/sim-configs-coverage-matrix.md`
- 159 条记录全部分类
2. 再补 blocked table 和 class taxonomy
执行:
- 逐目录梳理 `linuxcnc/configs/sim`
- 对照 `verify_sim_configs.sh` summary
- 把 full-process/HAL/UI-only family 写进 tracker blocked table
产出:
- 更新 `docs/linuxcnc-test-porting-tracker.md`
- 更新 `docs/compatibility-validation.md`
3. 实施 Node inventory runner
执行:
```text
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
```
通过条件:
- Node inventory 只跑可移植条目
- unexpected failure = 0
4. 扩 browser class coverage
执行:
- 先补 TWP representative
- 再补 gmoccapy representative
- 再补 axis/laser representative
- 最后补 macro-only / on_abort representative
通过条件:
- `verify_interp_browser.sh` 和 `verify_host_smokes.sh` 仍稳定通过
- browser 不引入目录枚举
5. 更新完成定义和漂移控制
执行:
- 更新 `docs/sim-configs-completion-plan.md`
- 更新 `docs/compatibility-validation.md`
- 更新 `docs/source-reuse-map.md`
完成判定:
- `configs/sim` 每个 `.ngc` 都有明确分类;
- 每个类别都有合适层级的验证入口;
- blocked dependency 清单完整;
- Node inventory 可重跑;
- browser class coverage 覆盖所有重要 runtime family
- Layer 2 的 8 个 expected_fail 都有稳定归因;
- 没有通过 project-owned CNC 语义让测试看起来通过。
不做事项:
- 不把 159 个程序全部塞进 browser smoke
- 不把 full-process/HAL/UI/linuxcncrsh 依赖程序误降级为 standalone file execution
- 不修改 `linuxcnc/configs/sim` upstream 文件;
- 不通过 JS 解释逻辑、临时字符串匹配、或 standalone `Interp::...` 新语义实现来换取 PASS。

248
text4.txt Normal file
View File

@@ -0,0 +1,248 @@
HAL/UI/full-process standalone/browser boundary design and next plan
Generated: 2026-06-10 CST
This plan follows `text3.txt`. The `configs/sim` inventory/matrix work is now
complete for the current definition. This file defines the next boundary before
any previously blocked HAL/UI/full-process family is promoted into standalone,
Node, or browser execution.
Goal
- Preserve LinuxCNC as the CNC semantic source of truth.
- Make HAL/UI/full-process dependencies machine-readable before attempting
execution.
- Promote only the subpaths that can run through vendored LinuxCNC source plus
explicit standalone runtime adapters.
- Keep task, HAL process launch, UI driver process launch, linuxcncrsh, Python
remap, and tool-database process behavior blocked until each has a deliberate
LinuxCNC-owned runtime boundary.
Non-goals
- Do not implement HAL, task, linuxcncrsh, GUI, Python remap, or tool-database
semantics in JavaScript.
- Do not make blocked `configs/sim` programs pass by editing upstream G-code,
changing SDK behavior, or adding project-owned interpreter semantics.
- Do not treat native LinuxCNC GUI code as implementation code for the browser
UI.
Current implementation added by this batch
1. SDK runtime-boundary classifier
Added:
```text
wasm-port/runtime/sdk/src/sim-config-staging.js
analyzeIniRuntimeBoundaries()
```
Exported through:
```text
wasm-port/runtime/sdk/src/index.js
```
The classifier reads INI text, manifest text, source-root metadata, and
optional execution text. It reports:
- declared `HAL` process inputs: `HALFILE`, `HALCMD`, `POSTGUI_HALFILE`,
`HALUI`;
- declared UI process inputs: `DISPLAY`, `PYVCP`, `GLADEVCP`,
`EMBED_TAB_COMMAND`;
- `HALUI` MDI command dependencies;
- `[EMCIO]DB_PROGRAM` tool-database process dependencies;
- Python references in UI, DB, `[PYTHON]`, or Python remap declarations;
- `[RS274NGC]USER_M_PATH` plus whether the current execution text calls
unstaged external `M100..M199` process codes.
It returns a policy recommendation for hard Layer 4 blocks:
- `L4-TOOL-DB` when `[EMCIO]DB_PROGRAM` is present;
- `L4-USER-M-PROCESS` when the current execution chain calls unstaged
external user-M process codes;
- `L4-PYTHON-REMAP` for Python remap runtime declarations;
- `-` when the dependency is only a declared process dependency already
represented by a narrower standalone adapter or class representative.
This is policy/accounting only. It does not execute or emulate HAL, task,
UI, Python, user-M, or tool-database behavior.
2. Node coverage for the classifier
Updated:
```text
wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs
```
Covered cases:
- synthetic INI with vendored `M123` user-M file remains unblocked;
- `axis/db_demo/db_nonran.ini` reports `L4-TOOL-DB`;
- `axis/vismach/millturn/millturn.ini` plus its remap execution chain
reports `L4-USER-M-PROCESS` because `M428/M429` call unstaged `M128/M129`;
- `axis/vismach/puma/puma_cube.ini` declares HAL/UI/HALUI process
dependencies but remains unblocked for the current representative program
because the promoted execution path does not call unstaged external
user-M process codes;
- `axis/gladevcp/gladevcp_panel.ini` declares UI/Python UI process
dependencies but remains unblocked for the current `probe.ngc`
representative.
3. Inventory policy guard
Updated:
```text
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs
```
The Node inventory now checks vendored INI rows against
`analyzeIniRuntimeBoundaries()` before execution/skipping:
- `L4-TOOL-DB` rows must declare `DB_PROGRAM`;
- `L4-USER-M-PROCESS` rows must be backed by an execution chain that calls
unstaged external user-M process codes;
- generated/tracked blocked policy drift fails the inventory.
Boundary model
Layer A: declaration classification
- Input: INI text, manifest text, optional execution text.
- Output: dependency list and recommended blocked kind.
- Owner: SDK host-boundary code.
- Validation: Node unit/smoke assertions and Node inventory policy checks.
Layer B: standalone adapter execution
- Allowed only when a narrow runtime edge already exists and CNC behavior still
comes from vendored LinuxCNC source.
- Current examples:
- HAL named-parameter lookup and switchkins M68/M66 synchronization through
the standalone HAL adapter;
- deterministic `USER_M_COMMAND` canonical events for already vendored
M110/M111-style user-M registration;
- five-axis remap execution through vendored LinuxCNC remap/O-word paths;
- OPFS/file/parameter/tool-table persistence as host storage boundaries.
Layer C: browser/UI representation
- Browser UI may present standalone simulation state and user controls.
- Browser UI must not execute native LinuxCNC GUI code.
- Browser UI must call SDK/WASM boundaries that are already validated in Node
or native probes.
- Full LinuxCNC GUI actions remain blocked unless expressed as a deliberate
standalone command boundary with LinuxCNC-owned behavior underneath.
Layer D: full-process blocked boundary
Keep blocked until explicitly designed:
- LinuxCNC task process lifecycle;
- HAL process/module loading and realtime scheduling;
- HALUI/linuxcncrsh command queues;
- external userspace components;
- native GUI driver processes;
- Python remap/prolog/epilog runtime;
- tool database process startup and protocol/state behavior.
Immediate next implementation batches
Batch 1: make boundary reports durable
- Add a generated machine-readable boundary artifact:
```text
wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv
```
- Minimum fields:
```text
path
ini
blocked
recommended_blocked
dependencies
user_m_execution_codes
user_m_vendored_count
db_program
hal_process
ui_process
halui_mdi_process
python_process
```
- The existing Node inventory should fail if `blocked` and
`recommended_blocked` conflict for hard blocks.
Batch 2: promote only safe HAL/UI representatives
- Keep `axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`,
`axis/vismach/puma/puma_cube.ngc`, and `axis/vismach/melfa-sim/example.ngc`
as representative file-execution paths.
- Add browser assertions that these programs remain file/remap execution
representatives and do not claim full UI/HAL process coverage.
- Do not promote `axis/vismach/millturn/example.ngc` until the user-M process
boundary is designed, because the remap chain calls M128/M129.
Batch 3: design external user-M process boundary
- Start with `axis/vismach/millturn` because it is the smallest current hard
blocked row with vendored INI and program context.
- Required design questions:
- Which LinuxCNC source owns M128/M129 behavior in the native config?
- Is the behavior expressible as a LinuxCNC-owned deterministic adapter
boundary, or does it require spawning external process scripts?
- What canonical/state output proves behavior without adding JS CNC
semantics?
- Do not mark `millturn` unblocked until native, Node, and browser checks can
prove the boundary.
Batch 4: design tool DB boundary
- Start with `axis/db_demo/db_nonran.ini`.
- Required design questions:
- Which LinuxCNC source owns `DB_PROGRAM` startup/protocol semantics?
- Can a standalone tool database adapter call vendored LinuxCNC tooldata
source without reimplementing database behavior?
- What fixture demonstrates tool lookup/update behavior across native and
WASM?
- Keep `axis/db_demo/base.ngc` as `L4-TOOL-DB` until this exists.
Batch 5: Python remap/full-process family plan
- Do not vendor or execute `gmoccapy`, `axis/laser`, or TWP nutating Layer 4
paths until Python remap runtime ownership is designed.
- First artifact should be a dependency inventory, not execution:
- Python modules referenced by INI/remap;
- prolog/epilog functions;
- HAL/task/UI assumptions;
- NGC-only subpaths, if any, that can be separated safely.
Validation gates
Run after each batch:
```bash
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tools/verify_no_standalone_cnc_semantics.sh
```
Completion criteria for this boundary phase
- Every vendored sim-config INI used by Node inventory has a machine-readable
runtime-boundary report.
- Hard blocked rows have a dependency-backed reason rather than path-only
classification.
- Safe representatives can declare HAL/UI process dependencies without being
mislabeled as full-process coverage.
- No blocked family is promoted until a LinuxCNC-owned runtime boundary exists
and is validated native, Node, and browser where appropriate.

View File

@@ -36,6 +36,12 @@ The current WASM sim-config smoke validation command is:
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
```
The current WASM sim-config inventory validation command is:
```bash
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
```
The current WASM `nc_files` smoke validation command is:
```bash
@@ -92,6 +98,7 @@ running the aggregate host check:
wasm-port/tests/wasm/node/verify_ini_wasm.sh
wasm-port/tests/wasm/node/verify_interp_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
wasm-port/tests/wasm/node/verify_nc_files_wasm.sh
wasm-port/tests/wasm/node/verify_tp_wasm.sh
wasm-port/tests/opfs/node/verify_file_service.sh
@@ -122,7 +129,278 @@ Layer responsibilities are intentionally narrow:
The current `wasm-port/tests/native/verify_sim_configs.sh` run reports
`total: 159`, `pass: 151`, `expected_fail: 8`, and `unexpected_fail: 0`.
The eight expected failures are:
The eight expected failures are listed in the table below.
The tracked per-program inventory for this layer now lives in
`wasm-port/docs/sim-configs-coverage-matrix.md`. That matrix maps all 159
current `summary.tsv` records to program class, native result, current
Layer 3/4 coverage, and the first-pass blocked or follow-up note used for
future `configs/sim` coverage work.
The native harness also emits machine-readable derived artifacts without
changing the `summary.tsv` schema:
```text
wasm-port/build/native/sim-configs/class-summary.tsv
wasm-port/build/native/sim-configs/path-matrix.tsv
```
`class-summary.tsv` aggregates class/status/expected-failure counts.
`path-matrix.tsv` records each path, class, native status, expected-failure
reason, INI, tool table, runtime family, and blocked kind for CI and Node
inventory reconciliation.
The Node inventory layer writes its own machine-readable artifacts:
```text
wasm-port/build/wasm/sim-configs-inventory/summary.tsv
wasm-port/build/wasm/sim-configs-inventory/skip-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/user-m-process-state-targets.tsv
wasm-port/build/wasm/sim-configs-inventory/user-m-process-native-state-alignment.tsv
wasm-port/build/wasm/sim-configs-inventory/tool-db-process-protocol-gates.tsv
wasm-port/build/wasm/sim-configs-inventory/tool-db-process-native-protocol-alignment.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-runtime-gates.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-alignment.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-readiness.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-state-plan.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-fixture-plan.tsv
wasm-port/build/wasm/sim-configs-inventory/python-remap-family-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/boundary-phase-completion-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/native-proof-alignment-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-native-alignment-summary.tsv
wasm-port/build/wasm/sim-configs-inventory/blocked-runtime-promotion-lock.tsv
wasm-port/build/wasm/sim-configs-inventory/next-boundary-worklist.tsv
wasm-port/build/wasm/sim-configs-inventory/boundary-proof-gates.tsv
```
The current skip/block summary is `ASSET-ONLY=65`, `L4-PYTHON-REMAP=53`,
`L4-TOOL-DB=1`, `L4-USER-M-PROCESS=1`, `NON_MAIN_CLASS=10`, and
`UPSTREAM-DEMO=1`.
`skip-summary.tsv` is checked against the skip reasons derived from
`path-matrix.tsv`, so both the per-row inventory status and the aggregate
skip counts fail on blocked-policy drift.
For eligible rows, missing vendored machine context is an inventory failure,
not an expected skip; blocked rows must be classified by runtime dependency
before the Node inventory filter runs.
`boundary-summary.tsv` records one row per native inventory path with the
matrix blocked kind, SDK classifier recommendation, declared HAL/UI/HALUI/Python
process dependencies, `[EMCIO]DB_PROGRAM`, user-M execution codes, and the
subset of execution user-M codes that are not staged by vendored
`USER_M_PATH` files. It also separates Python UI/DB process dependencies from
Python remap runtime dependencies. For vendored INI rows, the SDK classifier
report must be available and `L4-TOOL-DB` / `L4-USER-M-PROCESS` hard blocks
must match the classifier recommendation. `recommended_blocked=UNAVAILABLE` is
only allowed when the boundary row records a missing vendored INI. Non-vendored
Python-remap families remain unavailable until their dependency inventory batch
vendors the required INI context.
`ini-boundary-summary.tsv` aggregates those path-level reports by INI, giving
vendored sim-config INIs a direct `report_available=1` coverage check and
recording hard-block recommendation alignment at INI granularity.
The inventory also guards safe representative rows such as
`axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`,
`axis/vismach/puma/puma_cube.ngc`, and
`axis/vismach/melfa-sim/example.ngc`: they must keep their declared process
dependencies in `boundary-summary.tsv`, remain Node/browser representatives,
match the expected HAL/UI/HALUI/Python process flags, and avoid hard-block
promotion unless a real hard runtime dependency appears.
Deterministic `M110`/`M111` representatives are also guarded: the inventory
must see the execution-chain user-M code, a vendored user-M file, and no hard
`L4-USER-M-PROCESS` recommendation. `opa_demo.ngc` includes its vendored
`circles.ngc` subroutine text in the boundary analysis so the `M111` call is
accounted for even though it is reached through `SUBROUTINE_PATH`.
`blocked-dependency-summary.tsv` records the hard blocked rows without
promoting them: 53 Python-remap rows, one tool-database row, and one external
user-M process row. It reads the source `linuxcnc/configs/sim` INI files for
dependency accounting only and records Python modules, remap/prolog/epilog
function ownership, NGC remap subpaths, HAL/UI/HALUI process declarations,
`DB_PROGRAM`, tool database protocol evidence, external user-M execution
codes, user-M process script files, user-M process side-effect evidence, and
the LinuxCNC source/config files that own the blocked behavior. The user-M
evidence is source-derived from the `M128`/`M129` Tcl scripts and records their
Tcl/HAL runtime use, kinstype guard, and `ini.[xyz]` HAL pin updates. The tool
database evidence is source-derived from `taskclass.cc`, `tooldata_db.cc`, and
`axis/db_demo/db.py`, including the `v2.1` handshake, `g`/`FINI` get-all, and
`l`/`u`/`p` notification protocol.
The final Node inventory `summary.tsv` also guards every hard-blocked row:
`L4-TOOL-DB`, `L4-USER-M-PROCESS`, and `L4-PYTHON-REMAP` paths must remain
`SKIP` with their matching blocked reason, not only carry a matrix-level
blocked label.
The detailed boundary design for the current non-Python hard blocks is tracked
in `wasm-port/docs/full-process-boundary-design.md`. That document records the
LinuxCNC owner sets and proof required before `axis/vismach/millturn/example.ngc`
or `axis/db_demo/base.ngc` can move out of `L4-USER-M-PROCESS` or
`L4-TOOL-DB`. It is not an execution artifact and does not change the current
Layer 4 blocked counts.
`full-process-boundary-summary.tsv` is the machine-readable companion for that
design record. It has one designed-but-blocked row for `millturn` and one for
`db_demo`, records the LinuxCNC runtime owner evidence from the corresponding
blocked dependency row, records the required native/Node/browser proof, and
keeps `execution_enabled=0` until the corresponding LinuxCNC-owned runtime
boundary exists. The tracked matrix and inventory guard also require those two
rows to remain non-representative in Node/browser until that proof exists.
`user-m-process-state-targets.tsv` expands the `millturn` M128/M129 process
boundary into per-pin proof targets: two user-M codes, three axes, and four
`ini.[xyz]` HAL pins per axis. Each row records the source Tcl file, remap
caller, kinstype guard, INI source section/field, expected value,
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-native-state-alignment.tsv` then aligns each generated pin
target with the native source probe stdout key/value pair, for example
`M128_X_AXIS_X.MIN_LIMIT_ok=1`. This catches drift between generated target
rows and the LinuxCNC-owned native source proof without executing Tcl/HAL or
allowing promotion.
`user-m-process-native-transition-alignment.tsv` performs the same source
alignment for the `M428/M429` transition plan. It checks the native probe
stdout for `motion.analog-out-03`, kinstype targets `0` and `1`,
`G59.1`/`G59.2`, `P7`/`P8`, and the `M428 -> M128` / `M429 -> M129` calls.
Those rows also remain `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`.
`user-m-process-native-runtime-state-plan.tsv` is the runnable native probe
contract that follows those source-alignment tables. It names the required
LinuxCNC task/HAL/Tcl user-M process runtime, the required HAL/INI
environment, and the exact `ini.[xyz].*` state values that a future native
runtime probe must record after `M428` and `M429`. It remains a plan only with
`native_runtime_status=pending_native_hal_tcl_process_probe`,
`execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-native-runtime-readiness.tsv` is the host capability gate for
that future probe. It records availability of `tclsh`, `halrun`, `halcmd`, and
`linuxcnc`, captures PATH evidence for available commands, and leaves
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-native-runtime-probe-gate.tsv` combines that readiness with the
source/state proof for `M428/M128` and `M429/M129`. The native
`probe_millturn_user_m_runtime.sh` entry point is wired through
`build_native_probes.sh`; without the full LinuxCNC HAL/Tcl command set it
reports `skipped_missing_host_runtime`, and with the runtime present it remains
disabled by default. When explicitly enabled with
`ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1`, it starts the vendored `millturn.ini`,
runs the LinuxCNC-owned Tcl `M128`/`M129` scripts, verifies the expected
`ini.[xyz].*` HAL pin state, and reports `runtime_state_probe_passed` without
enabling promotion.
`tool-db-process-protocol-gates.tsv` expands the `db_demo` tool-database
boundary into pending protocol, callback, and state gates. It records the
LinuxCNC `v2.1`, `g`, `l`, `u`, and `p` protocol requirements, the demo DB
callbacks, DB mode state targets such as ignored `TOOL_TABLE`, `T10..T19`,
`tno+100` pockets, and OPFS/host persistence boundaries, while keeping
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`tool-db-process-native-protocol-alignment.tsv` aligns each generated DB gate
with the native source probe stdout proof keys, including the protocol
handshake, get-all, notifications, callback registration, and nonrandom state
targets. This is still dependency/proof accounting only: it does not spawn
`DB_PROGRAM`, emulate the tool database protocol in JavaScript, or fall back to
a `.tbl` file.
`tool-db-process-native-runtime-readiness.tsv` records the host prerequisites
for the guarded DB process protocol probe: `python3`, `linuxcnc`, `milltask`,
`halcmd`, the configured `db_nonran.py` executable, and LinuxCNC's Python
`linuxcnc.so` / `tooldb.py` modules. It captures availability evidence while
keeping `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`. When explicitly enabled with
`ENABLE_TOOL_DB_RUNTIME_PROBE=1`, `probe_tool_db_runtime.sh` starts the
vendored `DB_PROGRAM`, drives the LinuxCNC `tooldb.py` `v2.1`/`g`/`p`/`l`/`u`
protocol, verifies nonrandom startup/update/load/unload state and persistence,
and reports `runtime_protocol_probe_passed` without enabling promotion.
`python-remap-boundary-summary.tsv` is the machine-readable companion for the
Python remap inventory batch. It has one inventory-only row for each
`L4-PYTHON-REMAP` path, records Python modules, remap/prolog/epilog functions,
NGC-only subpaths, HAL/UI/HALUI assumptions, LinuxCNC Python runtime owner
evidence from `interp_python.cc` and `python_plugin.cc`, and keeps
`execution_enabled=0` until a LinuxCNC-owned Python runtime boundary exists.
`python-remap-runtime-gates.tsv` expands those rows into Python module,
remap/prolog/epilog callable, NGC-only subpath, process-assumption, and
runtime-owner gates, all with `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
`python-remap-native-runtime-alignment.tsv` aligns every generated Python gate
with native source proof: exact runtime owner gates use keys such as
`python_runtime_pycall_dispatch`, while dependency gates use representative
family inventory proof or the aggregate
`python_remap_native_source_inventory_proof`. It does not initialize Python,
import modules, execute callbacks, or promote browser/Node coverage.
`python-remap-native-runtime-readiness.tsv` records the native runtime
prerequisites for guarded probes by family: `python3`, `linuxcnc`,
LinuxCNC's `interp_python.cc` / `python_plugin.cc` owner source files, and the
configured Python modules. It is a readiness gate only and keeps every row
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`python-remap-native-runtime-state-plan.tsv` records the next native runtime
probe target set by family: LinuxCNC Python phases, configured modules,
callables, NGC-only subpaths, process assumptions, readiness counts, and
source-alignment artifacts. It remains a plan only and does not initialize
Python, import modules, execute callbacks, or permit promotion.
`python-remap-native-runtime-fixture-plan.tsv` selects the first minimal
Python runtime lifecycle fixture, `axis/remap/stop-lookahead/nc_files`, because
it exercises Python runtime phases and configured modules without Python
callable or NGC-only subpath complexity. It is still a fixture plan only:
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
When explicitly enabled with `ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1`,
`probe_python_remap_runtime.sh` follows the fixture `demo.ini` Python path and
toplevel declarations, imports the vendored modules, verifies `queuebuster`
callable lookup, generator return, and first `INTERP_EXECUTE_FINISH` yield, and
reports `runtime_lifecycle_probe_passed` without promoting Python-remap
execution.
`python-remap-family-summary.tsv` aggregates the same blocked rows by runtime
family, preserving row and INI counts plus family-level Python module,
remap/prolog/epilog, NGC-only subpath, Python runtime owner evidence,
HAL/UI/HALUI, and `execution_enabled=0` evidence. It is dependency inventory
only and must not be used to promote Python-remap execution.
`boundary-phase-completion-summary.tsv` records the current boundary-phase
completion criteria as machine-readable checks: vendored INI boundary report
coverage, hard-block dependency evidence, safe HAL/UI representative coverage,
proof that blocked families remain skipped/non-representative with execution
disabled, and proof that blocked runtime families carry LinuxCNC-owned user-M,
tool DB, and Python runtime evidence fields. It also records native source
proof alignment when the native proof summary is available, plus the aggregate
native stdout alignment summary for user-M, tool DB, and Python runtime gates.
`native-proof-alignment-summary.tsv` aligns native source proof rows with the
generated worklist and native proof gates for user-M, tool DB, and Python
runtime blockers. It is proof-consumption accounting only and keeps execution
and promotion disabled.
`runtime-boundary-native-alignment-summary.tsv` summarizes the three detailed
native alignment artifacts. It requires every alignment row to have native
stdout evidence, `alignment_ok=1`, `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
`blocked-runtime-promotion-lock.tsv` combines the next-boundary worklist,
native/Node/browser proof gates, and runtime native alignment summary into one
promotion lock per blocked runtime target. A lock row is active only while
every proof layer is still pending, execution and promotion remain disabled,
and the matching runtime alignment artifact is complete.
`next-boundary-worklist.tsv` records the next blocked runtime-boundary design
targets in priority order. It starts with the designed-but-disabled
`millturn` external user-M process and `db_demo` tool database process
boundaries, then lists Python runtime families from the inventory. Every row
keeps `execution_enabled=0` and `promotion_allowed=0`, records the LinuxCNC
owner set and runtime owner evidence, records required native, Node, and
browser proof, and names the next boundary-design action before promotion.
`boundary-proof-gates.tsv` expands that worklist into one pending native,
Node, and browser proof gate per target. It is a promotion guard only: current
rows keep `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`; user-M gates must require HAL pin state rather than
event-only proof, tool-DB gates must require protocol proof rather than a
`.tbl` fallback, and Python gates must require a LinuxCNC-owned Python runtime
boundary rather than JavaScript semantics.
The browser interpreter smoke reads the browser-layer rows from this artifact
before running safe representatives, so `millturn`, `db_demo`, and Python
runtime families cannot be accidentally treated as browser/full-process
coverage while their proof gates remain pending.
Current `configs/sim` class taxonomy:
| Class | Meaning | Current policy |
| --- | --- | --- |
| `main` | A complete standalone-executable sim-config program. | Eligible for native inventory; promote to Layer 3/4 when the required runtime boundary exists. |
| `macro_load` | A macro or load/parse asset that is not the primary machine program entry point. | Keep in native inventory, but do not treat it as a browser main-program target by default. Add class-level load/parse representatives instead of widening browser execution blindly. |
| `remap_subroutine` | A remap or subroutine asset under `remap_subs/` or similar directories. | Validate through remap parse/execute paths, not by pretending it is a standalone browser main program. |
Current `configs/sim` blocked policy:
| Blocked kind | Meaning | Current examples |
| --- | --- | --- |
| `ASSET-ONLY` | The file is a macro/remap asset or subroutine and is not a standalone browser main-program target. | `configs/sim/*/remap_subs/*.ngc` entries in the matrix. |
| `L4-TOOL-DB` | Native LinuxCNC `rs274` coverage exists, but Node/browser inventory is blocked by LinuxCNC tool-database process boundaries such as `[EMCIO]DB_PROGRAM`. | `configs/sim/axis/db_demo/*`. |
| `L4-USER-M-PROCESS` | Native LinuxCNC `rs274` coverage exists, but Node/browser inventory is blocked because the config depends on external `USER_M_PATH` process execution rather than the deterministic `M110`/`M111` boundary already modeled by the standalone runtime. | `configs/sim/axis/vismach/millturn/*`. |
| `L4-PYTHON-REMAP` | Native LinuxCNC `rs274` coverage exists, but full Node/browser inventory is blocked until an intentional Python-remap runtime boundary is exposed for Layer 4. | `configs/sim/gmoccapy/*`, `configs/sim/axis/laser/*`, `configs/sim/axis/remap/*/nc_files/*.ngc`, `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*`, and `configs/sim/axis/vismach/VMC_toolchange/toolchange.ngc`. |
| `UPSTREAM-DEMO` | A preserved upstream demo edge that should remain an expected failure instead of being forced through standalone semantics. | `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc`. |
| Program | Layer 2 classification | Current Layer 3/4 coverage or boundary |
| --- | --- | --- |
@@ -499,14 +777,15 @@ The validation fails if:
| Harness | Purpose |
| --- | --- |
| `tests/wasm/node/verify_ini_wasm.sh` | Validates the browser-facing INI WASM module can be built from vendored LinuxCNC `inifile.cc`, loaded through the JS SDK in Node, and queried through the exported C ABI, including LinuxCNC-backed boolean conversion and machine-session file-name string lookup. |
| `tests/wasm/node/verify_interp_wasm.sh` | Validates the interpreter-core WASM module can be built from vendored LinuxCNC interpreter/remap source, loaded through the interpreter JS SDK, run the first fixture group through `Interp::execute()` and selected file fixtures plus vendored upstream `tests/interp` regression files through `Interp::open()`/`read()`/`execute()`, match the native canonical event plus required state readback fixtures, emit `run_step` execution-status records with LinuxCNC line number, encoded source statement, return code, and interpreter axis positions for file execution, cover vendored `tests/interp/flowsnake` recursive O-word file execution, `tests/interp/g6164` path-control and naive-cam tolerance execution, `tests/interp/oword-unwind` continue-on-error stack unwind behavior through planner-staged INI context, selected `tests/interp/bad` file-error paths, and `tests/interp/g33.1` rigid-tap file execution, run vendored `xyzac-trt`/`xyzbc-trt` switchkins remap demo files through the WASM C ABI/SDK path, and run parameter-file restore/save through vendored LinuxCNC `Interp::restore_parameters()` and `Interp::save_parameters()`. |
| `tests/wasm/node/verify_sim_configs_wasm.sh` | Validates representative vendored LinuxCNC `configs/sim` programs in Node WASM through `planSimConfigStaging()` plus `runSimConfigProgram()`. The generic `planIniFileContextStaging()` planner and its sim-config wrapper use INI text and `tools/source-manifest.txt` to collect the program, INI, tool table, parameter file when vendored, `SUBROUTINE_PATH` files, `USER_M_PATH` files, and remap-NGC files before forwarding to `runFileWithIni()` or `runFiveAxisRemapFile()`. This covers INI-driven `U/V/W` axis mask handling, real `USER_M_PATH` registration for executable `M110`/`M111`, all four current external-offset M111 expected-failure programs, `SUBROUTINE_PATH` staging for `opa_demo.ngc -> circles.ngc`, bridge-mill remap-subroutine staging, and vendored LinuxCNC bridge-mill NGC remap execution without spawning host processes. The same smoke includes synthetic staging-plan assertions for generic `TOOL_TABLE`, `PARAMETER_FILE`, multi-directory `SUBROUTINE_PATH`, `USER_M_PATH`, and `REMAP ... ngc=...` file collection. |
| `tests/wasm/node/verify_interp_wasm.sh` | Validates the interpreter-core WASM module can be built from vendored LinuxCNC interpreter/remap source, loaded through the interpreter JS SDK, run the first fixture group through `Interp::execute()` and selected file fixtures plus vendored upstream `tests/interp` regression files through `Interp::open()`/`read()`/`execute()`, match the native canonical event plus required state readback fixtures, emit `run_step` execution-status records with LinuxCNC line number, encoded source statement, return code, and interpreter axis positions for file execution, cover vendored `tests/interp/flowsnake` recursive O-word file execution, `tests/interp/g6164` path-control and naive-cam tolerance execution, `tests/interp/oword-unwind` continue-on-error stack unwind behavior through planner-staged INI context, selected `tests/interp/bad` file-error paths, and `tests/interp/g33.1` rigid-tap file execution, run vendored `xyzac-trt`/`xyzbc-trt` table-rotary-tilting and `xyzab-tdr` table-dual-rotary switchkins remap demo files through the WASM C ABI/SDK path, and run parameter-file restore/save through vendored LinuxCNC `Interp::restore_parameters()` and `Interp::save_parameters()`. |
| `tests/wasm/node/verify_sim_configs_wasm.sh` | Validates representative vendored LinuxCNC `configs/sim` programs in Node WASM through `planSimConfigStaging()` plus `runSimConfigProgram()`. The generic `planIniFileContextStaging()` planner and its sim-config wrapper use INI text and `tools/source-manifest.txt` to collect the program, INI, tool table, parameter file when vendored, `SUBROUTINE_PATH` files, `USER_M_PATH` files, and remap-NGC files before forwarding to `runFileWithIni()` or `runFiveAxisRemapFile()`. This covers INI-driven `U/V/W` axis mask handling, real `USER_M_PATH` registration for executable `M110`/`M111`, all four current external-offset M111 expected-failure programs, deterministic `woodpecker/on_abort.ngc` file execution, plain INI/tool-table execution through `axis/gladevcp/probe.ngc`, `SUBROUTINE_PATH` staging for `opa_demo.ngc -> circles.ngc`, bridge-mill remap-subroutine staging, vendored LinuxCNC bridge-mill and `melfa-sim` NGC remap execution, and PUMA machine-context execution without spawning host processes. The same smoke includes synthetic staging-plan assertions for generic `TOOL_TABLE`, `PARAMETER_FILE`, multi-directory `SUBROUTINE_PATH`, `USER_M_PATH`, and `REMAP ... ngc=...` file collection. |
| `tests/wasm/node/verify_sim_configs_inventory_wasm.sh` | Validates the first machine-readable Node inventory layer for `configs/sim`. It ensures native `build/native/sim-configs/summary.tsv`, generated `class-summary.tsv`, and generated `path-matrix.tsv` exist; verifies that generated `path-matrix.tsv` and tracked `docs/sim-configs-coverage-matrix.md` contain the same 159 paths as native `summary.tsv`; checks tracked matrix fields for class, native status, expected-failure reason, and blocked kind drift against generated `path-matrix.tsv`; and checks that generated `class-summary.tsv` matches class/status/expected-failure counts derived from `summary.tsv`. It then executes only entries that are currently vendored and have a defined standalone/WASM runtime path, and writes the sim-config inventory TSV artifacts. The boundary summary records one row per native inventory path with the matrix block, SDK classifier recommendation, declared HAL/UI/HALUI/Python process dependencies, `[EMCIO]DB_PROGRAM`, and execution-chain user-M codes; vendored INI rows must have an available classifier report, vendored hard blocks fail on classifier/matrix drift, safe process-declaring representatives must remain Node/browser `REP` rows with the expected process flag combinations rather than full-process promotions, and the designed full-process blocked rows must remain non-`REP` until their proof criteria are met. The generated inventory summary also requires all hard-blocked rows to remain `SKIP` with matching reasons, and `skip-summary.tsv` must match the matrix-derived skip counts. The blocked-dependency and boundary summaries record hard blocked Python-remap, tool-database, and external user-M rows from source `linuxcnc/configs/sim` INI files for dependency accounting only, including LinuxCNC source/config ownership fields, user-M script side effects, tool DB protocol evidence, Python runtime owner evidence, and completion criteria that all remain non-executing. Current gate: `executed=28`, `passed=28`, `skipped=131`, `unexpected_fail=0`; current skip/block counts are `ASSET_ONLY=65`, `L4_PYTHON_REMAP=53`, `L4_TOOL_DB=1`, `L4_USER_M_PROCESS=1`, `NON_MAIN_CLASS=10`, and `UPSTREAM_DEMO=1`. The executed set now includes the deterministic `woodpecker` plus `qtdragon` / `qtdragon_hd` / `qtvcp_screens` `on_abort.ngc` family, `axis/gladevcp/probe.ngc`, `axis/rose_engine/rcone_demo.ngc`, `axis/vismach/melfa-sim/example.ngc`, and the `axis/vismach/puma` sample programs after vendoring the required machine INI, tool-table, and remap-subroutine inputs. When an upstream INI declares a missing local tool table but the native harness resolved a valid fallback table, the Node inventory stages that native-selected table at the INI-declared path so WASM execution uses the same machine context. The skip reasons are explicit: `NON_MAIN_CLASS`, `L4-TOOL-DB`, `L4-USER-M-PROCESS`, `L4-PYTHON-REMAP`, and `UPSTREAM-DEMO`; an eligible row that lacks vendored machine context is reported as an inventory failure. This runner is an inventory source-of-truth for Node WASM and is intentionally narrower than a browser full inventory. |
| `tests/wasm/node/verify_nc_files_wasm.sh` | Validates representative vendored LinuxCNC `nc_files` examples in Node WASM by copying `3D_Chips.ngc`, `arcspiral.ngc`, `hole-circle.ngc`, `factorial.ngc`, and `m6demo.ngc` into the Emscripten filesystem and forwarding to the LinuxCNC-backed `Interp::open()`/`read()`/`execute()` path. `3D_Chips.ngc` is staged with a minimal INI-declared `tool.tbl` because the upstream program contains `T1 M6`; JavaScript only stages files and checks LinuxCNC output, including `run_step` status records, and does not implement G-code, O-word, tool-change, or M-code behavior. |
| `tests/wasm/node/verify_tp_wasm.sh` | Validates a standalone trajectory-planner WASM module can be built from vendored LinuxCNC TP/TC/Ruckig support source, loaded in Node, and run the same linear, arc, and queued-line planner probe paths covered by the native TP harness. |
| `tests/opfs/node/verify_file_service.sh` | Validates the host-owned OPFS text-file adapter, path model, session snapshot store including custom filenames and envelope/path rejection paths, machine file store, G-code text store including filename rejection paths, OPFS-to-WASM parameter/tool-table bridges, and grouped machine-session loading without moving file persistence, parameter semantics, or tool-table semantics into the WASM core. |
| `tests/browser/verify_ini_panel_browser.sh` | Validates the INI SDK, INI/interpreter WASM module loading, LinuxCNC-backed INI machine-session file-name string lookup, OPFS text-file round trip, generic session snapshot round trip plus custom filename and envelope/path rejection paths, machine file text round trip, G-code text round trip plus filename rejection paths, and the INI panel UI's machine-session load with default OPFS parameter/tool-table file mapping, G-code run, `run_step`-backed progress/line/statement/axis display, canonical-event display paths, and 5-axis remap demo action in a real browser runtime. |
| `tests/browser/verify_interp_browser.sh` | Validates the interpreter-core WASM module loads through the interpreter JS SDK in a real browser runtime and runs selected positive and negative canonical fixtures plus vendored upstream `tests/interp` regression files through vendored LinuxCNC `Interp::execute()` and `Interp::open()`/`read()`/`execute()` via the exported C ABI, including direct browser SDK and OPFS-backed parameter-file restore/save, non-random/random tool-table load/save through vendored LinuxCNC source, vendored `xyzac-trt`/`xyzbc-trt` switchkins remap demo execution, representative vendored `configs/sim` `foam`, `geometry`, `external_offsets`, and bridge-mill programs through `runSimConfigProgram()`, representative vendored `nc_files` examples through `runFile()` or `runFileWithIni()` when the upstream file requires INI/tool-table context, and a synthetic browser assertion that `planIniFileContextStaging()` can collect INI, program, tool-table, parameter, multi-directory subroutine, executable user-M, and remap-NGC files using only manifest text. |
| `tests/host/verify_host_smokes.sh` | Runs the current host-side Node, WASM interpreter-core, WASM trajectory-planner, OPFS, and browser smoke validation with shared WASM builds. |
| `tests/browser/verify_interp_browser.sh` | Validates the interpreter-core WASM module loads through the interpreter JS SDK in a real browser runtime and runs selected positive and negative canonical fixtures plus vendored upstream `tests/interp` regression files through vendored LinuxCNC `Interp::execute()` and `Interp::open()`/`read()`/`execute()` via the exported C ABI, including direct browser SDK and OPFS-backed parameter-file restore/save, non-random/random tool-table load/save through vendored LinuxCNC source, vendored `xyzac-trt`/`xyzbc-trt` table-rotary-tilting and `xyzab-tdr` table-dual-rotary switchkins remap demo execution, representative vendored `configs/sim` `foam`, `geometry`, `external_offsets`, `axis/gladevcp/probe.ngc`, deterministic `woodpecker/on_abort.ngc`, bridge-mill, `melfa-sim`, and `puma_cube.ngc` programs through `runSimConfigProgram()`, representative vendored `nc_files` examples through `runFile()` or `runFileWithIni()` when the upstream file requires INI/tool-table context, and a synthetic browser assertion that `planIniFileContextStaging()` can collect INI, program, tool-table, parameter, multi-directory subroutine, executable user-M, and remap-NGC files using only manifest text. |
| `tests/host/verify_host_smokes.sh` | Runs the current host-side Node, WASM interpreter-core, sim-config representative smoke, sim-config Node inventory, WASM trajectory-planner, OPFS, and browser smoke validation with shared WASM builds. |
## Fixture Coverage

View File

@@ -0,0 +1,513 @@
# Full-Process Runtime Boundary Design
Generated: 2026-06-10 CST
This document records the first design pass for `configs/sim` rows that are
already classified by the Node inventory, but must remain blocked until a
LinuxCNC-owned runtime boundary exists. It is a design and accounting artifact,
not an execution path.
## Scope
- `axis/vismach/millturn/example.ngc`, currently `L4-USER-M-PROCESS`.
- `axis/db_demo/base.ngc`, currently `L4-TOOL-DB`.
- Python-remap and broader full-process families remain inventoried in
`build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv`; they are
not promoted here.
## Non-Goals
- Do not implement HAL, task, HALUI, Tcl, Python, tool-database, or external
process semantics in JavaScript.
- Do not make blocked rows pass by editing upstream G-code, Tcl, Python, INI,
or tool-table files.
- Do not treat native GUI code or config helper scripts as browser UI
implementation code.
- Do not mark a row unblocked until native, Node, and browser validation prove
the boundary where that layer is applicable.
## External User-M Process Boundary
### Current Block
`axis/vismach/millturn/example.ngc` is blocked because
`millturn.ini` declares:
- `[RS274NGC]USER_M_PATH = ./mcodes`;
- `REMAP = M428 ... ngc=428remap`;
- `REMAP = M429 ... ngc=429remap`;
- `[HAL]HALUI = halui`, `HALFILE`, `HALCMD`, and `POSTGUI_HALFILE`;
- `[HALUI]MDI_COMMAND = M128` and `M129`;
- `[DISPLAY]PYVCP = millturn.xml`.
The promoted execution chain reaches `remap_subs/428remap.ngc` and
`remap_subs/429remap.ngc`. Those LinuxCNC NGC remaps execute `M68`/`M66`
switchkins synchronization and then call external user-M process codes
`M128` or `M129`.
### LinuxCNC Owner Set
- `configs/sim/axis/vismach/millturn/millturn.ini` owns the machine
declarations and search paths.
- `configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc` and
`429remap.ngc` own the NGC remap call sequence around `M128` and `M129`.
- `configs/sim/axis/vismach/millturn/mcodes/M128` and
`configs/sim/axis/vismach/millturn/mcodes/M129` own the config side effects.
- `src/emc/task/emctask.cc` owns `USER_M_PATH` search, executable detection,
`USER_DEFINED_FUNCTION_ADD()`, and queuing `EMC_SYSTEM_CMD`.
- `src/emc/task/emctaskmain.cc` owns `emcSystemCmd()` process spawning and
completion tracking for queued system commands.
- `src/emc/usr_intf/halui.cc` owns HALUI MDI command queue behavior.
- The HAL runtime owns `hal getp`/`hal setp` state, including the `ini.*`
soft-limit pins used by the scripts.
### Native Behavior To Preserve
`M128` is a Tcl process script that:
- requires the LinuxCNC and HAL Tcl packages;
- calls `emc_init -quick`;
- calls `parse_ini $::env(INI_FILE_NAME)`;
- checks `hal getp kinstype.is-0`;
- writes mill limits from `[AXIS_X]`, `[AXIS_Y]`, and `[AXIS_Z]` into
`ini.x.*`, `ini.y.*`, and `ini.z.*` HAL pins.
`M129` follows the same process path, but checks `kinstype.is-1` and writes the
`MIN_LIMIT_TURN` / `MAX_LIMIT_TURN` values for X, Y, and Z. Both scripts also
restore `MAX_VELOCITY` and `MAX_ACCELERATION`.
The NGC remap files own the surrounding interpreter-visible work:
- set `motion.analog-out-03` through `M68`;
- force synchronization with `M66`;
- set G5x offsets with `G10 L2 P7` or `G10 L2 P8`;
- activate `G59.1` or `G59.2`;
- verify `_hal[motion.switchkins-type]` after the switch.
### Boundary Decision
This is not the same boundary as the existing deterministic `M110`/`M111`
registration adapter. `M110` and `M111` can currently be represented as
deterministic `USER_M_COMMAND` canonical events because the promoted tests only
need the interpreter to accept and queue the user-M command. `M128` and `M129`
must also prove HAL pin state updates that affect soft limits after a
kinematics switch.
The row therefore remains `L4-USER-M-PROCESS`.
### Current Machine-Readable Artifact
`user-m-process-boundary-summary.tsv` records the current designed-but-blocked
state target set for this boundary. It maps `M128` to
`remap_subs/428remap.ngc` and `M129` to `remap_subs/429remap.ngc`, records the
`kinstype.is-0` and `kinstype.is-1` guards, and expands the source-traceable
`ini.[xyz].min_limit`, `ini.[xyz].max_limit`, `ini.[xyz].min_velocity`, and
`ini.[xyz].max_acceleration` target pins from `millturn.ini`.
`user-m-process-state-targets.tsv` is the normalized companion table for that
same evidence. It has one pending proof row per `M128`/`M129` target pin,
including the config script source file, remap caller, mill/turn state mode,
guard pin, source INI section/field, and expected value. The current table has
24 target rows plus a header and keeps `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-transition-plan.tsv` records the next non-executing contract
for this boundary. It binds `M428` to `M128` and `M429` to `M129`, records the
`motion.analog-out-03` switchkins output, target kinstype values `0` and `1`,
the active `G59.1`/`G59.2` work offsets, `P7`/`P8` offset pockets, guard pins,
and the 12 expected `ini.[xyz].*` state outputs for each user-M code. This is
still a pending transition contract only; it does not execute Tcl, start HAL,
or permit standalone/browser promotion.
`user-m-process-native-state-alignment.tsv` aligns those 24 generated target
rows with the native source probe stdout keys, such as
`M128_X_AXIS_X.MIN_LIMIT_ok` and `M129_Z_AXIS_Z.MAX_LIMIT_TURN_ok`. This table
proves the generated pin targets still match the native LinuxCNC source/state
probe output, but it also remains `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-native-transition-alignment.tsv` aligns the two generated
transition-plan rows with native source probe stdout for `M428` and `M429`.
It verifies the source-owned `motion.analog-out-03` switchkins output, target
kinstype values `0` and `1`, active `G59.1`/`G59.2` offsets, `P7`/`P8`
offset pockets, and `M428 -> M128` / `M429 -> M129` process calls. This is
still source-transition alignment only; it does not execute the Tcl user-M
processes, start HAL, or allow promotion.
`user-m-process-native-runtime-state-plan.tsv` is the next native runnable
probe contract. It records the required LinuxCNC task/HAL/Tcl user-M runtime,
the required environment (`INI_FILE_NAME`, `motion.switchkins-type`,
`kinstype.is-0`, `kinstype.is-1`, and `ini.[xyz].*` pins), the two transition
steps, and the exact expected `ini.[xyz].*` values after each user-M process.
It requires the source transition/state alignment artifacts to be complete, but
keeps `native_runtime_status=pending_native_hal_tcl_process_probe`,
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`user-m-process-native-runtime-readiness.tsv` records whether the host has the
runtime commands needed to attempt that native probe. It currently checks
`tclsh`, `halrun`, `halcmd`, and `linuxcnc`, records PATH evidence where a
command exists, and keeps the boundary blocked with `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0` even if the commands become
available.
`user-m-process-native-runtime-probe-gate.tsv` is the generated execution gate
for the future runtime probe. It combines source proof readiness with host
runtime readiness for `M428/M128` and `M429/M129`, records missing runtime
commands, and keeps `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`.
`tests/native/probe_millturn_user_m_runtime.sh` is wired into
`build_native_probes.sh` as `linuxcnc_millturn_user_m_runtime_probe`. On hosts
without `halrun`, `halcmd`, or `linuxcnc`, it exits successfully but reports
`millturn_user_m_runtime_probe_status=skipped_missing_host_runtime`; on a host
with the full LinuxCNC runtime it remains disabled by default. If explicitly
enabled with `ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1`, it starts the vendored
`millturn.ini`, runs the LinuxCNC-owned Tcl `M128`/`M129` scripts, and verifies
the resulting `ini.[xyz].*` HAL state targets before reporting
`runtime_state_probe_passed`.
The artifact keeps `execution_enabled=0` and `promotion_allowed=0`. It is not
a standalone Tcl/HAL executor and does not make `millturn` a Node/browser
representative.
`linuxcnc_millturn_user_m_boundary_probe` is the current native guard for this
evidence. It reads the LinuxCNC source `millturn.ini`, `mcodes/M128`,
`mcodes/M129`, and the `428remap`/`429remap` callers, then verifies the
source-derived guard pins, `M428`/`M429` switchkins transition fields, and
`ini.[xyz].*` target values recorded in the machine-readable tables. This is a
source/state-target and source-transition proof only: it does not execute Tcl,
start HAL, spawn the external user-M process, or permit promotion.
### Candidate Boundary
A valid future boundary would have to be LinuxCNC-owned and state based:
1. Reuse LinuxCNC task user-M search and registration behavior for discovering
`M128` and `M129`.
2. Reuse a LinuxCNC-owned HAL/INI state boundary for the `ini.x.*`,
`ini.y.*`, `ini.z.*`, `kinstype.is-*`, and `motion.switchkins-type` pins.
3. Execute or faithfully host the config-owned side-effect source without
translating it into JavaScript CNC semantics. If the Tcl scripts cannot be
executed in the target layer, the boundary must be narrowed to a documented
LinuxCNC-owned state transition with source-traceable inputs and outputs.
4. Keep browser execution blocked unless the same state transition can be
proven without spawning arbitrary host processes.
### Required Proof Before Promotion
Native proof:
- The existing `linuxcnc_millturn_user_m_boundary_probe` source/state guard
must continue to prove that the pending M128/M129 state targets come from
LinuxCNC config files rather than project-owned behavior.
- A LinuxCNC or standalone-native probe runs the `M428 -> M129 -> M429 -> M128`
relevant switch path and records the `ini.[xyz].min_limit`,
`ini.[xyz].max_limit`, `ini.[xyz].min_velocity`, and
`ini.[xyz].max_acceleration` pin values before and after each user-M call.
- The same probe records the kinstype guard result and the active G5x offset.
Node WASM proof:
- The SDK stages the same INI, remap, and script assets for dependency
accounting.
- The WASM runtime proves the same state output through a LinuxCNC-owned
boundary. A `USER_M_COMMAND` event alone is not sufficient.
Browser proof:
- The browser smoke calls the already validated SDK/WASM boundary.
- The test labels the row as a millturn process-boundary representative only
after the state proof exists. It must not claim full LinuxCNC HAL/task/UI
process coverage.
## Tool Database Boundary
### Current Block
`axis/db_demo/base.ngc` is blocked because `db_nonran.ini` declares:
```text
[EMCIO]
RANDOM_TOOLCHANGER = 0
DB_PROGRAM = ./db_nonran.py
```
The INI explicitly notes that `TOOL_TABLE` is not used with `DB_PROGRAM`.
Standalone interpreter file execution would therefore bypass the tool database
startup, command/reply protocol, and persistent database state.
### LinuxCNC Owner Set
- `configs/sim/axis/db_demo/db_nonran.ini` owns the DB program declaration.
- `configs/sim/axis/db_demo/db.py` owns the demo database behavior.
- `src/emc/task/taskclass.cc` owns reading `[EMCIO]DB_PROGRAM`, enabling DB
mode, calling `tooldata_db_init()`, loading tooldata, and notifying DB state
changes during tool load/unload paths.
- `src/emc/tooldata/tooldata_db.cc` owns child process startup, pipe setup,
version handshake, `g` get-all requests, and `l`/`u`/`p` notifications.
- `src/emc/tooldata/tooldata_common.cc` owns common tooldata storage and DB
refresh behavior.
### Native Behavior To Preserve
`tooldata_db_init()` splits `DB_PROGRAM` into argv, verifies that the program is
executable, forks it, connects stdin/stdout pipes, and waits for the version
reply `v2.1`. `tooldata_db_getall()` sends `g`, resets local tooldata, reads
tool lines until `FINI`, and calls `tooldata_read_entry()` for each line.
`tooldata_db_notify()` sends:
- `l ...` for `SPINDLE_LOAD`;
- `u ...` for `SPINDLE_UNLOAD`;
- `p ...` for `TOOL_OFFSET`.
The demo `db.py` uses LinuxCNC's `tooldb` module with callbacks for:
- `user_get_tool`;
- `user_put_tool`;
- `user_load_spindle_nonran_tc` or `user_load_spindle_ran_tc`;
- `user_unload_spindle_nonran_tc` or `user_unload_spindle_ran_tc`.
It maintains a persistent flat-file database, updates tool usage minutes, and
can call `linuxcnc.command().load_tool_table` to synchronize changes back to
LinuxCNC. Those details are DB process behavior, not interpreter file
execution behavior.
### Boundary Decision
This row remains `L4-TOOL-DB`. A standalone adapter that merely loads a
fallback `.tbl` file would be wrong for this config because DB mode explicitly
replaces the tool table file path.
### Current Machine-Readable Artifact
`tool-db-process-boundary-summary.tsv` records the current designed-but-blocked
protocol and state target set for this boundary. It records `DB_PROGRAM =
./db_nonran.py`, the LinuxCNC tooldata protocol messages `v2.1`, `g`, `l`, `u`,
and `p`, the demo DB callbacks `user_get_tool`, `user_put_tool`,
`user_load_spindle_nonran_tc`, and `user_unload_spindle_nonran_tc`, and the
nonrandom database state targets such as `T10..T19`, `/tmp/db_nonran_file`,
`tno+100` startup pockets, and pocket-0 spindle load/unload behavior.
`tool-db-process-protocol-gates.tsv` is the normalized companion table for
that evidence. It splits the blocked DB boundary into pending protocol-message,
DB-program-callback, and state-target gates, including the `v2.1` startup
reply, `g` get-all through `FINI`, `l`/`u`/`p` notifications, demo callback
registration, ignored `TOOL_TABLE`, startup tools, nonrandom pocket mapping,
and persistence/sync targets. The current table keeps `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
`tool-db-process-transaction-plan.tsv` records the next non-executing contract
for this boundary. It orders the pending DB protocol into startup handshake,
initial get-all, spindle load notify, tool offset notify, and spindle unload
notify steps. Each step binds one LinuxCNC protocol message to the expected
`db.py` callback, required native/Node/browser proof, and source-traceable
state targets. This is still a transaction contract only; it does not start
`DB_PROGRAM`, run Python, mutate `/tmp/db_nonran_file`, fall back to a tool
table, or permit standalone/browser promotion.
`tool-db-process-native-protocol-alignment.tsv` aligns those generated gates
with the native source probe stdout keys, such as `tool_db_v2_1_handshake`,
`tool_db_getall_g_until_fini`, `tool_db_notify_l_u_p_protocol`, and
`tool_db_program_nonran_state_targets`. This table proves the generated gates
still match LinuxCNC-owned task/tooldata/config evidence, but it also remains
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`tool-db-process-native-runtime-readiness.tsv` records whether the host has
the runtime pieces needed to attempt a DB process protocol probe. It checks
`python3`, `linuxcnc`, `milltask`, `halcmd`, the configured
`axis/db_demo/db_nonran.py` program, and the LinuxCNC Python `linuxcnc.so` and
`tooldb.py` modules. It records PATH/source evidence where available and keeps
the DB boundary blocked with `proof_status=pending`, `execution_enabled=0`,
and `promotion_allowed=0`.
`tests/native/probe_tool_db_runtime.sh` is wired into `build_native_probes.sh`
as `linuxcnc_tool_db_runtime_probe`. On hosts without the required DB runtime
commands it exits successfully with `tool_db_runtime_probe_status =
skipped_missing_host_runtime`; on a ready host it remains disabled by default.
If explicitly enabled with `ENABLE_TOOL_DB_RUNTIME_PROBE=1`, it starts the
vendored `DB_PROGRAM`, drives the LinuxCNC `tooldb.py` `v2.1`/`g`/`p`/`l`/`u`
protocol over stdin/stdout, verifies nonrandom `T10..T19` startup state, tool
update, spindle load/unload, and flat-file persistence, then reports
`runtime_protocol_probe_passed`.
The artifact keeps `execution_enabled=0` and `promotion_allowed=0`. It is not
a standalone tool database executor, does not replace `DB_PROGRAM` with a
fallback `.tbl`, and does not make `axis/db_demo/base.ngc` a Node/browser
representative.
`linuxcnc_tool_db_boundary_probe` is the current native guard for this
evidence. It reads the LinuxCNC source `db_nonran.ini`, `db.py`,
`src/emc/task/taskclass.cc`, and `src/emc/tooldata/tooldata_db.cc`, then
verifies the DB mode owner path, child-process protocol, `v2.1` startup
handshake, `g`/`FINI` get-all path, `l`/`u`/`p` notifications, demo DB
callbacks, and nonrandom state targets. This is a source/protocol-target proof
only: it does not start `DB_PROGRAM`, run the Python tooldb loop, mutate the
flat-file database, or permit promotion.
### Candidate Boundary
A valid future boundary should be a narrow tool-database host adapter:
1. Reuse `tooldata_db.cc` and `tooldata_common.cc` for DB mode behavior.
2. Isolate the process-spawn edge behind a host abstraction so native can spawn
the configured DB program, while WASM/browser use an explicitly designed
equivalent only if it preserves the LinuxCNC protocol.
3. Preserve the `v2.1`, `g`, `l`, `u`, and `p` command/reply protocol rather
than parsing or inventing tool semantics in JavaScript.
4. Treat `db.py` as a config-owned process dependency. If it is not executable
in a target layer, that layer remains blocked.
### Required Proof Before Promotion
Native proof:
- The existing `linuxcnc_tool_db_boundary_probe` source/protocol guard must
continue to prove that the pending DB gates come from LinuxCNC task/tooldata
and demo DB sources rather than project-owned behavior.
- A probe starts `db_nonran.py` through the LinuxCNC DB path and verifies the
`v2.1` handshake.
- A get-all request returns the expected nonrandom startup tools.
- A load/unload or update path changes DB state through `l`, `u`, or `p` and
is reflected by a subsequent get-all.
Node WASM proof:
- The same protocol is visible through the SDK boundary.
- Tool lookup/update behavior matches the native proof without staging a fake
`.tbl` replacement.
Browser proof:
- Browser validation calls the Node-proven SDK/WASM boundary.
- OPFS may store DB files only as host persistence. It must not implement DB
command semantics.
## Python-Remap Inventory Boundary
Python-remap rows remain inventory-only. The current
`blocked-dependency-summary.tsv` records Python modules, remap/prolog/epilog
functions, NGC-only subpaths, and HAL/UI/HALUI declarations.
`python-remap-boundary-summary.tsv` preserves the same evidence per blocked
path and records LinuxCNC Python runtime owner evidence from
`src/emc/rs274ngc/interp_python.cc` and
`src/emc/pythonplugin/python_plugin.cc`. `python-remap-family-summary.tsv`
aggregates it by runtime family so mixed Python/NGC-only subpaths remain
visible without promoting execution. No Python-remap row should be promoted
until a separate LinuxCNC-owned Python runtime boundary exists and has native
plus Node/browser proof appropriate to the target layer.
`python-remap-runtime-gates.tsv` expands each blocked path into Python module,
remap/prolog/epilog callable, NGC-only subpath, process-assumption, and
runtime-owner gates. `python-remap-native-runtime-alignment.tsv` aligns those
generated gates with the current native source probe stdout. Runtime owner
gates map to exact LinuxCNC runtime proof keys such as
`python_runtime_pycall_dispatch` and `python_plugin_callable_invoke`; dependency
inventory gates map to representative family inventory proof or the aggregate
`python_remap_native_source_inventory_proof`. Both tables remain
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`python-remap-runtime-contract.tsv` records the next non-executing family-level
contract. It keeps one row per blocked Python-remap family, records the
LinuxCNC-owned Python runtime phases (`initialize_python`,
`apply_ini_python_path`, `execute_toplevel`, callable lookup/invoke,
remap-phase dispatch, generator finish, execute-string/file, and reload),
aggregates Python modules/callables/NGC-only subpaths, carries HAL/UI/HALUI
process assumptions, and binds each family to native, Node, and browser proof
requirements. It is a runtime contract only: it does not initialize Python,
import modules, execute callbacks, or permit promotion.
`python-remap-native-runtime-readiness.tsv` records the current host/source
readiness for future native Python-remap runtime probes. It checks `python3`,
`linuxcnc`, the LinuxCNC interpreter/plugin owner source files, and each
configured Python module by blocked runtime family. The artifact remains a
gate only: every row stays `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`.
`python-remap-native-runtime-state-plan.tsv` records the non-executing runtime
state plan for those future probes. It binds each blocked Python-remap family
to the required LinuxCNC Python phases, configured modules, callables,
NGC-only subpaths, process assumptions, readiness counts, source-alignment
artifacts, and future native proof targets. It does not initialize Python,
import modules, execute callbacks, or permit promotion.
`python-remap-native-runtime-fixture-plan.tsv` selects the first native runtime
fixture target, `axis/remap/stop-lookahead/nc_files`. That family is the
smallest current Python runtime lifecycle candidate because it needs the
LinuxCNC Python initialization/path/toplevel/runtime phases and configured
modules but avoids Python callable and NGC-only subpath complexity. The
fixture plan is still non-executing: it records the proof target only and
keeps `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`.
`tests/native/probe_python_remap_runtime.sh` is wired into
`build_native_probes.sh` as `linuxcnc_python_remap_runtime_probe`. It records
the stop-lookahead fixture identity, configured Python modules, required
LinuxCNC Python runtime phases, host command readiness, and source/module
availability. On hosts without `linuxcnc`, it exits successfully but reports
`python_remap_runtime_probe_status=skipped_missing_host_runtime`; on hosts with
the runtime available it remains disabled by default. If explicitly enabled
with `ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1`, it follows the `demo.ini`
`[PYTHON]` path/toplevel declarations, imports the vendored stop-lookahead
modules, verifies `queuebuster` callable lookup, confirms the callable returns
a generator, and checks that the first yield is the LinuxCNC
`INTERP_EXECUTE_FINISH` value from `interp_return.hh` before reporting
`runtime_lifecycle_probe_passed`.
`linuxcnc_python_remap_boundary_probe` is the current native guard for this
inventory. It reads the LinuxCNC Python runtime owners and representative
config families (`axis/laser`, `axis/remap/cycle`, TWP nutating, and
`gmoccapy` stdglue), then verifies the runtime dispatch/phase/callable owner
evidence plus representative Python modules, remap callables, prolog/epilog
callables, and Python path declarations. This is source inventory only: it
does not initialize Python, import modules, execute remap callbacks, or permit
promotion.
## Next Boundary Worklist
`next-boundary-worklist.tsv` is the machine-readable handoff for the next
runtime-boundary design phase. It is a planning artifact only: every row keeps
`execution_enabled=0` and `promotion_allowed=0`, records the LinuxCNC owner set,
records runtime owner evidence, records required native, Node, and browser
proof, and names the next boundary-design action before promotion.
`boundary-proof-gates.tsv` is the machine-readable proof checklist derived from
that worklist. It expands every target into native, Node, and browser proof
rows and keeps each row at `proof_status=pending`, `execution_enabled=0`, and
`promotion_allowed=0`. It must fail validation if a future edit tries to
promote a target without first replacing the pending gate with LinuxCNC-owned
proof for that layer. For the current blockers, event-only `USER_M_COMMAND`
coverage is insufficient for `millturn`, `.tbl` fallback coverage is
insufficient for `db_demo`, and JavaScript-owned behavior is insufficient for
Python runtime families.
`native-proof-alignment-summary.tsv` records whether the native source proof
summary, when present, is consumed by generated worklist and native proof-gate
rows. It currently aligns the `millturn` user-M source-state proof, `db_demo`
tool database protocol source proof, and Python runtime source-inventory proof
without enabling execution or promotion.
`runtime-boundary-native-alignment-summary.tsv` is the aggregate guard for the
detailed native alignment artifacts. It requires every user-M, tool DB, and
Python alignment row to have native stdout evidence, `alignment_ok=1`,
`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`.
`build/native/native-runtime-probe-summary.tsv` is the native companion for the
disabled runtime probe entry points. It summarizes the current runtime
readiness for `millturn` user-M, `db_demo` tool DB, and the Python
stop-lookahead fixture, records the missing host runtime requirements, points
back to each probe stdout log, and keeps every row at `execution_enabled=0` and
`promotion_allowed=0`.
`runtime-boundary-contract-summary.tsv` is the aggregate guard for the
non-executing runtime contracts. It ties the `millturn` user-M transition
contract, `db_demo` tool DB transaction contract, and Python-remap family
runtime contract to their native-alignment artifacts, and requires every
contract row to remain pending with execution and promotion disabled.
`blocked-runtime-promotion-lock.tsv` is the final machine-readable lock for
this phase. It combines the worklist, native/Node/browser proof gates, and
runtime alignment summary so every blocked target has `lock_active=1` until a
LinuxCNC-owned runtime boundary replaces the pending gates.
The first two priorities are the current designed-but-disabled full-process
blocks:
1. `external_user_m_process` for `axis/vismach/millturn/example.ngc`;
2. `tool_database_process` for `axis/db_demo/base.ngc`.
Python runtime family rows follow as inventory-only targets. They must remain
behind a LinuxCNC-owned Python runtime boundary and must not be used to vendor
or execute `gmoccapy`, `axis/laser`, TWP nutating, or other Python-remap
families by path alone.
## Current Validation
These commands must continue to pass after any change to this document or to
the inventory code:
```bash
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tools/verify_no_standalone_cnc_semantics.sh
```

View File

@@ -48,13 +48,14 @@ wasm-port/tests/host/verify_host_smokes.sh
| Reject standalone CNC semantics | Done | `tools/verify_no_standalone_cnc_semantics.sh` guards project-owned `Interp::...` definitions outside documented runtime-edge stubs. |
| Maintain source reuse map | Done | Current sim-config, remap, interpreter, kinematics, TP, user-M, tool, named-parameter, and OPFS runtime boundaries are recorded in `docs/source-reuse-map.md`; keep updating it whenever LinuxCNC source, test assets, or runtime boundaries are added. |
| Maintain compatibility validation notes | Done | Current native, Node WASM, browser, OPFS, and host aggregate checks are recorded in `docs/compatibility-validation.md`; keep updating it whenever a validation command or fixture class is added. |
| Maintain sim-config coverage matrix | Done | `docs/sim-configs-coverage-matrix.md` now maps all current `verify_sim_configs.sh` records to program class, native result, current Layer 3/4 coverage, and blocked/class-coverage notes. The native harness emits `class-summary.tsv` and `path-matrix.tsv`, and the Node inventory runner checks generated/tracked path sets plus tracked class/native-status/expected-failure/blocked fields against native outputs before execution. Future changes should update the matrix only with a matching regenerated native inventory. |
| Document validation layers | Done | `docs/compatibility-validation.md` now records Layer 1 `nc_files` basic smoke, Layer 2 `configs/sim` native strict harness, Layer 3 standalone native runtime probes, and Layer 4 WASM Node/browser representative smokes with entry commands, current results, expected boundaries, and the no-LinuxCNC-semantics rule. |
| Build LinuxCNC test inventory | In progress | `linuxcnc/tests/remap` has been inventoried by dependency class; the first broader `linuxcnc/tests` pass now records full-process, HAL/realtime, linuxcncrsh, Python-binding, and external-component families in the blocked table. |
| Prefer pure interpreter tests first | In progress | Continue with tests that can run through `Interp::open()`, `read()`, and `execute()` without realtime hardware or GUI. |
| Add upstream-output comparison | In progress | Use upstream `../linuxcnc/bin/rs274` or original `test.sh` output where practical, then compare against native/WASM/browser output. |
| Promote tests through three layers | In progress | Add each selected test first to native harnesses, then WASM Node, then browser smoke where meaningful. |
| Record blocked tests | In progress | First broader family-level blocked batch is recorded below; continue expanding it as each `linuxcnc/tests` family is inspected. |
| Add aggregate smoke coverage | Done | `tests/host/verify_host_smokes.sh` now runs stable Node WASM, sim-config WASM, `nc_files` WASM, OPFS, and browser smoke checks with shared builds. Current run passed with `host_wasm_opfs_browser_smokes=ok`. |
| Add aggregate smoke coverage | Done | `tests/host/verify_host_smokes.sh` now runs stable Node WASM, sim-config representative WASM, sim-config Node inventory, `nc_files` WASM, OPFS, and browser smoke checks with shared builds. Current run passed with `host_wasm_opfs_browser_smokes=ok`. |
| Add `linuxcnc/nc_files` basic examples | Done | `tests/native/verify_nc_files.sh` now runs the basic/example subset of upstream `linuxcnc/nc_files` through LinuxCNC `bin/rs274`; current native baseline is 107 total, 101 pass, 6 expected context/entry-point edges, 0 unexpected failures. Exploratory `--all` inventory is 247 total, 219 pass, 28 expected context/entry-point edges, 0 unexpected failures. A representative vendored subset now passes Node WASM and browser execution through LinuxCNC-backed `Interp::open()`/`read()`/`execute()`, with `3D_Chips.ngc` using an INI-declared tool-table context for its upstream `T1 M6` line. |
## Current Review Boundaries
@@ -132,6 +133,10 @@ directories under `wasm-port/vendor/linuxcnc/tests/interp/` including
| `configs/sim/axis/foam/foam.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/foam`; validates LinuxCNC INI-driven `U/V` axis mask handling through `axis_foam.ini` and vendored file execution paths. |
| `configs/sim/axis/geometry/xyzc.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/geometry`; validates LinuxCNC `USER_M_PATH` registration with the real executable `M110` while process execution remains a deterministic standalone `USER_M_COMMAND` boundary. |
| `configs/sim/axis/external_offsets/*.ngc` M111 demos | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/external_offsets`; validates `dyn_demo.ngc`, `eoffsets.ngc`, `jwp_z.ngc`, and `opa_demo.ngc` with their corresponding INI files, real executable `M111`, shared `eoffset.tbl`, and `opa_demo.ngc`'s `circles.ngc` subroutine while process execution remains a deterministic standalone boundary. |
| `configs/sim/axis/gladevcp/probe.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/gladevcp`; validates plain INI/tool-table main-program staging through `gladevcp_panel.ini` without treating the GTK panel process as browser runtime. |
| `configs/sim/axis/vismach/melfa-sim/example.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/melfa-sim`; validates a robot/Genser-style remap machine representative through real INI, tool table, and M428/M429/M430 remap subroutines while GUI/HAL process launch remains outside the standalone boundary. |
| `configs/sim/axis/vismach/puma/puma_cube.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/puma`; validates a PUMA machine-context representative through real INI, tool table, and remap subroutine staging while external GUI/HAL process launch remains outside the standalone boundary. |
| `configs/sim/woodpecker/on_abort.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/woodpecker`; validates deterministic `on_abort` file execution through the real machine INI and tool table without expanding browser coverage to unrelated full-process UI flows. |
| More `tests/remap/*` interpreter-only cases | Planned | Native first | Select cases that do not require Python behavior beyond documented runtime-edge stubs unless the required LinuxCNC source path is ported. |
| More `tests/interp/*` interpreter-only cases | Planned | Native first | Select upstream interpreter cases that can run through vendored file execution without Python, HAL, realtime motion, or GUI. |
| `tests/rs274ngc/*` candidates | Planned | Native first | Use upstream `rs274` as the baseline where output is comparable. |
@@ -192,6 +197,15 @@ Use this checklist when adding each LinuxCNC upstream test:
| `tests/trajectory-planner/circular-arcs` | Blocked | Full LinuxCNC sim configs with task, HAL/Tcl files, GUI/display settings, and motion execution logs. | Keep using standalone TP API probes for planner code; full circular-arc machine tests require task/HAL/motion boundaries. |
| `tests/lowlevel/emcmot-error-mpsc` | Blocked | RIP-only build against LinuxCNC motion sources and low-level motion error driver. | Revisit only if low-level motion process test drivers are intentionally ported. |
| `tests/uspace/spawnv-root` | Blocked | Sudo-installed userspace HAL component and `spawnv` root behavior. | Keep upstream-only unless HAL component install/runtime support is added. |
| `configs/sim/*/remap_subs/*.ngc` browser main-program inventory | Blocked | These files are remap/subroutine assets, not standalone browser main-program targets. | Keep validating them through native remap parse/execute paths and explicit five-axis/runtime probes instead of widening browser `runSimConfigProgram()` blindly. |
| `configs/sim/axis/db_demo/base.ngc` Layer 4 inventory | Blocked | `[EMCIO]DB_PROGRAM = ./db_nonran.py` requires LinuxCNC task/tooldata DB process startup, command/reply protocol, and database state behavior, not standalone interpreter file execution. | Keep as `L4-TOOL-DB` until a LinuxCNC-owned tool database runtime boundary exists and proves lookup/update behavior across native and WASM. `blocked-dependency-summary.tsv` records `taskclass.cc`, `tooldata_db.cc`, `tooldata_common.cc`, and `configs/sim/axis/db_demo/db.py` as the owner set plus source-derived `tool_db_protocol_evidence` for the `v2.1` handshake, `g`/`FINI` get-all, and `l`/`u`/`p` notification protocol. |
| `configs/sim/axis/vismach/millturn/example.ngc` Layer 4 inventory | Blocked | The remap execution chain calls external `USER_M_PATH` process codes `M128` and `M129`, with HAL/HALUI/UI process declarations in `millturn.ini`. | Keep as `L4-USER-M-PROCESS`; do not promote until the M128/M129 LinuxCNC-owned state boundary proves the kinstype guard and `ini.[xyz].*` HAL pin updates. `blocked-dependency-summary.tsv` records the `mcodes/M128` and `mcodes/M129` Tcl scripts plus source-derived `user_m_process_effects` for Tcl/HAL runtime use, kinstype guards, and `ini.[xyz]` HAL pin side effects. |
| `configs/sim/gmoccapy/*` Layer 4 full inventory | Blocked | Python remap runtime boundary is present in native LinuxCNC `rs274`, but not yet intentionally exposed for Node/browser full inventory. | Keep native inventory coverage as source-of-truth; add one representative Node/browser class sample only after the Python remap boundary is deliberately designed. Python module and prolog/epilog ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. |
| `configs/sim/axis/laser/*` Layer 4 full inventory | Blocked | Python remap runtime boundary is present in native LinuxCNC `rs274`, but not yet intentionally exposed for Node/browser full inventory. | Keep native inventory coverage as source-of-truth; add one representative Node/browser class sample only after the Python remap boundary is deliberately designed. Python module and remap ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. |
| `configs/sim/axis/remap/*/nc_files/*.ngc` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but these demo main programs depend on Python remaps, Python prolog/epilog callbacks, or Python-backed queue/tool-change handlers. | Keep native inventory coverage as source-of-truth; do not reduce Python remap demos to missing vendored files or browser standalone execution until the Python remap boundary is deliberately designed. Dependency ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. |
| `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but the demo family depends on Python remap entry points such as `g682`, `g69_core`, and `g53x_core` that are not yet intentionally exposed for Node/browser inventory. | Keep native inventory coverage as source-of-truth; revisit Layer 4 only after the Python remap boundary is deliberately designed rather than faked in JS. Python and NGC remap dependencies are inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. |
| `configs/sim/axis/vismach/VMC_toolchange/toolchange.ngc` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but the program is the remapped tool-change body for a Python prolog/epilog and full tool-change/HAL process flow. | Keep native inventory coverage as source-of-truth and validate tool-change mechanics through existing standalone interpreter/tooldata probes until task/HAL/tool-change runtime boundaries exist. |
| `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` | Blocked | Preserved upstream demo edge: line uses bare `X/Y/Z` after `G53.6` without an explicit motion G-code in the upstream standalone baseline. | Keep as expected failure in Layer 2 and do not modify G-code or project-owned interpreter semantics to force a pass. |
## Next Work Batch

View File

@@ -16,6 +16,8 @@ Result file:
```text
wasm-port/build/native/sim-configs/summary.tsv
wasm-port/build/native/sim-configs/class-summary.tsv
wasm-port/build/native/sim-configs/path-matrix.tsv
```
Baseline:
@@ -50,19 +52,52 @@ Remaining failures are explicit LinuxCNC-native baseline edges:
## Target
The first target is not a browser UI feature. It is a repeatable native and
WASM simulation harness that can load and execute all `linuxcnc/configs/sim`
programs that are meaningful in a standalone non-hardware simulation context.
The first target is not a browser UI feature and not a requirement that every
`linuxcnc/configs/sim` `.ngc` program pass through standalone `bin/rs274`.
It is a repeatable native and WASM inventory that classifies every
`configs/sim` program, runs the entries that are meaningful in standalone
native/WASM/browser contexts, and records blocked dependencies for the entries
that require full LinuxCNC task, HAL, UI, Python-remap, or external process
runtime.
Acceptance criteria:
- The native sim-config harness reports all executable sim programs as `PASS`.
- The native sim-config harness reports `unexpected_fail: 0` and writes
`summary.tsv`, `class-summary.tsv`, and `path-matrix.tsv`.
- Macro/remap files are validated by the correct entry point: direct execution
only for real programs, load/parse or remap-call validation for subroutines.
- WASM tests cover the same representative classes after the native harness is
green.
- Any remaining unsupported files are explicitly classified as native GUI or
hardware-only and excluded by rule, not by accident.
- Node WASM inventory executes only entries with a defined standalone/WASM
runtime path and reports `unexpected_fail: 0`.
- Browser coverage remains focused on representative runtime classes rather
than blind full-directory execution.
- Any remaining unsupported files are explicitly classified by dependency, not
by accident.
## Definition Of Done For Full configs/sim Coverage
Full coverage for this project means:
- Inventory complete: every `summary.tsv` `.ngc` entry appears in
`docs/sim-configs-coverage-matrix.md` and generated `path-matrix.tsv`.
- Classification complete: every entry has `main`, `macro_load`, or
`remap_subroutine` class.
- Blocked table complete: full-process, HAL, UI, linuxcncrsh, external
userspace component, Python binding/remap, tool-database, and process user-M
dependencies are recorded explicitly.
- Native source-of-truth complete: `verify_sim_configs.sh` remains the Layer 2
source for per-path status and expected-failure reason.
- Node inventory complete: `verify_sim_configs_inventory_wasm.sh` checks the
native/generated/tracked path sets, runs eligible vendored programs, and
emits stable WASM inventory and skip/block summaries.
Any eligible row with missing vendored machine context is an inventory
failure, not an expected skip.
- Browser class coverage complete: each promoted browser class has a
representative sample and no browser test relies on directory enumeration.
- Expected failures justified: the current eight Layer 2 expected failures are
tied to runtime boundaries or the preserved upstream demo edge.
- No accidental standalone semantic ownership: tests must not pass by changing
G-code semantics, JS interpreter behavior, or project-owned
`Interp::...` implementations.
## Phase 1: Make The Harness A First-Class Test
@@ -80,7 +115,8 @@ validation entry point.
- scan only `linuxcnc/configs/sim`;
- identify `.ngc`, nearest `.ini`, nearest `.tbl`;
- run from the INI directory;
- write `summary.tsv`, stdout, stderr, and interpreter output under
- write `summary.tsv`, `class-summary.tsv`, `path-matrix.tsv`, stdout,
stderr, and interpreter output under
`wasm-port/build/native/sim-configs/`;
- classify programs as `main`, `macro_load`, `remap_subroutine`, or
`unsupported_runtime_edge`;
@@ -252,71 +288,61 @@ wasm-port/tests/native/verify_native_probes.sh
wasm-port/tests/wasm/node/verify_interp_wasm.sh
```
## Phase 4: Bring Up Python Remap Runtime Edges
## Phase 4: Classify Python Remap Runtime Edges
Status: complete for the native sim-config harness. Current checks:
Status: complete for the native sim-config harness and blocked for Layer 4
full inventory. Current native checks:
```text
gmoccapy: total 38, pass 38, fail 0
axis/laser: total 3, pass 3, fail 0
axis/remap main demos: total 6, pass 6, fail 0
VMC_toolchange: total 1, pass 1, fail 0
```
Root cause:
Boundary:
The configs use LinuxCNC Python remap modules. Earlier harness runs failed while
initializing `python/toplevel.py`; current native runs now resolve and execute
these configs under the LinuxCNC `rs274` baseline.
The configs use LinuxCNC Python remap modules. Native LinuxCNC `rs274` can
resolve and execute these configs under the current baseline, but Node/browser
Layer 4 full inventory is intentionally blocked until a Python-remap runtime
boundary is deliberately designed. Do not make these pass in browser by
translating Python remap behavior into JavaScript or by adding project-owned
CNC semantics.
Implementation steps:
Recorded dependency:
1. Preserve upstream behavior where possible:
- `configs/sim/gmoccapy/python/toplevel.py`
- `configs/sim/gmoccapy/python/remap.py`
- `configs/sim/gmoccapy/python/stdglue.py`
- `configs/sim/axis/laser/python/toplevel.py`
- `configs/sim/axis/laser/python/remap.py`
- `configs/sim/axis/remap/*/python/*.py` for Python remap, prolog, epilog,
queue, and tool-change callbacks.
- `configs/sim/axis/vismach/VMC_toolchange/remap.py` and `toplevel.py` for
Python tool-change prolog/epilog handling.
- inspect vendored LinuxCNC Python plugin interfaces;
- identify exact APIs used by:
- `configs/sim/gmoccapy/python/toplevel.py`
- `configs/sim/gmoccapy/python/remap.py`
- `configs/sim/gmoccapy/python/stdglue.py`
- `configs/sim/axis/laser/python/toplevel.py`
- `configs/sim/axis/laser/python/remap.py`
Current policy:
2. Split the implementation into two layers:
- native harness support using the host Python runtime, if available;
- WASM support using a documented adapter boundary or a Python-free
equivalent only for runtime edges, not G-code semantics.
3. Add runtime state adapters required by Python remap:
- selected tool and pocket;
- tool table access;
- interpreter status object fields used by stdglue;
- message/error reporting;
- canonical tool-change side effects needed by `M6`, `M61`, and laser
remaps.
4. Make Python module path resolution match LinuxCNC:
- INI directory is the base directory;
- `PYTHONPATH` includes config `python/` directories;
- remap modules load relative to the sim config.
5. Add narrowly-scoped tests before running all 38 gmoccapy programs. Done:
- one gmoccapy tool-change macro;
- one gmoccapy lathe macro;
- one gmoccapy 5-axis example;
- one laser raster/vector program.
- Keep native inventory as source-of-truth.
- Mark `gmoccapy/*`, `axis/laser/*`, `axis/remap/*/nc_files/*.ngc`, and
`axis/vismach/VMC_toolchange/toolchange.ngc` rows as `L4-PYTHON-REMAP` in
`docs/sim-configs-coverage-matrix.md`.
- Revisit Layer 4 only after the runtime boundary is designed from LinuxCNC
source ownership, not as a browser smoke expansion.
Completion check:
```bash
wasm-port/tests/native/verify_sim_configs.sh --only gmoccapy
wasm-port/tests/native/verify_sim_configs.sh --only axis/laser
wasm-port/tests/native/verify_sim_configs.sh --only axis/remap
wasm-port/tests/native/verify_sim_configs.sh --only VMC_toolchange
```
## Phase 5: Support TWP Remaps Including G69
## Phase 5: Classify TWP Remaps Including G69
Status: mapping complete. The harness now maps
Status: native mapping complete and Layer 4 blocked on Python-remap runtime
ownership. The harness now maps
`axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*` through the
explicit `xyzacb-trsrn_twp/xyzacb-trsrn.ini` machine config instead of falling
back to `axis/axis.ini`. That loads the TWP `G69` remap declarations correctly,
@@ -329,7 +355,7 @@ Current failures:
`x50y50z150` after `G53.6`; same-directory demos use explicit `G0` motion
words at this point.
Root cause:
Boundary:
The demo programs rely on table/spindle rotary TWP remaps. The original test
mapping fell back to `axis/axis.ini` for these demo files because the actual
@@ -341,26 +367,15 @@ axis/vismach/5axis/table-rotary_spindle-rotary-nutating/
xyzbca-trsrn_twp/xyzbca-trsrn.ini
```
Implementation steps:
Current policy:
1. Improve sim-config mapping. Done:
- if a `.ngc` is under a `demos/` sibling of machine-specific INI
directories, map it to the appropriate TWP INI instead of walking upward
to `axis/axis.ini`;
- encode this as explicit metadata in the harness, not a fragile heuristic.
2. Ensure `SUBROUTINE_PATH` includes `../remap_subs:../demos` as declared by
the TWP INIs.
3. Verify remap subroutines:
- `g69remap.ngc`
- `g531remap.ngc`
- `g533remap.ngc`
- `g536remap.ngc`
4. Add a native test for each failing demo.
- Keep native mapping and expected-failure classification in
`verify_sim_configs.sh`.
- Keep `incremental_repetition_g533.ngc` as `UPSTREAM-DEMO`; do not edit the
upstream G-code or add standalone semantics to force a pass.
- Keep TWP demo Layer 4 rows as `L4-PYTHON-REMAP` until Python remap entry
points such as `g682`, `g69_core`, and `g53x_core` have an intentional
runtime boundary.
Latest result:
@@ -380,13 +395,14 @@ Completion check:
wasm-port/tests/native/verify_sim_configs.sh --only table-rotary_spindle-rotary-nutating
```
## Phase 6: Promote Native Coverage To WASM
## Phase 6: Promote Eligible Native Coverage To WASM
Status: complete for representative Node and browser WASM coverage. Dedicated
Node and browser smokes now pass a representative vendored `configs/sim` subset
through the SDK `runSimConfigProgram()` host boundary, which copies files into
the Emscripten filesystem and forwards execution to existing LinuxCNC-backed C
ABI paths. They cover:
Status: complete for the current representative Node/browser class coverage
and the Node inventory layer. Dedicated Node and browser smokes now pass a
representative vendored `configs/sim` subset through the SDK
`runSimConfigProgram()` host boundary, which copies files into the Emscripten
filesystem and forwards execution to existing LinuxCNC-backed C ABI paths. They
cover:
- `axis/foam/foam.ngc` with `axis_foam.ini`, verifying INI-driven `U/V` axis
mask handling in WASM.
@@ -400,87 +416,214 @@ ABI paths. They cover:
shared `eoffset.tbl`, and `opa_demo.ngc`'s `circles.ngc` subroutine,
verifying the same user-M and `SUBROUTINE_PATH` boundaries against upstream
sim programs.
The Node inventory guard keeps these deterministic `M110`/`M111` rows
unblocked, requires a vendored user-M file, and includes the `opa_demo.ngc`
`circles.ngc` subroutine text in boundary analysis so the reached `M111`
call is accounted for instead of being mistaken for an external user-M
process gap.
- `axis/gladevcp/probe.ngc` as a plain INI/tool-table main-program sample.
- `axis/external_offsets/circles.ngc` as the macro-load class representative,
wrapped only with an added `M2` for load/parse style execution.
- `axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc` and
`axis/vismach/5axis/table-rotary-tilting/demos/*` through the existing
five-axis remap execution C ABI.
- `axis/vismach/melfa-sim/example.ngc` and `axis/vismach/puma/puma_cube.ngc`
as additional remap/kinematics machine representatives.
- `woodpecker/on_abort.ngc` as the deterministic on-abort/user-action macro
class representative.
- Node inventory for the eligible vendored program set:
`executed=28`, `passed=28`, `skipped=131`, `unexpected_fail=0`.
- Node inventory skip/block summary:
`ASSET-ONLY=65`, `L4-PYTHON-REMAP=53`, `L4-TOOL-DB=1`,
`L4-USER-M-PROCESS=1`, `NON_MAIN_CLASS=10`, `UPSTREAM-DEMO=1`.
- Node blocked-dependency inventory for the hard blocked row set:
`L4-PYTHON-REMAP=53`, `L4-TOOL-DB=1`, `L4-USER-M-PROCESS=1`.
The inventory reads source `linuxcnc/configs/sim` INI files for dependency
accounting only and writes
`build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv` without
vendoring or executing those blocked families. The blocked summary includes
source-derived `user_m_process_effects` for `millturn`,
`tool_db_protocol_evidence` for `db_demo`, and Python module/remap/prolog/
epilog dependency ownership for Python-remap families. Python-remap rows are
also projected into
`build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv`, which
keeps all 53 `L4-PYTHON-REMAP` rows inventory-only with
`python_runtime_evidence` and `execution_enabled=0`.
Boundary decisions for the current hard blocks:
- `axis/vismach/millturn/example.ngc` remains `L4-USER-M-PROCESS`. The
source INI declares HAL, HALUI MDI, and UI process dependencies, and the
remap chain enters `remap_subs/428remap.ngc` and `429remap.ngc`, which call
external user-M process codes `M128` and `M129`. Those process scripts live
at `configs/sim/axis/vismach/millturn/mcodes/M128` and `M129`; they use Tcl
LinuxCNC/HAL packages, `emc_init`, `parse_ini`, `hal getp`, and `hal setp`
to change INI axis limit HAL pins after the kinematics switch. The current
LinuxCNC owner is therefore task user-M process dispatch plus HALUI/MDI and
the config-owned Tcl process scripts, not the standalone interpreter. Do not
promote this row until the boundary design in
`docs/full-process-boundary-design.md` has a deterministic state proof for
these HAL pin updates across native, Node, and browser. The Node inventory
guard requires this row to stay non-`REP` in Node and browser while it remains
`L4-USER-M-PROCESS`, and the generated inventory summary must keep it as
`SKIP` with that reason.
- `axis/db_demo/base.ngc` remains `L4-TOOL-DB`. The source INI declares
`[EMCIO]DB_PROGRAM = ./db_nonran.py`, so standalone interpreter execution
would miss LinuxCNC tool-database process startup and protocol/state
behavior. The LinuxCNC owner is `src/emc/task/taskclass.cc` for DB_PROGRAM
activation, `src/emc/tooldata/tooldata_db.cc` for DB process startup and
command/reply protocol, `src/emc/tooldata/tooldata_common.cc` for DB-backed
tooldata behavior, and the config program `configs/sim/axis/db_demo/db.py`.
Do not promote until the boundary design in
`docs/full-process-boundary-design.md` has a LinuxCNC-owned tool database
boundary that proves lookup/update behavior across native and WASM. The Node
inventory guard requires this row to stay non-`REP` in Node and browser while
it remains `L4-TOOL-DB`, and the generated inventory summary must keep it as
`SKIP` with that reason.
- Python-remap/full-process families remain `L4-PYTHON-REMAP`. The blocked
dependency inventory records Python modules, remap/prolog/epilog function
ownership, NGC remap subpaths, and HAL/UI/HALUI declarations for gmoccapy,
axis/laser, axis/remap demos, TWP nutating demos, and VMC tool-change
rows. The Python-specific boundary summary records the same row set as
inventory-only and requires a LinuxCNC-owned Python runtime boundary before
any promotion. Every `L4-PYTHON-REMAP` row must also remain `SKIP` with
`L4-PYTHON-REMAP` in the generated inventory summary. This is an inventory
artifact, not a Layer 4 execution path.
Completion checks:
```bash
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
```
Remaining work:
Current Layer 4 non-goals:
1. Extend `runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp` with the same
machine-config entry point used by native tests. Done for the existing
`runFileWithIni()` file-execution path.
- Do not run all 159 programs in browser.
- Do not promote Python remap/full-process/HAL/UI-only families into
Emscripten without LinuxCNC-owned runtime support.
- Do not add JS-owned G-code, remap, tool, kinematics, parameter, or planner
semantics.
2. Extend `runtime/sdk/src/linuxcnc-interp.js` with a host-boundary method such
as:
Browser inventory decision record:
```js
runSimConfigProgram({ iniPath, programPath, files })
```
Done. The method only writes caller-provided text files into the
Emscripten filesystem, applies executable bits for user M-code files, and
forwards execution to the existing LinuxCNC-backed C ABI path. It does not
implement CNC semantics in JavaScript.
3. Copy required sim config files into the Emscripten FS:
- INI;
- tool table;
- parameter file;
- `.ngc` program;
- `SUBROUTINE_PATH` files;
- `USER_M_PATH` handler files or registered adapter handlers.
Done for the representative Node and browser subsets.
4. Add Node WASM coverage. Done:
```text
wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs
wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
```
5. Add representative browser coverage. Done in
`wasm-port/tests/browser/interp_smoke.html` through the existing browser
interpreter smoke and the same `runSimConfigProgram()` SDK boundary as Node.
- Promoted after Node inventory: plain INI/tool-table execution
(`axis/gladevcp/probe.ngc`), deterministic macro/load execution
(`axis/external_offsets/circles.ngc`), deterministic on-abort/user-action
execution (`woodpecker/on_abort.ngc`), TDR/TRT five-axis remap execution,
bridge-mill W-axis remap execution, `melfa-sim`, and PUMA.
The Node inventory guard requires process-declaring representatives such as
`axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`,
`axis/vismach/melfa-sim/example.ngc`, and
`axis/vismach/puma/puma_cube.ngc` to keep their dependency rows in
`boundary-summary.tsv`, match the expected HAL/UI/HALUI/Python process flag
combinations, remain Node/browser `REP` rows, and avoid hard-block promotion
unless the classifier finds a real hard runtime dependency.
- Kept as blocked: TWP `table-rotary_spindle-rotary-nutating`, `gmoccapy`,
`axis/laser`, `axis/remap/*/nc_files`, and VMC tool-change Python remap
families. These are not missing browser staging work; they depend on
Python-remap, prolog/epilog, or full runtime process boundaries that have not
been intentionally exposed in Layer 4.
- Kept out of browser full inventory: remap subroutine assets and macro-only
non-representatives. They remain covered by native inventory, native remap
parse/execute probes, Node inventory where eligible, or a class
representative in browser.
## Phase 7: Documentation And Drift Control
Status: complete for the current representative sim-config WASM/browser
coverage. The documentation and manifest now record the native, Node WASM,
browser, source reuse, and vendor-sync state for the selected sim-config
programs.
Status: complete for the current full `configs/sim` coverage definition. The
documentation and manifest now record native inventory, generated class/path
artifacts, blocked policy, Node inventory, browser class coverage, source
reuse, and vendor-sync state.
1. Update `docs/compatibility-validation.md` with the sim-config matrix. Done.
1. Update `docs/compatibility-validation.md` with the sim-config matrix,
blocked policy, and validation commands. Done.
2. Update `docs/source-reuse-map.md` for newly vendored source files. Done.
2. Add `docs/sim-configs-coverage-matrix.md` as the tracked review surface for
all 159 current native inventory rows. Done.
3. Update `tools/source-manifest.txt` and `tools/verify_vendor_sync.sh` if new
3. Update `docs/source-reuse-map.md` for newly vendored source files. Done.
4. Update `tools/source-manifest.txt` and `tools/verify_vendor_sync.sh` if new
LinuxCNC files are copied into `wasm-port/vendor/linuxcnc`. Done for the
representative `axis/foam`, `axis/geometry`, and `axis/external_offsets`
sim-config files, including the remaining external-offset M111 programs and
`circles.ngc`; no `verify_vendor_sync.sh` logic change was needed.
current representative and inventory-backed sim-config files; no
`verify_vendor_sync.sh` logic change was needed.
4. Preserve the latest result summary as a machine-readable artifact, but do
5. Preserve the latest result summary as a machine-readable artifact, but do
not commit generated logs unless they are intentionally used as fixtures.
Done: generated logs remain under build/test output directories, while the
tracked documentation records only the current summary values and validation
commands.
Done: `summary.tsv` remains the source row set, and `class-summary.tsv` plus
`path-matrix.tsv` are generated artifacts under `build/native/sim-configs/`.
Node inventory also writes `build/wasm/sim-configs-inventory/summary.tsv`
`build/wasm/sim-configs-inventory/skip-summary.tsv`, and
`build/wasm/sim-configs-inventory/boundary-summary.tsv` plus
`build/wasm/sim-configs-inventory/ini-boundary-summary.tsv` for Layer 4
execution, skip/block accounting, and runtime-boundary dependency reporting.
The same inventory now writes the full blocked-boundary handoff artifacts:
`blocked-dependency-summary.tsv`, `full-process-boundary-summary.tsv`,
`user-m-process-boundary-summary.tsv`, `user-m-process-state-targets.tsv`,
`tool-db-process-boundary-summary.tsv`,
`tool-db-process-protocol-gates.tsv`,
`python-remap-boundary-summary.tsv`, `python-remap-family-summary.tsv`,
`boundary-phase-completion-summary.tsv`,
`native-proof-alignment-summary.tsv`, `next-boundary-worklist.tsv`, and
`boundary-proof-gates.tsv`. These remain accounting/proof-gate artifacts;
they do not enable blocked execution or promotion.
The inventory guard checks `skip-summary.tsv` against skip reasons derived
from `path-matrix.tsv`, so aggregate skip counts drift when any blocked or
class policy changes without updating the tracked matrix and inventory.
The inventory guard requires every vendored INI row to have an available
SDK runtime-boundary classifier report; `UNAVAILABLE` is reserved for rows
whose boundary summary records a missing vendored INI.
Hard blocked rows are additionally recorded in
`build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv` without
promotion into standalone/WASM execution. That artifact includes source
owner fields and runtime proof fields such as `user_m_process_files`,
`user_m_process_effects`, `tool_db_protocol_evidence`, and `linuxcnc_owner`,
so `millturn` and `db_demo` remain blocked for dependency-backed reasons
rather than path-only classification. The follow-up boundary design and
required proof for those two blocked rows are tracked in
`docs/full-process-boundary-design.md`. Node inventory also writes
`build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv` for
the designed-but-blocked non-Python full-process rows, including their
`runtime_owner_evidence`, and
`build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv` for
the Python remap inventory-only row set. The Python boundary and family
summaries include `python_runtime_evidence`. All blocked boundary artifacts
require `execution_enabled=0`.
## Recommended Work Order
## Layer 2 Expected-Failure Policy
1. Harness first: make `verify_sim_configs.sh` reproducible.
2. Axis config next: unblock `U/V/W` failures.
3. TWP mapping: complete; remaining TWP demo failures are Python/HAL remap
runtime edges.
4. User M-code dispatch: small runtime-edge feature, unblocks five files.
5. Python remap runtime: largest block; do it after the harness and smaller
runtime edges are stable.
6. WASM promotion after native parity.
The current Layer 2 baseline remains:
```text
total: 159
pass: 151
fail: 8
timeout: 0
expected_fail: 8
unexpected_fail: 0
```
Do not reduce the eight expected failures by changing upstream G-code, JS
interpreter behavior, or project-owned standalone interpreter semantics. Reducing
this count is only valid if a new LinuxCNC-owned native/runtime entry point can
legitimately supply the missing task/user-M/axis/TWP context while preserving the
strict native baseline as a separately documented source of truth.
## Recommended Next Work
1. Keep `verify_sim_configs.sh`, `path-matrix.tsv`, and
`docs/sim-configs-coverage-matrix.md` in sync whenever the source manifest or
vendored sim-config set changes.
2. Add new Node/browser representatives only when they cover a new runtime class
with a LinuxCNC-owned execution path.
3. Treat Python remap, full-process HAL/UI, tool database, and external
userspace process families as blocked until their runtime boundary is
intentionally designed and the proof criteria in
`docs/full-process-boundary-design.md` are met where applicable.
4. Re-evaluate Layer 2 expected failures only after a new legitimate
LinuxCNC-owned entry point exists.
## Non-Goals

View File

@@ -0,0 +1,421 @@
# Sim Configs Coverage Matrix
This matrix maps every current `wasm-port/tests/native/verify_sim_configs.sh` entry
to its native classification and current Layer 3/4 coverage status. It is the
tracked review surface for `linuxcnc/configs/sim` inventory; the native harness
also emits machine-readable artifacts for automation.
Current baseline:
- Source file: `wasm-port/build/native/sim-configs/summary.tsv`
- Generated class summary: `wasm-port/build/native/sim-configs/class-summary.tsv`
- Generated path matrix: `wasm-port/build/native/sim-configs/path-matrix.tsv`
- Total records: `159`
- Native result: `pass 151`, `expected_fail 8`, `unexpected_fail 0`
- Current Layer 4 representative subset: `axis/foam`, `axis/geometry`,
`axis/external_offsets`, `axis/gladevcp`, `woodpecker/on_abort.ngc`,
bridge-mill `5axisgui.ngc`, TDR/TRT five-axis switchkins demos,
`melfa-sim`, and `puma_cube.ngc`
- `wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs` checks that
this tracked matrix and generated `path-matrix.tsv` contain the same 159 paths
as native `summary.tsv` before running Node inventory.
- Node inventory artifact: `wasm-port/build/wasm/sim-configs-inventory/summary.tsv`
- Node skip/block artifact: `wasm-port/build/wasm/sim-configs-inventory/skip-summary.tsv`
- Node runtime-boundary artifact: `wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv`
- Node INI runtime-boundary artifact:
`wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv`
- Node blocked-dependency artifact:
`wasm-port/build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv`
- Node full-process boundary design artifact:
`wasm-port/build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv`
- Node user-M process boundary design artifact:
`wasm-port/build/wasm/sim-configs-inventory/user-m-process-boundary-summary.tsv`
- Node user-M process transition contract artifact:
`wasm-port/build/wasm/sim-configs-inventory/user-m-process-transition-plan.tsv`
- Node tool DB process boundary design artifact:
`wasm-port/build/wasm/sim-configs-inventory/tool-db-process-boundary-summary.tsv`
- Node tool DB process transaction contract artifact:
`wasm-port/build/wasm/sim-configs-inventory/tool-db-process-transaction-plan.tsv`
- Node Python-remap boundary inventory artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv`
- Node Python-remap family inventory artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-family-summary.tsv`
- Node Python-remap runtime contract artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-runtime-contract.tsv`
- Node Python-remap native runtime readiness artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-readiness.tsv`
- Node Python-remap native runtime state-plan artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-state-plan.tsv`
- Node Python-remap native runtime fixture-plan artifact:
`wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-fixture-plan.tsv`
- Node runtime-boundary contract summary artifact:
`wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-contract-summary.tsv`
- Node boundary-phase completion artifact:
`wasm-port/build/wasm/sim-configs-inventory/boundary-phase-completion-summary.tsv`
- Node next-boundary worklist artifact:
`wasm-port/build/wasm/sim-configs-inventory/next-boundary-worklist.tsv`
- Current Node inventory: `executed 28`, `passed 28`, `skipped 131`,
`unexpected_fail 0`
- Current Node skip/block counts: `ASSET-ONLY 65`, `L4-PYTHON-REMAP 53`,
`L4-TOOL-DB 1`, `L4-USER-M-PROCESS 1`, `NON_MAIN_CLASS 10`,
`UPSTREAM-DEMO 1`
Legend:
- `Layer 3`: `SIM-*` means dedicated native runtime probe coverage; `5AX-EXEC` means
native five-axis remap execution coverage; `-` means no dedicated runtime probe yet.
- `Layer 4 Node/Browser`: `REP` means the current representative smoke covers this
exact program; `INV` means the Node inventory runner covers the exact program;
`N/A` means the row is a subroutine asset and should not be judged as a standalone
browser main program; `-` means the row is not individually promoted at that layer
and must be interpreted with the row's blocked or class-coverage note.
- `Blocked`: current hard blocked dependency or non-target classification for future
inventory work. `ASSET-ONLY` means the row is not a browser/main-program target.
`L4-PYTHON-REMAP` means native `rs274` coverage exists but Node/browser full inventory
is blocked on an intentional Python-remap runtime boundary decision. `UPSTREAM-DEMO`
means the file is a preserved upstream expected-failure edge.
- `boundary-summary.tsv`: one row per native inventory path. It records the
matrix blocked kind, the SDK classifier's recommended hard block when an INI
is vendored, declared HAL/UI/HALUI/Python process dependencies, tool database
declarations, user-M process codes seen in the execution text, and which of
those user-M codes are not staged by vendored `USER_M_PATH` files. Python is
split into total process dependency, UI/DB process dependency, and Python
remap runtime dependency so safe UI representatives such as `gladevcp` are
not mislabeled as Python-remap coverage. Rows whose INI has not been
vendored yet use `recommended_blocked=UNAVAILABLE` and keep their tracked
matrix policy as the source of truth until the relevant boundary inventory
batch vendors the missing context.
- `ini-boundary-summary.tsv`: one row per unique INI referenced by the native
inventory. It aggregates path-level boundary reports so vendored INIs have a
direct machine-readable `report_available=1` check and hard block
recommendations can be audited at INI granularity.
- `blocked-dependency-summary.tsv`: one row per hard blocked
`L4-PYTHON-REMAP`, `L4-TOOL-DB`, and `L4-USER-M-PROCESS` path. It reads the
source `linuxcnc/configs/sim` INI files without vendoring or executing those
families, records Python modules, remap/prolog/epilog function ownership,
NGC remap subpaths, HAL/UI/HALUI process declarations, `DB_PROGRAM`, and
tool database protocol evidence, plus external user-M execution codes, their
process script files, and process side-effect evidence. The `linuxcnc_owner`
field records the LinuxCNC source/config files that own the blocked behavior,
and keeps those rows blocked until a LinuxCNC-owned runtime boundary is
designed.
- `full-process-boundary-summary.tsv`: one row for each designed-but-still-blocked
non-Python full-process boundary. It currently covers `axis/db_demo/base.ngc`
and `axis/vismach/millturn/example.ngc`, records LinuxCNC runtime owner
evidence, records required native/Node/browser proof, and requires
`execution_enabled=0`.
- `user-m-process-boundary-summary.tsv`: one row for each designed-but-still-blocked
external user-M process boundary. It currently records the `millturn`
`M128`/`M129` process files, remap call chain, kinstype guards, and
source-traceable `ini.[xyz].*` HAL pin state targets, while requiring
`execution_enabled=0` and `promotion_allowed=0`.
- `user-m-process-transition-plan.tsv`: the pending non-executing transition
contract for the `millturn` user-M boundary. It binds `M428` to `M128` and
`M429` to `M129`, records switchkins output/target, active G5x work offset,
guard pin, state mode, and expected `ini.[xyz].*` outputs, and still requires
`execution_enabled=0` and `promotion_allowed=0`.
- `user-m-process-native-transition-alignment.tsv`: the native source
alignment for the two `millturn` transition rows. It proves the generated
`M428/M429` transition contract still matches the native probe stdout for
switchkins output/target, G5x, offset pocket, and `M428 -> M128` /
`M429 -> M129` calls, while remaining pending and non-executing.
- `user-m-process-native-runtime-state-plan.tsv`: the pending native runnable
state-probe contract for `millturn`. It records the required LinuxCNC
task/HAL/Tcl user-M runtime, the HAL/INI environment, and exact
`ini.[xyz].*` values that a future runtime probe must observe after the
transitions, while keeping `execution_enabled=0` and `promotion_allowed=0`.
- `user-m-process-native-runtime-readiness.tsv`: the host capability gate for
that future native probe. It records whether `tclsh`, `halrun`, `halcmd`,
and `linuxcnc` are available on PATH and keeps the boundary pending and
non-promotable regardless of host readiness.
- `user-m-process-native-runtime-probe-gate.tsv`: the generated execution gate
for that future native probe. It records per-transition runtime readiness,
missing host commands, source-proof readiness, and the pending gate status.
The native `probe_millturn_user_m_runtime.sh` entry point reports
`skipped_missing_host_runtime` on hosts without the full LinuxCNC HAL/Tcl
runtime, `ready_disabled_by_default` when the host is ready but the guarded
runtime probe is not explicitly enabled, or `runtime_state_probe_passed` when
`ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1` proves the LinuxCNC-owned
`M128`/`M129` Tcl scripts update the expected `ini.[xyz].*` HAL pins.
command set and does not enable execution or promotion.
- `tool-db-process-boundary-summary.tsv`: one row for each designed-but-still-blocked
tool database process boundary. It currently records `db_nonran.py`,
LinuxCNC tooldata protocol messages, DB program callbacks, nonrandom tool
database state targets, and runtime owner evidence, while requiring
`execution_enabled=0` and `promotion_allowed=0`.
- `tool-db-process-transaction-plan.tsv`: the pending non-executing transaction
contract for the `db_demo` tool database boundary. It orders startup
handshake, get-all, spindle load notify, tool offset notify, and spindle
unload notify steps, binds each protocol message to the expected `db.py`
callback and state targets, and still requires `execution_enabled=0` and
`promotion_allowed=0`.
- `tool-db-process-native-runtime-readiness.tsv`: the host capability gate for
the guarded native DB process protocol probe. It records whether `python3`,
`linuxcnc`, `milltask`, `halcmd`, the configured `db_nonran.py`, and
LinuxCNC's `linuxcnc.so` / `tooldb.py` Python modules are available, while
keeping the DB boundary pending and non-promotable. The native
`probe_tool_db_runtime.sh` entry point reports `skipped_missing_host_runtime`
when the host runtime is unavailable, `ready_disabled_by_default` when it is
available but not explicitly enabled, or `runtime_protocol_probe_passed` when
`ENABLE_TOOL_DB_RUNTIME_PROBE=1` proves the LinuxCNC-owned `DB_PROGRAM`
`v2.1`/`g`/`p`/`l`/`u` protocol, nonrandom state updates, and flat-file
persistence.
- `python-remap-boundary-summary.tsv`: one row for each `L4-PYTHON-REMAP`
path. It records Python modules, remap/prolog/epilog functions, NGC-only
subpaths, HAL/UI/HALUI assumptions, the LinuxCNC Python owner set, LinuxCNC
Python runtime owner evidence, and requires `execution_enabled=0`.
- `python-remap-family-summary.tsv`: one row per blocked Python-remap runtime
family. It aggregates row and INI counts plus Python module,
remap/prolog/epilog, NGC-only subpath, Python runtime owner evidence,
HAL/UI/HALUI, and `execution_enabled=0` evidence without vendoring or
executing those families.
- `python-remap-runtime-contract.tsv`: one row per blocked Python-remap runtime
family. It records LinuxCNC-owned Python runtime phases, Python modules,
remap/prolog/epilog callables, NGC-only subpaths, HAL/UI/HALUI assumptions,
native/Node/browser proof requirements, and keeps `proof_status=pending`,
`execution_enabled=0`, and `promotion_allowed=0`.
- `python-remap-native-runtime-readiness.tsv`: the host/source capability gate
for guarded native Python-remap runtime probes. It records `python3`,
`linuxcnc`, LinuxCNC's Python interpreter/plugin owner source files, and the
configured Python modules for each blocked family, while keeping every row
pending, non-executing, and non-promotable.
- `python-remap-native-runtime-state-plan.tsv`: one row per blocked
Python-remap family. It records the runtime phases, modules, callables,
NGC-only subpaths, process assumptions, readiness counts, source-alignment
inputs, and exact future native state-probe targets while keeping every row
pending, non-executing, and non-promotable.
- `python-remap-native-runtime-fixture-plan.tsv`: the first non-executing
Python runtime fixture plan. It selects
`axis/remap/stop-lookahead/nc_files` as the minimal lifecycle fixture because
it has Python modules and runtime phases without Python callable or NGC-only
subpath complexity, and keeps execution/promotion disabled. The native
`probe_python_remap_runtime.sh` entry point reports
`skipped_missing_host_runtime` without the host runtime,
`ready_disabled_by_default` when the host is ready but the probe is not
explicitly enabled, or `runtime_lifecycle_probe_passed` when
`ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1` proves the `demo.ini`
path/toplevel import, `queuebuster` callable lookup, generator return, and
first `INTERP_EXECUTE_FINISH` yield.
- `runtime-boundary-contract-summary.tsv`: one row per blocked runtime boundary
class. It unifies the user-M transition contract, tool DB transaction
contract, and Python runtime contract with their native-alignment artifact,
and requires every contract row to remain pending with execution and
promotion disabled.
- `boundary-phase-completion-summary.tsv`: one row per boundary-phase
completion criterion. It requires vendored INI boundary reports, dependency
evidence for hard blocks, safe HAL/UI representative coverage, blocked
families remaining skipped/non-representative with execution disabled, and
LinuxCNC-owned runtime proof fields for user-M, tool DB, and Python runtime
blockers. When native source proof is available, it also requires that proof
to be consumed by generated worklist/native proof-gate rows without enabling
execution or promotion.
- `native-proof-alignment-summary.tsv`: one row per native source proof class.
It aligns the native source proof summary with generated worklist/native
proof-gate consumers for user-M, tool DB, and Python runtime blockers.
- `next-boundary-worklist.tsv`: one row per next blocked runtime-boundary
design target. It keeps execution and promotion disabled, records the
LinuxCNC owner set and runtime owner evidence, records native, Node, and
browser proof requirements, and names the next boundary-design action before
any blocked family can be promoted.
## Summary
| Class | Count |
| --- | --- |
| `main` | `48` |
| `macro_load` | `46` |
| `remap_subroutine` | `65` |
## Family Summary
| Family | Count |
| --- | --- |
| `axis/db_demo` | `1` |
| `axis/external_offsets` | `6` |
| `axis/foam` | `1` |
| `axis/geometry` | `1` |
| `axis/gladevcp` | `1` |
| `axis/laser` | `3` |
| `axis/lathe-fanucy` | `1` |
| `axis/remap` | `29` |
| `axis/rose_engine` | `2` |
| `axis/vismach` | `57` |
| `gmoccapy/lathe_configs` | `8` |
| `gmoccapy/macros` | `25` |
| `gmoccapy/non_trivial_kinematics` | `5` |
| `gscreen/industrial_lathe_wear` | `1` |
| `gscreen/silverdragon` | `4` |
| `qtaxis/non-trivial` | `3` |
| `qtdragon/qtdragon_multi_joint` | `1` |
| `qtdragon/qtdragon_xyz` | `1` |
| `qtdragon/qtdragon_xyz45` | `1` |
| `qtdragon_hd/qtdragon_hd_xyz` | `1` |
| `qtdragon_hd/qtdragon_hd_z_compensation` | `1` |
| `qtvcp_screens/industrial_lathe_wear` | `1` |
| `qtvcp_screens/non-trivial` | `3` |
| `qtvcp_screens/qtdragon` | `1` |
| `woodpecker` | `1` |
## Program Matrix
| Path | Family | Class | Native | Expected Failure | Layer 3 | Layer 4 Node | Layer 4 Browser | Blocked | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `axis/db_demo/base.ngc` | `axis/db_demo` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-TOOL-DB` | native pass, but Node/browser inventory is blocked by the LinuxCNC tool-database process boundary declared by `[EMCIO]DB_PROGRAM` |
| `axis/external_offsets/circles.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 4 macro-only class representative now covered through wrapped execution with native staging inputs |
| `axis/external_offsets/dyn_demo.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered |
| `axis/external_offsets/eoffsets.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered |
| `axis/external_offsets/jwp_z.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered |
| `axis/external_offsets/opa_demo.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered |
| `axis/external_offsets/queuebuster.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` |
| `axis/foam/foam.ngc` | `axis/foam` | `main` | `FAIL` | `ini-axis-mask-UV` | `SIM-FOAM` | `REP` | `REP` | `-` | Layer 2 expected-fail; Layer 3/4 runtime edge covered |
| `axis/geometry/xyzc.ngc` | `axis/geometry` | `main` | `FAIL` | `user-m-code-M110` | `SIM-XYZC` | `REP` | `REP` | `-` | Layer 2 expected-fail; M110 runtime edge covered |
| `axis/gladevcp/probe.ngc` | `axis/gladevcp` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | plain INI/tool-table main-program class representative covered in Node and browser through vendored staging inputs |
| `axis/laser/raster_test.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `axis/laser/vector_test.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `axis/laser/vector_test2.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `axis/lathe-fanucy/toolchange.ngc` | `axis/lathe-fanucy` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `axis/remap/cycle/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python remap/prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` |
| `axis/remap/cycle/nc_subroutines/g843.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python prolog/epilog remap runtime boundaries; remap subroutine assets remain `ASSET-ONLY` |
| `axis/remap/extend-builtins/nc_subroutines/change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m0.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m1.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m60.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m7.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m8.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/extend_m9.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/prepare.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/setfeed.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/setspeed.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/extend-builtins/nc_subroutines/settool.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/getting-started/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python remap handlers such as `G88.1`; remap subroutine assets remain `ASSET-ONLY` |
| `axis/remap/getting-started/nc_subroutines/change_min.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/getting-started/nc_subroutines/m400.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/getting-started/nc_subroutines/m410.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/getting-started/nc_subroutines/prepare_min.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/manual-toolchange-with-tool-length-switch/nc_files/tcdemo.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` |
| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/manual_change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/on_abort.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/restore.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/rack-toolchange/nc_files/tcdemo.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` |
| `axis/remap/rack-toolchange/nc_subroutines/on_abort.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/rack-toolchange/nc_subroutines/rack_change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/rack-toolchange/nc_subroutines/tool_getput_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/rack-toolchange/nc_subroutines/tool_holder_clear_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/remap/stop-lookahead/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python `queuebuster` remap runtime boundaries; remap subroutine assets remain `ASSET-ONLY` |
| `axis/rose_engine/rcone.ngc` | `axis/rose_engine` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `axis/rose_engine/rcone_demo.ngc` | `axis/rose_engine` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory coverage uses the native harness-selected `axis/sim.tbl` fallback staged at the INI-declared tool-table path; browser class coverage is represented by other plain INI/tool-table samples |
| `axis/vismach/5axis/bridgemill/5axisgui.ngc` | `axis/vismach` | `main` | `FAIL` | `ini-axis-mask-W` | `SIM-BRIDGE,5AX-EXEC` | `REP` | `REP` | `-` | Layer 2 expected-fail; W-axis and remap runtime edge covered |
| `axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TDR five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-dual-rotary/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/centering.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_ac.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzac_switchkins_sub.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/circular_pocket.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_back_and_forth.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` | `axis/vismach` | `main` | `FAIL` | `upstream-demo-missing-motion-gcode` | `-` | `-` | `-` | `UPSTREAM-DEMO` | preserve upstream demo failure; do not force PASS |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/simple_example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/square.ngc` | `axis/vismach` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g531remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g533remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g536remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g69remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/on_abort_no_twp_reset.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/on_abort_with_twp_reset.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/VMC_toolchange/toolchange.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog and full tool-change runtime boundaries |
| `axis/vismach/hexapod-sim/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/hexapod-sim/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/hexapod-sim/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/melfa-sim/example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | robot/Genser-style remap machine class representative covered in Node and browser through vendored INI, tool-table, and remap-subroutine staging |
| `axis/vismach/melfa-sim/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/melfa-sim/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/melfa-sim/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/millturn/example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-USER-M-PROCESS` | native pass, but Node/browser inventory is blocked by external `USER_M_PATH` process M-codes `M128` and `M129` rather than the deterministic `M110`/`M111` boundary already modeled by the standalone runtime |
| `axis/vismach/millturn/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/millturn/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/puma/puma_cube.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | PUMA kinematics/remap machine class representative covered in Node and browser through vendored INI, tool-table, and remap-subroutine staging |
| `axis/vismach/puma/puma_seam_weld.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory covered with the same vendored puma machine context; browser class coverage is represented by `puma_cube.ngc` |
| `axis/vismach/puma/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/puma/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/puma/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/scara/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/scara/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `axis/vismach/scara/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `gmoccapy/lathe_configs/boring.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/chamfer.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/drilling.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/facing.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/grooving.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/radius.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/threading.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/lathe_configs/turning.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/change.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/change_g43.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/go_to_position.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/halo_world.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/i_am_lost.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/increment.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/jog_around.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_0.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_1.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_10.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_11.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_12.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_13.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_14.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_15.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_2.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_3.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_4.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_5.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_6.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_7.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_8.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/macro_9.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/on_abort.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/macros/settool_g43.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzbc.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzbc.ngc` | `gmoccapy/non_trivial_kinematics` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed |
| `gscreen/industrial_lathe_wear/toolchange.ngc` | `gscreen/industrial_lathe_wear` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `gscreen/silverdragon/macros/auto_zref.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `gscreen/silverdragon/macros/laserzero.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `gscreen/silverdragon/macros/tool_sensor.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `gscreen/silverdragon/macros/touch_plate.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `qtaxis/non-trivial/scara/remap_subs/428remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtaxis/non-trivial/scara/remap_subs/429remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtaxis/non-trivial/scara/remap_subs/430remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtdragon/qtdragon_multi_joint/on_abort.ngc` | `qtdragon/qtdragon_multi_joint` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `qtdragon/qtdragon_xyz/on_abort.ngc` | `qtdragon/qtdragon_xyz` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `qtdragon/qtdragon_xyz45/on_abort.ngc` | `qtdragon/qtdragon_xyz45` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `qtdragon_hd/qtdragon_hd_xyz/on_abort.ngc` | `qtdragon_hd/qtdragon_hd_xyz` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc` | `qtdragon_hd/qtdragon_hd_z_compensation` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `qtvcp_screens/industrial_lathe_wear/toolchange.ngc` | `qtvcp_screens/industrial_lathe_wear` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later |
| `qtvcp_screens/non-trivial/scara/remap_subs/428remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtvcp_screens/non-trivial/scara/remap_subs/429remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtvcp_screens/non-trivial/scara/remap_subs/430remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution |
| `qtvcp_screens/qtdragon/on_abort.ngc` | `qtvcp_screens/qtdragon` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample |
| `woodpecker/on_abort.ngc` | `woodpecker` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | Layer 4 deterministic on_abort class representative now covered |

View File

@@ -41,7 +41,8 @@ Current validation is intentionally mechanical:
| Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` |
| TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` |
| Five-axis switchkins machine configs and M428/M429/M430 remaps | `configs/sim/axis/vismach/5axis/bridgemill/*`, `table-dual-rotary/*`, and `table-rotary-tilting/*` selected INI, HAL, tool-table, XML, demo, and `remap_subs/*.ngc` files plus `src/emc/rs274ngc/interp_remap.cc` | Copy unchanged | `M428`, `M429`, and `M430` remain LinuxCNC `REMAP` entries that call LinuxCNC NGC subroutines using `M68`, `M66`, `_hal[motion.switchkins-type]`, and the INI/HAL `motion.analog-out-03 => motion.switchkins-type` link; standalone remap descriptor parsing routes through vendored `Interp::parse_remap()` and `find_ngc_file()`, and NGC remap/file execution routes through vendored LinuxCNC O-word and `open()`/`read()`/`execute()` paths while HAL synchronization stays a runtime adapter boundary | Vendor byte sync, `linuxcnc_5axis_remap_asset_probe`, `linuxcnc_remap_parse_harness`, `linuxcnc_remap_hal_sync_harness`, `linuxcnc_5axis_remap_execute_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/browser/verify_ini_panel_browser.sh` |
| Representative sim-config machine programs | `configs/sim/axis/foam/*`, `configs/sim/axis/geometry/M110`, `xyzc.ini`, `xyzc.ngc`, `configs/sim/axis/external_offsets/M111`, `dyn_demo.ngc`, `dynamic_offsets.ini`, `eoffsets.ngc`, `eoffsets.ini`, `jwp_z.ngc`, `jwp_z.ini`, `opa_demo.ngc`, `opa.ini`, `circles.ngc`, `eoffset.tbl`, and `configs/sim/axis/sim.tbl` | Copy unchanged | The `foam`, `xyzc`, and external-offset sample programs remain LinuxCNC sim-config assets. The standalone boundary only copies INI, tool table, G-code, executable user-M files, `SUBROUTINE_PATH` files, and remap-NGC files into the native or WASM filesystem, then calls vendored LinuxCNC INI parsing and `Interp::open()`/`read()`/`execute()` through the existing machine-config adapter. The native sim-config harness now prefers `[DISPLAY]OPEN_FILE` when several INI files live beside a program, so each program is judged with its corresponding machine context. The JS SDK `planIniFileContextStaging()` is a generic manifest-based file-plan helper, `planSimConfigStaging()` is its `configs/sim` wrapper, and `runSimConfigProgram()` only writes caller-provided text files to the Emscripten filesystem, applies executable bits, and forwards to LinuxCNC-backed C ABI entry points. `M110`/`M111` process execution stays a runtime boundary represented by deterministic `USER_M_COMMAND` canonical events | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/browser/verify_interp_browser.sh` |
| Representative sim-config machine programs | `configs/sim/axis/foam/*`, `configs/sim/axis/geometry/M110`, `xyzc.ini`, `xyzc.ngc`, `configs/sim/axis/external_offsets/M111`, `dyn_demo.ngc`, `dynamic_offsets.ini`, `eoffsets.ngc`, `eoffsets.ini`, `jwp_z.ngc`, `jwp_z.ini`, `opa_demo.ngc`, `opa.ini`, `circles.ngc`, `eoffset.tbl`, `configs/sim/axis/sim.tbl`, `configs/sim/axis/gladevcp/gladevcp_panel.ini`, `probe.ngc`, `sim.tbl`, `configs/sim/axis/vismach/melfa-sim/*`, selected `configs/sim/axis/vismach/puma/*`, and `configs/sim/woodpecker/on_abort.ngc`, `tool.tbl`, `woodpecker.ini` | Copy unchanged | The `foam`, `xyzc`, external-offset, plain `gladevcp/probe.ngc`, `melfa-sim`, PUMA, and deterministic `woodpecker/on_abort.ngc` sample programs remain LinuxCNC sim-config assets. The standalone boundary only copies INI, tool table, G-code, executable user-M files, `SUBROUTINE_PATH` files, and remap-NGC files into the native or WASM filesystem, then calls vendored LinuxCNC INI parsing and `Interp::open()`/`read()`/`execute()` or the existing five-axis remap execution C ABI through the machine-config adapter. The native sim-config harness now prefers `[DISPLAY]OPEN_FILE` when several INI files live beside a program, so each program is judged with its corresponding machine context. The JS SDK `planIniFileContextStaging()` is a generic manifest-based file-plan helper, `planSimConfigStaging()` is its `configs/sim` wrapper, and `runSimConfigProgram()` only writes caller-provided text files to the Emscripten filesystem, applies executable bits, and forwards to LinuxCNC-backed C ABI entry points. `M110`/`M111` process execution stays a runtime boundary represented by deterministic `USER_M_COMMAND` canonical events, while GUI driver, HAL process launch, and external userspace process startup remain outside standalone Node/browser execution. The TWP `table-rotary_spindle-rotary-nutating` demo family remains outside this representative row because its Layer 4 promotion still depends on a deliberate Python-remap runtime boundary, not on additional JS-owned staging logic. | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/wasm/node/verify_sim_configs_inventory_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/host/verify_host_smokes.sh` |
| Sim-config inventory and blocked-boundary assets | Selected `configs/sim/axis/db_demo/*`, `axis/rose_engine/*`, `axis/vismach/millturn/*`, `configs/sim/qtdragon/*`, `configs/sim/qtdragon_hd/*`, and `configs/sim/qtvcp_screens/qtdragon/*` files | Copy unchanged | These assets are vendored for the machine-readable `configs/sim` Node inventory and blocked-boundary accounting. Eligible `on_abort` and plain INI/tool-table rows run through the same LinuxCNC-backed `runSimConfigProgram()` staging path as other sim-config samples. Rows such as `axis/db_demo/base.ngc` and `axis/vismach/millturn/example.ngc` remain explicit Layer 4 blocked entries because their native LinuxCNC configs depend on tool-database or external user-M process boundaries; Node/browser inventory records those dependencies instead of reducing them to standalone file execution. | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_inventory_wasm.sh`, `tests/host/verify_host_smokes.sh` |
| Representative `nc_files` examples | `nc_files/3D_Chips.ngc`, `nc_files/arcspiral.ngc`, `nc_files/factorial.ngc`, `nc_files/hole-circle.ngc`, `nc_files/m6demo.ngc` | Copy unchanged | These upstream `linuxcnc/nc_files` examples are copied byte-for-byte into the WASM vendor tree after the native `nc_files` harness classifies the broader directory. Node and browser tests only stage the original `.ngc` text and, for `3D_Chips.ngc`, the minimal INI-declared tool table context required by its upstream `T1 M6` line in the Emscripten filesystem, then call the LinuxCNC-backed `Interp::open()`, `read()`, and `execute()` path through the existing SDK; no G-code, O-word, tool-change, or M-code behavior is implemented in JavaScript | Vendor byte sync, `tests/native/verify_nc_files.sh`, `tests/wasm/node/verify_nc_files_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/host/verify_host_smokes.sh` |
| LinuxCNC remap regression fixtures | `tests/remap/duplicate-o-word/*`, `tests/remap/fail/args.0/*`, `tests/remap/fail/args.1/*`, `tests/remap/fail/args.2/*`, `tests/remap/fail/body-ngc/*`, `tests/remap/m30-interaction/*`, `tests/remap/nested-remaps-oword/*`, `tests/remap/posargs.0/*`, `tests/remap/sequencing/*`, selected NGC-only `tests/remap/remap-io/test-ngc.ini` plus `io_*.ngc`, and `src/emc/rs274ngc/interp_remap.cc` plus `interp_o_word.cc` | Copy unchanged | The upstream duplicate O-word, NGC-only remap failure, M30/remap-level interaction, nested O-word remap, positional-argument remap, G/M remap sequencing, and remap-IO NGC subroutine regressions remain LinuxCNC REMAP/O-word/file or MDI execution tests. The standalone boundary only copies the upstream test files into native or WASM filesystems, reads LinuxCNC INI `SUBROUTINE_PATH`, `REMAP`, and `OWORD_NARGS` entries, and calls vendored `Interp::parse_remap()`, `open()`, `read()`, and `execute()` or feeds the upstream remap-IO MDI sequence into vendored `Interp::execute()`; the continue-on-error runner path only mirrors LinuxCNC `rs274 -n 0` test execution and does not implement duplicate-label, O-word, nested remap, M30, positional-argument, failure, sequencing, M62-M68, M66 input, or remap semantics | Vendor byte sync, `linuxcnc_duplicate_oword_remap_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/browser/verify_interp_browser.sh` |
| LinuxCNC interpreter regression fixtures | `tests/interp/do-while-break/*`, `tests/interp/oword-bug315/*`, `tests/interp/oword-bug315-p2/*`, `tests/interp/exists/*`, `tests/interp/return-value/*`, `tests/interp/subs-follow-main/*`, `tests/interp/fractional-linenumbers/*`, `tests/interp/cam-nisley/*`, `tests/interp/namedparam-bug424/*`, `tests/interp/flowsnake/*`, selected `tests/interp/good/*.ngc` center-format arc tolerance fixtures, `tests/interp/g6164/*`, `tests/interp/inside-corners/*`, `tests/interp/inverse-time-with-comp/*`, selected `tests/ccomp/*` standalone cutter-compensation fixtures, selected `tests/interp/bad/*.ngc` file-error fixtures, `tests/interp/g33.1/*`, selected `tests/interp/g71-*/*` and `tests/interp/g72-*/*` lathe canned-cycle fixtures, `tests/interp/g76/*`, `tests/interp/g10/*`, `tests/interp/g52/g52-g92-interaction/*`, selected `tests/interp/rotation/*` pure interpreter cases, `tests/interp/iniparam/*`, `tests/interp/iniparam-failassign/*`, `tests/interp/m19/*`, `tests/interp/magic_comments/param_format_printing/*`, selected `tests/interp/m98m99/*` pure interpreter cases, `tests/interp/sub-call-from-sub/*`, `tests/interp/sequence-number/*`, `tests/interp/nested-sub-error/*`, `tests/interp/nested-sub-in-file-error/*`, `tests/interp/oword-unwind/*`, `tests/interp/abort-hot-comment/*`, plus vendored interpreter/O-word sources including `interp_o_word.cc`, `interp_read.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_namedparams.cc`, and `rs274ngc_pre.cc` | Copy unchanged | The upstream do/while/break, O-word bug315, `EXISTS[]`, subroutine return-value, subs-after-main, fractional line-number, storm-door latch cam toolpath with upstream tool-table context, named-parameter, recursive O-word flowsnake toolpath, selected center-format arc tolerance acceptance/rejection cases, `G61`/`G64` path-control and naive-cam tolerance behavior, cutter-compensation concave/convex/tangent geometry, inverse-time feed and cutter-compensation interaction, selected standalone cutter-compensation file execution with upstream tool tables, selected file-execution error cases including canned-cycle A-axis rejection, center-format arc radius mismatch rejection, cutter-compensation arc-exit/gouging rejection, and malformed `EXISTS[]`, rigid-tap `G33.1`, G71/G72 lathe canned-cycle iteration behavior, G76 lathe threading with upstream tool-table context, `G10 L1/L10/L11/L2/L20` tool-table/offset/G5X/G92/rotation regressions, G52/G92 shared-offset interaction, selected rotation/G53/G28 absolute-position and endpoint, INI named-parameter lookup/read-only protection, M19 spindle-orient offset/timeout handling, magic-comment parameter formatting, selected Fanuc `M98/M99` call, loop, missing-P-word, missing-subprogram, mixed Fanuc/RS274NGC sub-style, `DISABLE_FANUC_STYLE_SUB`, main-program O-word termination, and O-expression regressions, external-subroutine-call, external-subroutine line-number, nested-subroutine-definition rejection, blocked forward-seek-to-later-numbered-sub, O-word stack unwind after a subroutine error, `(ABORT,...)` hot-comment parameter-expansion regressions, and INI-declared G92 parameter-file startup persistence remain LinuxCNC interpreter file-execution or initialization tests. The standalone boundary only vendors the original upstream assets, copies `*.ngc`, `test.ini`, `test.tbl`, `subs/*.ngc`, referenced external subroutine `.ngc` files, and staged variable files into native or WASM filesystems where applicable, sets the LinuxCNC `INI_FILE_NAME` runtime edge for `_ini[...]`, applies LinuxCNC INI machine settings such as `[RS274NGC]ORIENT_OFFSET`, loads upstream tool tables through LinuxCNC `tooldata_load()`/`Interp::load_tool_table()`, reads LinuxCNC INI `SUBROUTINE_PATH`, passes `[RS274NGC]PARAMETER_FILE` through vendored `ini_load()`/`Interp::init()`/`restore_parameters()` when the staged variable file exists, captures LinuxCNC `(PRINT,...)` output through the existing stdout/Emscripten `print` boundary, and calls vendored `Interp::open()`, `read()`, and `execute()`; it does not implement O-word loop, break, unwind, subroutine, dynamic call, `M98/M99`, `EXISTS[]`, named-parameter, canned-cycle, cutter-compensation, inverse-time feed, recursive O-word or cam toolpath generation, path-control, naive-cam tolerance, arc tolerance, threading, rigid tap, `G10`, G52/G92 offset behavior, G92 persistence, tool-offset, absolute-position named-parameter, G28/G53 endpoint, INI-variable, read-only parameter, line-number, spindle-speed, spindle-orient, magic-comment formatting, subroutine lookup, ABORT hot-comment, error, or branch semantics | Vendor byte sync, `linuxcnc_interp_minimal_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/browser/verify_interp_browser.sh` |

View File

@@ -0,0 +1,215 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include "emc/ini/inifile.hh"
#ifndef LINUXCNC_SOURCE_CONFIG_DIR
#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree"
#endif
namespace {
struct UserMCase {
const char *code;
const char *remap_code;
const char *script_rel;
const char *remap_rel;
const char *state_mode;
const char *guard_pin;
const char *switchkins_target;
const char *active_g5x;
const char *work_offset_pocket;
const char *work_offset_words;
const char *min_limit_key;
const char *max_limit_key;
};
std::string source_config_path(const std::string &rel)
{
return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel;
}
std::string read_text(const std::string &path)
{
std::ifstream input(path);
return std::string(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
bool contains(const std::string &text, const std::string &needle)
{
return text.find(needle) != std::string::npos;
}
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
bool check_ini_value(
const linuxcnc::IniFile &ini,
const std::string &label,
const std::string &section,
const std::string &tag,
const std::string &expected)
{
const auto actual = ini.findString(tag, section);
std::cout << label << "_" << section << "." << tag << "="
<< (actual ? *actual : "<missing>") << "\n";
const bool ok = actual && *actual == expected;
print_bool(label + "_" + section + "." + tag + "_ok", ok);
return ok;
}
bool check_axis_targets(
const linuxcnc::IniFile &ini,
const UserMCase &user_m,
const char *axis,
const char *expected_min,
const char *expected_max,
const char *expected_velocity,
const char *expected_acceleration)
{
const std::string section = std::string("AXIS_") + axis;
const std::string label = std::string(user_m.code) + "_" + axis;
bool ok = true;
ok &= check_ini_value(ini, label, section, user_m.min_limit_key, expected_min);
ok &= check_ini_value(ini, label, section, user_m.max_limit_key, expected_max);
ok &= check_ini_value(ini, label, section, "MAX_VELOCITY", expected_velocity);
ok &= check_ini_value(ini, label, section, "MAX_ACCELERATION", expected_acceleration);
return ok;
}
bool check_script(const UserMCase &user_m)
{
const std::string text = read_text(source_config_path(user_m.script_rel));
bool ok = true;
ok &= contains(text, "#!/usr/bin/tclsh");
ok &= contains(text, "package require Linuxcnc");
ok &= contains(text, "package require Hal");
ok &= contains(text, "parse_ini $::env(INI_FILE_NAME)");
ok &= contains(text, std::string("hal getp ") + user_m.guard_pin);
ok &= contains(text, "hal setp ini.$l.min_limit");
ok &= contains(text, "hal setp ini.$l.max_limit");
ok &= contains(text, "hal setp ini.$l.min_velocity");
ok &= contains(text, "hal setp ini.$l.max_acceleration");
ok &= contains(text, user_m.min_limit_key);
ok &= contains(text, user_m.max_limit_key);
print_bool(std::string(user_m.code) + "_script_tcl_hal_runtime", ok);
return ok;
}
bool check_remap_caller(const UserMCase &user_m)
{
const std::string text = read_text(source_config_path(user_m.remap_rel));
const std::string remap_code(user_m.remap_code);
const bool ok =
contains(text, user_m.code) &&
contains(text, "#<SWITCHKINS_PIN> = 3") &&
contains(text, std::string("#<kinstype> = ") + user_m.switchkins_target) &&
contains(text, "M68") &&
contains(text, "M68 E#<SWITCHKINS_PIN> Q#<kinstype>") &&
contains(text, "M66") &&
contains(text, "M66 E0 L0") &&
contains(text, std::string("G10 L2 ") + user_m.work_offset_pocket + " " + user_m.work_offset_words) &&
contains(text, user_m.active_g5x) &&
contains(text, "#<_hal[motion.switchkins-type]>") &&
contains(text, std::string("[#<_hal[motion.switchkins-type]> NE ") + user_m.switchkins_target + "]");
std::cout << remap_code << "_switchkins_output_pin=motion.analog-out-03\n";
std::cout << remap_code << "_switchkins_target=" << user_m.switchkins_target << "\n";
std::cout << remap_code << "_work_offset_pocket=" << user_m.work_offset_pocket << "\n";
std::cout << remap_code << "_work_offset_words=" << user_m.work_offset_words << "\n";
std::cout << remap_code << "_active_g5x=" << user_m.active_g5x << "\n";
print_bool(remap_code + "_calls_" + user_m.code, contains(text, user_m.code));
print_bool(remap_code + "_source_transition_from_linuxcnc", ok);
print_bool(std::string(user_m.code) + "_remap_calls_user_m_process", ok);
return ok;
}
bool check_user_m_case(const linuxcnc::IniFile &ini, const UserMCase &user_m)
{
bool ok = true;
ok &= check_script(user_m);
ok &= check_remap_caller(user_m);
if (std::string(user_m.code) == "M128") {
ok &= check_axis_targets(ini, user_m, "X", "-300", "300", "60.0", "400.0");
ok &= check_axis_targets(ini, user_m, "Y", "-100", "100", "60.0", "400.0");
ok &= check_axis_targets(ini, user_m, "Z", "-240", "0", "60.0", "400.0");
} else {
ok &= check_axis_targets(ini, user_m, "X", "-240", "0", "60.0", "400.0");
ok &= check_axis_targets(ini, user_m, "Y", "-100", "100", "60.0", "400.0");
ok &= check_axis_targets(ini, user_m, "Z", "-300", "300", "60.0", "400.0");
}
print_bool(std::string(user_m.code) + "_source_state_targets_from_linuxcnc", ok);
return ok;
}
} // namespace
int main()
{
const std::string ini_path = source_config_path("axis/vismach/millturn/millturn.ini");
linuxcnc::IniFile ini(ini_path);
const bool opened = static_cast<bool>(ini);
print_bool("millturn_ini_open", opened);
if (!opened) {
return 1;
}
bool ok = true;
ok &= check_ini_value(ini, "millturn", "RS274NGC", "USER_M_PATH", "./mcodes");
ok &= check_ini_value(ini, "millturn", "RS274NGC", "SUBROUTINE_PATH", "./remap_subs");
ok &= check_ini_value(ini, "millturn", "DISPLAY", "PYVCP", "millturn.xml");
ok &= check_ini_value(ini, "millturn", "HAL", "HALUI", "halui");
ok &= check_ini_value(
ini,
"millturn",
"HAL",
"HALCMD",
"net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type");
const UserMCase cases[] = {
{
"M128",
"M428",
"axis/vismach/millturn/mcodes/M128",
"axis/vismach/millturn/remap_subs/428remap.ngc",
"mill",
"kinstype.is-0",
"0",
"G59.1",
"P7",
"X-290 Y0 Z-160 A0",
"MIN_LIMIT",
"MAX_LIMIT",
},
{
"M129",
"M429",
"axis/vismach/millturn/mcodes/M129",
"axis/vismach/millturn/remap_subs/429remap.ngc",
"turn",
"kinstype.is-1",
"1",
"G59.2",
"P8",
"X-160 Y0 Z-290 A0",
"MIN_LIMIT_TURN",
"MAX_LIMIT_TURN",
},
};
for (const auto &user_m : cases) {
std::cout << user_m.code << "_state_mode=" << user_m.state_mode << "\n";
std::cout << user_m.code << "_guard_pin=" << user_m.guard_pin << "\n";
ok &= check_user_m_case(ini, user_m);
}
print_bool("millturn_user_m_native_source_state_proof", ok);
print_bool("millturn_user_m_execution_enabled", false);
print_bool("millturn_user_m_promotion_allowed", false);
return ok ? 0 : 1;
}

View File

@@ -0,0 +1,189 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#ifndef LINUXCNC_SOURCE_DIR
#error "LINUXCNC_SOURCE_DIR must point at the LinuxCNC source tree"
#endif
#ifndef LINUXCNC_SOURCE_CONFIG_DIR
#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree"
#endif
namespace {
std::string source_path(const std::string &rel)
{
return std::string(LINUXCNC_SOURCE_DIR) + "/" + rel;
}
std::string source_config_path(const std::string &rel)
{
return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel;
}
std::string read_text(const std::string &path)
{
std::ifstream input(path);
return std::string(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
bool contains(const std::string &text, const std::string &needle)
{
return text.find(needle) != std::string::npos;
}
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
bool check_python_runtime_owner()
{
const std::string interp_python = read_text(source_path("src/emc/rs274ngc/interp_python.cc"));
const std::string python_plugin = read_text(source_path("src/emc/pythonplugin/python_plugin.cc"));
const bool pycall_dispatch =
contains(interp_python, "PythonPlugin *python_plugin") &&
contains(interp_python, "Interp::pycall") &&
contains(interp_python, "python_plugin->call(module,funcname");
const bool remap_phases =
contains(interp_python, "PY_PROLOG") &&
contains(interp_python, "PY_BODY") &&
contains(interp_python, "PY_EPILOG");
const bool generator_finish =
contains(interp_python, "PyGen_Check(retval.ptr())") &&
contains(interp_python, "PY_FINISH_PROLOG") &&
contains(interp_python, "PY_FINISH_EPILOG");
const bool callable_lookup =
contains(interp_python, "Interp::is_pycallable") &&
contains(interp_python, "python_plugin->is_callable(module,funcname)");
const bool execute_runtime =
contains(interp_python, "Interp::py_execute") &&
contains(interp_python, "python_plugin->run_string(cmd, retval, as_file)");
const bool initializes_python =
contains(python_plugin, "PyConfig_InitPythonConfig(&config)") &&
contains(python_plugin, "Py_InitializeFromConfig(&config)");
const bool toplevel_exec =
contains(python_plugin, "findString(\"TOPLEVEL\", section)") &&
contains(python_plugin, "bp::exec_file(abs_path, main_namespace, main_namespace)");
const bool ini_python_path =
contains(python_plugin, "findString(n, \"PATH_PREPEND\", \"PYTHON\")") &&
contains(python_plugin, "findString(n, \"PATH_APPEND\", \"PYTHON\")") &&
contains(python_plugin, "PyRun_SimpleString(pycmd)");
const bool callable_invoke =
contains(python_plugin, "PythonPlugin::call") &&
contains(python_plugin, "PyObject_Call(function.ptr(), tupleargs.ptr(), kwargs.ptr())");
const bool reload_on_change =
contains(python_plugin, "PythonPlugin::reload") &&
contains(python_plugin, "reload_on_change");
print_bool("python_runtime_pycall_dispatch", pycall_dispatch);
print_bool("python_runtime_remap_phases", remap_phases);
print_bool("python_runtime_generator_finish", generator_finish);
print_bool("python_runtime_callable_lookup", callable_lookup);
print_bool("python_runtime_execute_runtime", execute_runtime);
print_bool("python_plugin_initializes_python", initializes_python);
print_bool("python_plugin_toplevel_exec_file", toplevel_exec);
print_bool("python_plugin_ini_python_path", ini_python_path);
print_bool("python_plugin_callable_invoke", callable_invoke);
print_bool("python_plugin_reload_on_change", reload_on_change);
return pycall_dispatch && remap_phases && generator_finish && callable_lookup &&
execute_runtime && initializes_python && toplevel_exec && ini_python_path &&
callable_invoke && reload_on_change;
}
bool check_axis_laser_family()
{
const std::string ini = read_text(source_config_path("axis/laser/laser.ini"));
const std::string remap = read_text(source_config_path("axis/laser/python/remap.py"));
const bool ok =
contains(ini, "REMAP= M10 modalgroup=10 python=rasterStop") &&
contains(ini, "REMAP= M11 modalgroup=10 python=rasterBegin") &&
contains(ini, "REMAP= M12 modalgroup=10 python=rasterData") &&
contains(ini, "REMAP= M13 modalgroup=10 python=rasterStart") &&
contains(ini, "TOPLEVEL=python/toplevel.py") &&
contains(ini, "PATH_APPEND=python") &&
contains(remap, "def rasterBegin(self, **words):") &&
contains(remap, "def rasterData(self, **words):") &&
contains(remap, "def rasterStart(self, **words):") &&
contains(remap, "def rasterStop(self, **words):");
print_bool("python_family_axis_laser_inventory", ok);
return ok;
}
bool check_twp_nutating_family()
{
const std::string ini = read_text(source_config_path(
"axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini"));
const std::string remap = read_text(source_config_path(
"axis/vismach/5axis/table-rotary_spindle-rotary-nutating/python/remap.py"));
const bool ok =
contains(ini, "REMAP = G68.2") &&
contains(ini, "python=g682") &&
contains(ini, "REMAP = G68.3") &&
contains(ini, "python=g683") &&
contains(ini, "REMAP = G68.4") &&
contains(ini, "python=g684") &&
contains(ini, "python=g53x_core") &&
contains(ini, "python=g69_core") &&
contains(ini, "PATH_APPEND = ../python") &&
contains(ini, "TOPLEVEL = ../python/toplevel.py") &&
contains(remap, "def g53x_core(self):") &&
contains(remap, "def g69_core(self):") &&
contains(remap, "def g682(self, **words):") &&
contains(remap, "def g683(self, **words):") &&
contains(remap, "def g684(self, **words):");
print_bool("python_family_twp_nutating_inventory", ok);
return ok;
}
bool check_cycle_and_stdglue_families()
{
const std::string cycle_ini = read_text(source_config_path("axis/remap/cycle/cycle.ini"));
const std::string cycle_remap = read_text(source_config_path("axis/remap/cycle/python/remap.py"));
const std::string stdglue = read_text(source_config_path(
"axis/nc_files/remap_lib/python-stdglue/stdglue.py"));
const std::string gmoccapy_stdglue = read_text(source_config_path("gmoccapy/python/stdglue.py"));
const bool cycle_ok =
contains(cycle_ini, "python=g842") &&
contains(cycle_ini, "prolog=cycle_prolog") &&
contains(cycle_ini, "epilog=cycle_epilog") &&
contains(cycle_ini, "PATH_PREPEND=./python") &&
contains(cycle_ini, "PATH_APPEND=../../nc_files/remap_lib/python-stdglue") &&
contains(cycle_remap, "def g842(self,**words):") &&
contains(stdglue, "def cycle_prolog(self,**words):") &&
contains(stdglue, "def cycle_epilog(self,**words):");
const bool gmoccapy_ok =
contains(gmoccapy_stdglue, "def settool_prolog(self,**words):") &&
contains(gmoccapy_stdglue, "def settool_epilog(self,**words):") &&
contains(gmoccapy_stdglue, "def change_prolog(self, **words):") &&
contains(gmoccapy_stdglue, "def change_epilog(self, **words):");
print_bool("python_family_axis_remap_cycle_inventory", cycle_ok);
print_bool("python_family_gmoccapy_stdglue_inventory", gmoccapy_ok);
return cycle_ok && gmoccapy_ok;
}
} // namespace
int main()
{
bool ok = true;
ok &= check_python_runtime_owner();
ok &= check_axis_laser_family();
ok &= check_twp_nutating_family();
ok &= check_cycle_and_stdglue_families();
print_bool("python_remap_native_source_inventory_proof", ok);
print_bool("python_remap_execution_enabled", false);
print_bool("python_remap_promotion_allowed", false);
return ok ? 0 : 1;
}

View File

@@ -0,0 +1,177 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include "emc/ini/inifile.hh"
#ifndef LINUXCNC_SOURCE_DIR
#error "LINUXCNC_SOURCE_DIR must point at the LinuxCNC source tree"
#endif
#ifndef LINUXCNC_SOURCE_CONFIG_DIR
#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree"
#endif
namespace {
std::string source_path(const std::string &rel)
{
return std::string(LINUXCNC_SOURCE_DIR) + "/" + rel;
}
std::string source_config_path(const std::string &rel)
{
return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel;
}
std::string read_text(const std::string &path)
{
std::ifstream input(path);
return std::string(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
bool contains(const std::string &text, const std::string &needle)
{
return text.find(needle) != std::string::npos;
}
void print_bool(const std::string &name, bool value)
{
std::cout << name << "=" << (value ? 1 : 0) << "\n";
}
bool check_ini_value(
const linuxcnc::IniFile &ini,
const std::string &label,
const std::string &section,
const std::string &tag,
const std::string &expected)
{
const auto actual = ini.findString(tag, section);
std::cout << label << "_" << section << "." << tag << "="
<< (actual ? *actual : "<missing>") << "\n";
const bool ok = actual && *actual == expected;
print_bool(label + "_" + section + "." + tag + "_ok", ok);
return ok;
}
bool check_task_owner()
{
const std::string text = read_text(source_path("src/emc/task/taskclass.cc"));
const bool db_init =
contains(text, "findString(\"DB_PROGRAM\", \"EMCIO\")") &&
contains(text, "tooldata_set_db(db_mode)") &&
contains(text, "tooldata_db_init(db_program, random_toolchanger)");
const bool tbl_ignored = contains(text, "DB_PROGRAM active: IGNORING tool table file");
const bool load_unload_notify =
contains(text, "tooldata_db_notify(SPINDLE_UNLOAD") &&
contains(text, "tooldata_db_notify(SPINDLE_LOAD");
print_bool("tool_db_task_db_mode_init", db_init);
print_bool("tool_db_task_ignores_tool_table_with_db_program", tbl_ignored);
print_bool("tool_db_task_load_unload_notify", load_unload_notify);
return db_init && tbl_ignored && load_unload_notify;
}
bool check_tooldata_db_owner()
{
const std::string text = read_text(source_path("src/emc/tooldata/tooldata_db.cc"));
const bool child_process =
contains(text, "pipe2(pipes[PARENT_READ_PIPE]") &&
contains(text, "pipe2(pipes[PARENT_WRITE_PIPE]") &&
contains(text, "fork()") &&
contains(text, "execv(myargv[0], myargv)");
const bool executable_check =
contains(text, "access(child_argv[0],X_OK)") &&
contains(text, "not executable");
const bool version_handshake =
contains(text, "#define DB_VERSION \"v2.1\"") &&
contains(text, "read_reply(reply,sizeof(reply))") &&
contains(text, "strncmp(reply,DB_VERSION");
const bool getall =
contains(text, "send_request((char*)\"g\\n\")") &&
contains(text, "tooldata_reset()") &&
contains(text, "strstr(reply,\"FINI\")") &&
contains(text, "tooldata_read_entry(reply)");
const bool notify =
contains(text, "snprintf(msg,sizeof(msg),\"l %s\\n\",buffer)") &&
contains(text, "snprintf(msg,sizeof(msg),\"u %s\\n\",buffer)") &&
contains(text, "snprintf(msg,sizeof(msg),\"p %s\\n\",buffer)") &&
contains(text, "send_and_verify(msg)");
print_bool("tool_db_child_process_boundary", child_process);
print_bool("tool_db_program_executable_check", executable_check);
print_bool("tool_db_v2_1_handshake", version_handshake);
print_bool("tool_db_getall_g_until_fini", getall);
print_bool("tool_db_notify_l_u_p_protocol", notify);
return child_process && executable_check && version_handshake && getall && notify;
}
bool check_db_program_owner()
{
const std::string text = read_text(source_config_path("axis/db_demo/db.py"));
const bool imports =
contains(text, "from tooldb import tooldb_callbacks") &&
contains(text, "from tooldb import tooldb_tools") &&
contains(text, "from tooldb import tooldb_loop");
const bool callbacks =
contains(text, "def user_get_tool(tno):") &&
contains(text, "def user_put_tool(tno,params):") &&
contains(text, "def user_load_spindle_nonran_tc(tno,params):") &&
contains(text, "def user_unload_spindle_nonran_tc(tno,params):") &&
contains(text, "tooldb_callbacks(user_get_tool") &&
contains(text, "tooldb_tools(toollist)") &&
contains(text, "tooldb_loop()");
const bool state_targets =
contains(text, "db_nonran_savefile = \"/tmp/db_nonran_file\"") &&
contains(text, "toolno_min = 10") &&
contains(text, "toolno_max = 19") &&
contains(text, "pocket_offset = 100") &&
contains(text, "return tno+pocket_offset") &&
contains(text, "D['P'] = \"0\"") &&
contains(text, "nonran_restore_pocket(spindle_tool)") &&
contains(text, "linuxcnc.command().load_tool_table") &&
contains(text, "save_tools_to_file(db_savefile");
const bool reload_rules =
contains(text, "apply_db_rules()") &&
contains(text, "G10L0");
print_bool("tool_db_program_tooldb_module", imports);
print_bool("tool_db_program_nonran_callbacks", callbacks);
print_bool("tool_db_program_nonran_state_targets", state_targets);
print_bool("tool_db_program_reload_rules", reload_rules);
return imports && callbacks && state_targets && reload_rules;
}
} // namespace
int main()
{
const std::string ini_path = source_config_path("axis/db_demo/db_nonran.ini");
const std::string ini_text = read_text(ini_path);
linuxcnc::IniFile ini(ini_path);
const bool opened = static_cast<bool>(ini);
print_bool("db_nonran_ini_open", opened);
if (!opened) {
return 1;
}
bool ok = true;
ok &= check_ini_value(ini, "db_nonran", "EMCIO", "RANDOM_TOOLCHANGER", "0");
ok &= check_ini_value(ini, "db_nonran", "EMCIO", "DB_PROGRAM", "./db_nonran.py");
const bool tool_table_ignored = contains(ini_text, "TOOL_TABLE= is not used with DB_PROGRAM");
print_bool("db_nonran_tool_table_ignored_with_db_program", tool_table_ignored);
ok &= tool_table_ignored;
ok &= check_task_owner();
ok &= check_tooldata_db_owner();
ok &= check_db_program_owner();
print_bool("tool_db_native_source_protocol_proof", ok);
print_bool("tool_db_execution_enabled", false);
print_bool("tool_db_promotion_allowed", false);
return ok ? 0 : 1;
}

View File

@@ -23,6 +23,7 @@ Use `src/index.js` for stable imports:
```js
import {
analyzeIniRuntimeBoundaries,
createLinuxCncIniSdk,
createLinuxCncInterpSdk,
planIniFileContextStaging,
@@ -104,6 +105,20 @@ source manifest text, machine relative path, INI file name, and INI text. It
uses `planIniFileContextStaging()` with a `configs/sim/<machine>` source root
and `configs/sim` upward-search boundary.
`analyzeIniRuntimeBoundaries()` is a host-boundary classifier for LinuxCNC
INI-driven runs. It reads INI text plus optional execution text and manifest
text, then reports declared HAL, UI, HALUI MDI, Python, tool-database, and
external user-M process dependencies. User-M accounting is per execution code:
`executionCodes` lists `M100..M199` codes seen in the supplied execution text,
while `unstagedExecutionCodes` lists the subset not backed by vendored
`USER_M_PATH` files. Python accounting keeps UI/DB references separate from
Python remap runtime references, so a UI handler or DB program does not imply
Python-remap coverage. It also returns the currently recommended Layer 4
blocked kind for hard process boundaries such as `L4-TOOL-DB` and
`L4-USER-M-PROCESS`. The classifier is policy/accounting only: it does not
execute HAL, task, UI, Python, user-M, or tool-database behavior and does not
change interpreter semantics.
`runFileWithIniContinueOnError()` uses the same LinuxCNC-backed file execution
path but keeps the runner loop going after LinuxCNC reports an error, matching
upstream `rs274 -n 0` regression tests such as `tests/interp/oword-unwind`.

View File

@@ -1,6 +1,7 @@
export { createLinuxCncIniSdk } from "./linuxcnc-ini.js";
export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js";
export {
analyzeIniRuntimeBoundaries,
planIniFileContextStaging,
planSimConfigStaging,
} from "./sim-config-staging.js";

View File

@@ -172,6 +172,197 @@ function remapNgcNames(iniValues) {
return names;
}
function sectionValues(iniValues, section) {
const prefix = `${section.toUpperCase()}.`;
const values = [];
for (const [key, entries] of iniValues.entries()) {
if (!key.startsWith(prefix)) {
continue;
}
for (const value of entries) {
values.push({ key: key.slice(prefix.length), value });
}
}
return values;
}
function valuesMatching(iniValues, section, keys) {
const wanted = new Set(keys.map((key) => key.toUpperCase()));
return sectionValues(iniValues, section)
.filter((entry) => wanted.has(entry.key))
.map((entry) => entry.value);
}
function looksLikePythonReference(value) {
return /(^|\s|=|:)["']?[^"'\s]*\.py(["'\s]|$)/i.test(value);
}
function userMCodesInText(text) {
const codes = new Set();
for (const match of text.matchAll(/(?<![A-Za-z0-9_])M\s*(1\d\d)(?![0-9])/gi)) {
codes.add(`M${match[1]}`);
}
return [...codes].sort();
}
function vendoredUserMCodes({
manifestEntries,
sourceDir,
normalizedSearchRoot,
userMPathValues,
}) {
const manifestSet = new Set(manifestEntries);
const executableCodes = new Set();
for (const dirEntry of userMPathValues.flatMap(splitSearchPath)) {
if (dirEntry.startsWith("/")) {
continue;
}
const sourceUserMDir = normalizeRel(`${sourceDir}/${dirEntry}`);
const prefix = sourceUserMDir ? `${sourceUserMDir}/` : "";
for (const sourceRel of manifestEntries) {
if (
sourceRel.startsWith(prefix) &&
!sourceRel.slice(prefix.length).includes("/") &&
isUserMCodePath(sourceRel)
) {
executableCodes.add(basename(sourceRel).toUpperCase());
}
}
}
for (const dirEntry of userMPathValues.flatMap(splitSearchPath)) {
if (dirEntry.startsWith("/")) {
continue;
}
const sourceUserMDir = normalizeRel(`${sourceDir}/${dirEntry}`);
for (let code = 100; code <= 199; code += 1) {
const candidate = findUpwardByBasename(
manifestSet,
sourceUserMDir,
`M${code}`,
normalizedSearchRoot,
);
if (candidate) {
executableCodes.add(`M${code}`);
}
}
}
return [...executableCodes].sort();
}
export function analyzeIniRuntimeBoundaries({
manifestText = "",
sourceRootRel,
sourceSearchRootRel = sourceRootRel,
iniFile = "",
iniText,
executionTexts = [],
}) {
const manifestEntries = cleanManifest(manifestText);
const iniValues = parseIni(iniText);
const normalizedSourceRoot = normalizeRel(sourceRootRel);
const normalizedSearchRoot = normalizeRel(sourceSearchRootRel);
const sourceDir = normalizeRel(`${normalizedSourceRoot}/${dirname(iniFile)}`);
const userMPathValues = allIniValues(iniValues, "RS274NGC", "USER_M_PATH");
const halValues = valuesMatching(iniValues, "HAL", [
"HALFILE",
"HALCMD",
"POSTGUI_HALFILE",
"HALUI",
]);
const displayValues = valuesMatching(iniValues, "DISPLAY", [
"DISPLAY",
"PYVCP",
"GLADEVCP",
"EMBED_TAB_COMMAND",
]);
const halUiMdiCommands = allIniValues(iniValues, "HALUI", "MDI_COMMAND");
const dbProgram = firstIniValue(iniValues, "EMCIO", "DB_PROGRAM");
const remapValues = allIniValues(iniValues, "RS274NGC", "REMAP");
const pythonRemapReferences = [
...sectionValues(iniValues, "PYTHON").map((entry) => entry.value),
...remapValues.filter((value) => /(?:^|\s)python=/i.test(value)),
];
const pythonUiReferences = [
...displayValues.filter(looksLikePythonReference),
...(dbProgram && looksLikePythonReference(dbProgram) ? [dbProgram] : []),
];
const pythonReferences = [...pythonRemapReferences, ...pythonUiReferences];
const vendoredUserMCodeList = vendoredUserMCodes({
manifestEntries,
sourceDir,
normalizedSearchRoot,
userMPathValues,
});
const vendoredUserMCodeSet = new Set(vendoredUserMCodeList);
const hasUserMPath = userMPathValues.length > 0;
const executionUserMCodes = [...new Set(executionTexts.flatMap(userMCodesInText))].sort();
const unstagedExecutionUserMCodes = executionUserMCodes
.filter((code) => !vendoredUserMCodeSet.has(code));
const hasExternalUserMUse = hasUserMPath && unstagedExecutionUserMCodes.length > 0;
const dependencies = [];
if (dbProgram) {
dependencies.push("tool_database_process");
}
if (halValues.length > 0) {
dependencies.push("hal_process");
}
if (displayValues.some((value) => !/^axis$/i.test(value))) {
dependencies.push("ui_process");
}
if (halUiMdiCommands.length > 0) {
dependencies.push("halui_mdi_process");
}
if (pythonReferences.length > 0) {
dependencies.push("python_runtime");
}
if (hasExternalUserMUse) {
dependencies.push("external_user_m_process");
}
let recommendedBlockedKind = "-";
if (dbProgram) {
recommendedBlockedKind = "L4-TOOL-DB";
} else if (hasExternalUserMUse) {
recommendedBlockedKind = "L4-USER-M-PROCESS";
} else if (pythonRemapReferences.length > 0) {
recommendedBlockedKind = "L4-PYTHON-REMAP";
}
return {
dependencies: [...new Set(dependencies)].sort(),
recommendedBlockedKind,
toolDatabaseProgram: dbProgram ?? "",
halRuntime: {
values: halValues,
requiresProcess: halValues.length > 0,
},
uiRuntime: {
values: displayValues,
requiresProcess: displayValues.some((value) => !/^axis$/i.test(value)),
},
haluiRuntime: {
mdiCommands: halUiMdiCommands,
requiresProcess: halUiMdiCommands.length > 0,
},
userMRuntime: {
paths: userMPathValues,
vendoredExecutableCount: vendoredUserMCodeList.length,
executionCodes: executionUserMCodes,
unstagedExecutionCodes: unstagedExecutionUserMCodes,
requiresExternalProcess: hasExternalUserMUse,
},
pythonRuntime: {
references: pythonReferences,
remapReferences: pythonRemapReferences,
uiReferences: pythonUiReferences,
requiresProcess: pythonReferences.length > 0,
},
};
}
export function planSimConfigStaging({
manifestText,
machineRel,

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,33 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
CHROMIUM="${CHROMIUM:-$(command -v chromium || command -v chromium-browser || command -v google-chrome || command -v google-chrome-stable || true)}"
BOUNDARY_PROOF_GATES="$ROOT_DIR/build/wasm/sim-configs-inventory/boundary-proof-gates.tsv"
BOUNDARY_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/boundary-summary.tsv"
INI_BOUNDARY_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"
NATIVE_PROOF_ALIGNMENT_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/native-proof-alignment-summary.tsv"
NATIVE_RUNTIME_PROBE_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/native-runtime-probe-summary.tsv"
RUNTIME_BOUNDARY_NATIVE_ALIGNMENT_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/runtime-boundary-native-alignment-summary.tsv"
RUNTIME_BOUNDARY_CONTRACT_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/runtime-boundary-contract-summary.tsv"
USER_M_PROCESS_NATIVE_STATE_ALIGNMENT="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-native-state-alignment.tsv"
USER_M_PROCESS_NATIVE_TRANSITION_ALIGNMENT="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-native-transition-alignment.tsv"
USER_M_PROCESS_NATIVE_RUNTIME_STATE_PLAN="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-native-runtime-state-plan.tsv"
USER_M_PROCESS_NATIVE_RUNTIME_READINESS="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-native-runtime-readiness.tsv"
USER_M_PROCESS_NATIVE_RUNTIME_PROBE_GATE="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-native-runtime-probe-gate.tsv"
USER_M_PROCESS_TRANSITION_PLAN="$ROOT_DIR/build/wasm/sim-configs-inventory/user-m-process-transition-plan.tsv"
TOOL_DB_PROCESS_NATIVE_PROTOCOL_ALIGNMENT="$ROOT_DIR/build/wasm/sim-configs-inventory/tool-db-process-native-protocol-alignment.tsv"
TOOL_DB_PROCESS_NATIVE_RUNTIME_READINESS="$ROOT_DIR/build/wasm/sim-configs-inventory/tool-db-process-native-runtime-readiness.tsv"
TOOL_DB_PROCESS_TRANSACTION_PLAN="$ROOT_DIR/build/wasm/sim-configs-inventory/tool-db-process-transaction-plan.tsv"
PYTHON_REMAP_NATIVE_RUNTIME_ALIGNMENT="$ROOT_DIR/build/wasm/sim-configs-inventory/python-remap-native-runtime-alignment.tsv"
PYTHON_REMAP_NATIVE_RUNTIME_READINESS="$ROOT_DIR/build/wasm/sim-configs-inventory/python-remap-native-runtime-readiness.tsv"
PYTHON_REMAP_NATIVE_RUNTIME_STATE_PLAN="$ROOT_DIR/build/wasm/sim-configs-inventory/python-remap-native-runtime-state-plan.tsv"
PYTHON_REMAP_NATIVE_RUNTIME_FIXTURE_PLAN="$ROOT_DIR/build/wasm/sim-configs-inventory/python-remap-native-runtime-fixture-plan.tsv"
PYTHON_REMAP_RUNTIME_CONTRACT="$ROOT_DIR/build/wasm/sim-configs-inventory/python-remap-runtime-contract.tsv"
BLOCKED_RUNTIME_PROMOTION_LOCK="$ROOT_DIR/build/wasm/sim-configs-inventory/blocked-runtime-promotion-lock.tsv"
BOUNDARY_PHASE_COMPLETION_SUMMARY="$ROOT_DIR/build/wasm/sim-configs-inventory/boundary-phase-completion-summary.tsv"
NEXT_BOUNDARY_RECOMMENDATIONS="$ROOT_DIR/build/wasm/sim-configs-inventory/next-boundary-recommendations.tsv"
INVENTORY_SCRIPT="$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs"
NATIVE_SOURCE_PROOF_SUMMARY="$ROOT_DIR/build/native/native-source-proof-summary.tsv"
NATIVE_RUNTIME_PROBE_SOURCE_SUMMARY="$ROOT_DIR/build/native/native-runtime-probe-summary.tsv"
if [[ -z "$CHROMIUM" ]]; then
echo "missing Chromium-compatible browser; set CHROMIUM=/path/to/browser" >&2
@@ -15,6 +42,45 @@ fi
if [[ "${SKIP_INI_BUILD:-0}" != "1" ]]; then
"$ROOT_DIR/tools/build_ini_panel.sh"
fi
INVENTORY_REQUIRED=0
for artifact in \
"$BOUNDARY_PROOF_GATES" \
"$BOUNDARY_SUMMARY" \
"$INI_BOUNDARY_SUMMARY" \
"$NATIVE_PROOF_ALIGNMENT_SUMMARY" \
"$RUNTIME_BOUNDARY_NATIVE_ALIGNMENT_SUMMARY" \
"$RUNTIME_BOUNDARY_CONTRACT_SUMMARY" \
"$USER_M_PROCESS_NATIVE_STATE_ALIGNMENT" \
"$USER_M_PROCESS_NATIVE_TRANSITION_ALIGNMENT" \
"$USER_M_PROCESS_NATIVE_RUNTIME_STATE_PLAN" \
"$USER_M_PROCESS_NATIVE_RUNTIME_READINESS" \
"$USER_M_PROCESS_NATIVE_RUNTIME_PROBE_GATE" \
"$USER_M_PROCESS_TRANSITION_PLAN" \
"$TOOL_DB_PROCESS_NATIVE_PROTOCOL_ALIGNMENT" \
"$TOOL_DB_PROCESS_NATIVE_RUNTIME_READINESS" \
"$TOOL_DB_PROCESS_TRANSACTION_PLAN" \
"$PYTHON_REMAP_NATIVE_RUNTIME_ALIGNMENT" \
"$PYTHON_REMAP_NATIVE_RUNTIME_READINESS" \
"$PYTHON_REMAP_NATIVE_RUNTIME_STATE_PLAN" \
"$PYTHON_REMAP_NATIVE_RUNTIME_FIXTURE_PLAN" \
"$PYTHON_REMAP_RUNTIME_CONTRACT" \
"$NATIVE_RUNTIME_PROBE_SUMMARY" \
"$BLOCKED_RUNTIME_PROMOTION_LOCK" \
"$BOUNDARY_PHASE_COMPLETION_SUMMARY" \
"$NEXT_BOUNDARY_RECOMMENDATIONS"; do
if [[ ! -f "$artifact" || "$INVENTORY_SCRIPT" -nt "$artifact" ]]; then
INVENTORY_REQUIRED=1
fi
done
if [[ -f "$NATIVE_SOURCE_PROOF_SUMMARY" && "$NATIVE_SOURCE_PROOF_SUMMARY" -nt "$NATIVE_PROOF_ALIGNMENT_SUMMARY" ]]; then
INVENTORY_REQUIRED=1
fi
if [[ -f "$NATIVE_RUNTIME_PROBE_SOURCE_SUMMARY" && "$NATIVE_RUNTIME_PROBE_SOURCE_SUMMARY" -nt "$NATIVE_RUNTIME_PROBE_SUMMARY" ]]; then
INVENTORY_REQUIRED=1
fi
if [[ "$INVENTORY_REQUIRED" == "1" ]]; then
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.sh"
fi
TMP_DIR="$(mktemp -d)"
PORT_FILE="$TMP_DIR/port"

View File

@@ -9,6 +9,7 @@ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
SKIP_INI_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_ini_wasm.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_interp_wasm.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_sim_configs_wasm.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.sh"
SKIP_INTERP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_nc_files_wasm.sh"
SKIP_TP_BUILD=1 "$ROOT_DIR/tests/wasm/node/verify_tp_wasm.sh"
"$ROOT_DIR/tests/opfs/node/verify_file_service.sh"

View File

@@ -0,0 +1,202 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
MACHINE_DIR="$LINUXCNC_ROOT/configs/sim/axis/vismach/millturn"
INI_FILE="$MACHINE_DIR/millturn.ini"
RUN_DIR="$ROOT_DIR/build/native/millturn-user-m-runtime"
LINUXCNC_STDOUT="$RUN_DIR/linuxcnc.stdout.log"
LINUXCNC_STDERR="$RUN_DIR/linuxcnc.stderr.log"
required_commands=(tclsh halrun halcmd linuxcnc)
missing_commands=()
LINUXCNC_PID=""
cleanup() {
if [[ -n "$LINUXCNC_PID" ]]; then
kill "$LINUXCNC_PID" 2>/dev/null || true
wait "$LINUXCNC_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
command_path() {
command -v "$1" 2>/dev/null || true
}
csv_join() {
local IFS=,
printf '%s' "$*"
}
print_kv() {
printf '%s=%s\n' "$1" "$2"
}
runtime_requirements=()
for command_name in "${required_commands[@]}"; do
path="$(command_path "$command_name")"
if [[ -n "$path" ]]; then
runtime_requirements+=("$command_name:1")
print_kv "millturn_user_m_runtime_${command_name}_path" "$path"
else
runtime_requirements+=("$command_name:0")
missing_commands+=("$command_name")
fi
done
source_ready=1
for rel in \
millturn.ini \
mcodes/M128 \
mcodes/M129 \
remap_subs/428remap.ngc \
remap_subs/429remap.ngc; do
if [[ ! -f "$MACHINE_DIR/$rel" ]]; then
source_ready=0
print_kv "millturn_user_m_missing_source_${rel//[^A-Za-z0-9]/_}" "$MACHINE_DIR/$rel"
fi
done
runtime_ready=0
if [[ "${#missing_commands[@]}" -eq 0 ]]; then
runtime_ready=1
fi
print_kv millturn_user_m_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
if [[ "${#missing_commands[@]}" -eq 0 ]]; then
print_kv millturn_user_m_missing_requirements "-"
else
print_kv millturn_user_m_missing_requirements "$(csv_join "${missing_commands[@]}")"
fi
print_kv millturn_user_m_source_proof_ready "$source_ready"
print_kv millturn_user_m_runtime_ready "$runtime_ready"
print_kv millturn_user_m_execution_enabled 0
print_kv millturn_user_m_promotion_allowed 0
if [[ "$source_ready" != "1" ]]; then
print_kv millturn_user_m_runtime_probe_status "blocked_missing_source"
exit 0
fi
if [[ "$runtime_ready" != "1" ]]; then
print_kv millturn_user_m_runtime_probe_status "skipped_missing_host_runtime"
exit 0
fi
if [[ "${ENABLE_MILLTURN_USER_M_RUNTIME_PROBE:-0}" != "1" ]]; then
print_kv millturn_user_m_runtime_probe_status "ready_disabled_by_default"
print_kv millturn_user_m_runtime_probe_note "set_ENABLE_MILLTURN_USER_M_RUNTIME_PROBE_1_to_run_full_process_probe"
exit 0
fi
mkdir -p "$RUN_DIR"
wait_for_hal_pin() {
local pin="$1"
local limit="${MILLTURN_USER_M_RUNTIME_WAIT_SECONDS:-30}"
local end=$((SECONDS + limit))
while (( SECONDS < end )); do
if halcmd getp "$pin" >/dev/null 2>&1; then
return 0
fi
sleep 0.25
done
return 1
}
read_hal_pin() {
halcmd getp "$1" 2>/dev/null | tr -d '[:space:]'
}
expect_hal_pin() {
local label="$1"
local pin="$2"
local expected="$3"
local actual
actual="$(read_hal_pin "$pin")"
print_kv "millturn_user_m_${label}_${pin//[^A-Za-z0-9]/_}" "$actual"
[[ "$actual" == "$expected" ]]
}
set_switchkins_target() {
local target="$1"
local guard_pin="kinstype.is-$target"
if ! halcmd setp motion.switchkins-type "$target" >/dev/null 2>&1; then
halcmd unlinkp motion.switchkins-type >/dev/null 2>&1 || true
halcmd setp motion.switchkins-type "$target"
fi
for _ in $(seq 1 40); do
if [[ "$(read_hal_pin "$guard_pin")" =~ ^(TRUE|1)$ ]]; then
return 0
fi
sleep 0.05
done
return 1
}
run_user_m_case() {
local code="$1"
local mode="$2"
local switchkins_target="$3"
local expected_x_min="$4"
local expected_x_max="$5"
local expected_y_min="$6"
local expected_y_max="$7"
local expected_z_min="$8"
local expected_z_max="$9"
print_kv "millturn_user_m_${code}_runtime_mode" "$mode"
if ! set_switchkins_target "$switchkins_target"; then
print_kv "millturn_user_m_${code}_switchkins_target_ready" 0
return 1
fi
print_kv "millturn_user_m_${code}_switchkins_target_ready" 1
INI_FILE_NAME="$INI_FILE" "$MACHINE_DIR/mcodes/$code"
local ok=1
expect_hal_pin "${code}" ini.x.min_limit "$expected_x_min" || ok=0
expect_hal_pin "${code}" ini.x.max_limit "$expected_x_max" || ok=0
expect_hal_pin "${code}" ini.y.min_limit "$expected_y_min" || ok=0
expect_hal_pin "${code}" ini.y.max_limit "$expected_y_max" || ok=0
expect_hal_pin "${code}" ini.z.min_limit "$expected_z_min" || ok=0
expect_hal_pin "${code}" ini.z.max_limit "$expected_z_max" || ok=0
expect_hal_pin "${code}" ini.x.max_velocity "60" || ok=0
expect_hal_pin "${code}" ini.y.max_velocity "60" || ok=0
expect_hal_pin "${code}" ini.z.max_velocity "60" || ok=0
expect_hal_pin "${code}" ini.x.max_acceleration "400" || ok=0
expect_hal_pin "${code}" ini.y.max_acceleration "400" || ok=0
expect_hal_pin "${code}" ini.z.max_acceleration "400" || ok=0
print_kv "millturn_user_m_${code}_runtime_state_ok" "$ok"
[[ "$ok" == "1" ]]
}
print_kv millturn_user_m_runtime_probe_ini "$INI_FILE"
print_kv millturn_user_m_runtime_probe_linuxcnc_stdout "$LINUXCNC_STDOUT"
print_kv millturn_user_m_runtime_probe_linuxcnc_stderr "$LINUXCNC_STDERR"
linuxcnc -r "$INI_FILE" >"$LINUXCNC_STDOUT" 2>"$LINUXCNC_STDERR" &
LINUXCNC_PID="$!"
if ! wait_for_hal_pin ini.x.min_limit || ! wait_for_hal_pin motion.switchkins-type; then
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_failed"
print_kv millturn_user_m_runtime_probe_note "linuxcnc_started_but_required_hal_pins_did_not_appear"
exit 1
fi
probe_ok=1
run_user_m_case M128 mill 0 -300 300 -100 100 -240 0 || probe_ok=0
run_user_m_case M129 turn 1 -240 0 -100 100 -300 300 || probe_ok=0
if [[ "$probe_ok" == "1" ]]; then
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_passed"
print_kv millturn_user_m_runtime_probe_note "linuxcnc_owned_M128_M129_tcl_hal_state_probe_passed_without_promotion"
exit 0
fi
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_failed"
print_kv millturn_user_m_runtime_probe_note "linuxcnc_owned_M128_M129_tcl_hal_state_probe_failed"
exit 1

View File

@@ -0,0 +1,189 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
FIXTURE_FAMILY="axis/remap/stop-lookahead/nc_files"
FIXTURE_DIR="$LINUXCNC_ROOT/configs/sim/axis/remap/stop-lookahead"
FIXTURE_INI="$FIXTURE_DIR/demo.ini"
RUN_DIR="$ROOT_DIR/build/native/python-remap-runtime"
PYTHON_RUNTIME_STDOUT="$RUN_DIR/python_lifecycle.stdout.log"
PYTHON_RUNTIME_STDERR="$RUN_DIR/python_lifecycle.stderr.log"
required_commands=(python3 linuxcnc)
missing_requirements=()
command_path() {
command -v "$1" 2>/dev/null || true
}
csv_join() {
local IFS=,
printf '%s' "$*"
}
print_kv() {
printf '%s=%s\n' "$1" "$2"
}
runtime_requirements=()
for command_name in "${required_commands[@]}"; do
path="$(command_path "$command_name")"
if [[ -n "$path" ]]; then
runtime_requirements+=("$command_name:1")
print_kv "python_remap_runtime_${command_name}_path" "$path"
else
runtime_requirements+=("$command_name:0")
missing_requirements+=("$command_name")
fi
done
source_ready=1
for rel in \
src/emc/rs274ngc/interp_python.cc \
src/emc/pythonplugin/python_plugin.cc \
configs/sim/axis/remap/stop-lookahead/demo.ini \
configs/sim/axis/remap/stop-lookahead/python/remap.py \
configs/sim/axis/remap/stop-lookahead/python/toplevel.py; do
if [[ ! -f "$LINUXCNC_ROOT/$rel" ]]; then
source_ready=0
missing_requirements+=("$rel")
print_kv "python_remap_missing_source_${rel//[^A-Za-z0-9]/_}" "$LINUXCNC_ROOT/$rel"
fi
done
runtime_ready=0
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
runtime_ready=1
fi
print_kv python_remap_runtime_fixture_family "$FIXTURE_FAMILY"
print_kv python_remap_runtime_fixture_id "stop_lookahead_python_runtime_lifecycle"
print_kv python_remap_runtime_fixture_scope "no_python_callables_no_ngc_only_subpaths"
print_kv python_remap_runtime_phases "initialize_python,apply_ini_python_path,execute_toplevel,callable_lookup,pycall_dispatch,callable_invoke,remap_phase_dispatch,generator_finish,execute_python_runtime,reload_on_change"
print_kv python_remap_runtime_modules "axis/remap/stop-lookahead/python/remap.py,axis/remap/stop-lookahead/python/toplevel.py"
print_kv python_remap_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
print_kv python_remap_missing_requirements "-"
else
print_kv python_remap_missing_requirements "$(csv_join "${missing_requirements[@]}")"
fi
print_kv python_remap_source_proof_ready "$source_ready"
print_kv python_remap_runtime_ready "$runtime_ready"
print_kv python_remap_execution_enabled 0
print_kv python_remap_promotion_allowed 0
if [[ "$source_ready" != "1" ]]; then
print_kv python_remap_runtime_probe_status "blocked_missing_source"
exit 0
fi
if [[ "$runtime_ready" != "1" ]]; then
print_kv python_remap_runtime_probe_status "skipped_missing_host_runtime"
exit 0
fi
if [[ "${ENABLE_PYTHON_REMAP_RUNTIME_PROBE:-0}" != "1" ]]; then
print_kv python_remap_runtime_probe_status "ready_disabled_by_default"
print_kv python_remap_runtime_probe_note "set_ENABLE_PYTHON_REMAP_RUNTIME_PROBE_1_to_run_python_lifecycle_probe"
exit 0
fi
mkdir -p "$RUN_DIR"
rm -f "$PYTHON_RUNTIME_STDOUT" "$PYTHON_RUNTIME_STDERR"
print_kv python_remap_runtime_probe_fixture "$FIXTURE_DIR"
print_kv python_remap_runtime_probe_ini "$FIXTURE_INI"
print_kv python_remap_runtime_probe_stdout "$PYTHON_RUNTIME_STDOUT"
print_kv python_remap_runtime_probe_stderr "$PYTHON_RUNTIME_STDERR"
if python3 - "$LINUXCNC_ROOT" "$FIXTURE_DIR" "$FIXTURE_INI" "$RUN_DIR" \
>"$PYTHON_RUNTIME_STDOUT" 2>"$PYTHON_RUNTIME_STDERR" <<'PY'
import configparser
import importlib
import inspect
import os
from pathlib import Path
import re
import sys
import tempfile
linuxcnc_root = Path(sys.argv[1])
fixture_dir = Path(sys.argv[2])
fixture_ini = Path(sys.argv[3])
run_dir = Path(sys.argv[4])
def emit(name, value):
print(f"{name}={value}")
def require(condition, message):
if not condition:
raise RuntimeError(message)
interp_return = linuxcnc_root / "src/emc/nml_intf/interp_return.hh"
match = re.search(
r"INTERP_EXECUTE_FINISH\s*=\s*([0-9]+)",
interp_return.read_text(encoding="utf-8"),
)
require(match, "missing_INTERP_EXECUTE_FINISH_source_value")
execute_finish = int(match.group(1))
emit("python_remap_lifecycle_execute_finish_source_value", execute_finish)
stub_dir = Path(tempfile.mkdtemp(prefix="python-remap-interpreter-", dir=run_dir))
(stub_dir / "interpreter.py").write_text(
f"INTERP_EXECUTE_FINISH = {execute_finish}\n",
encoding="utf-8",
)
parser = configparser.ConfigParser(strict=False)
parser.optionxform = str
parser.read(fixture_ini)
require(parser.has_section("PYTHON"), "missing_PYTHON_section")
path_prepend = parser.get("PYTHON", "PATH_PREPEND", fallback="")
toplevel = parser.get("PYTHON", "TOPLEVEL", fallback="")
require(path_prepend == "python", f"PATH_PREPEND_drift:{path_prepend}")
require(toplevel == "python/toplevel.py", f"TOPLEVEL_drift:{toplevel}")
emit("python_remap_lifecycle_ini_path_prepend", path_prepend)
emit("python_remap_lifecycle_ini_toplevel", toplevel)
sys.path.insert(0, str(stub_dir))
sys.path.insert(0, str(fixture_dir / path_prepend))
sys.path.insert(0, str(linuxcnc_root / "lib/python"))
import interpreter # noqa: E402
require(interpreter.INTERP_EXECUTE_FINISH == execute_finish, "interpreter_sentinel_drift")
emit("python_remap_lifecycle_interpreter_sentinel_ok", 1)
toplevel_module = importlib.import_module(Path(toplevel).stem)
emit("python_remap_lifecycle_toplevel_imported", int(toplevel_module.__name__ == "toplevel"))
remap_module = importlib.import_module("remap")
emit("python_remap_lifecycle_remap_imported", int(remap_module.__name__ == "remap"))
require(hasattr(remap_module, "queuebuster"), "missing_queuebuster_callable")
require(callable(remap_module.queuebuster), "queuebuster_not_callable")
emit("python_remap_lifecycle_callable_lookup_ok", 1)
result = remap_module.queuebuster(object())
require(inspect.isgenerator(result), "queuebuster_not_generator")
emit("python_remap_lifecycle_generator_returned", 1)
first_yield = next(result)
require(first_yield == execute_finish, f"queuebuster_yield_drift:{first_yield}")
emit("python_remap_lifecycle_generator_first_yield", first_yield)
try:
next(result)
raise RuntimeError("queuebuster_generator_did_not_finish")
except StopIteration:
emit("python_remap_lifecycle_generator_finish_ok", 1)
emit("python_remap_runtime_lifecycle_probe_ok", 1)
PY
then
cat "$PYTHON_RUNTIME_STDOUT"
print_kv python_remap_runtime_probe_status "runtime_lifecycle_probe_passed"
print_kv python_remap_runtime_probe_note "linuxcnc_stop_lookahead_python_lifecycle_probe_passed_without_promotion"
exit 0
fi
cat "$PYTHON_RUNTIME_STDOUT" || true
print_kv python_remap_runtime_probe_status "runtime_lifecycle_probe_failed"
print_kv python_remap_runtime_probe_note "linuxcnc_stop_lookahead_python_lifecycle_probe_failed"
exit 1

View File

@@ -0,0 +1,232 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
DB_DEMO_DIR="$LINUXCNC_ROOT/configs/sim/axis/db_demo"
DB_PROGRAM="$DB_DEMO_DIR/db_nonran.py"
RUN_DIR="$ROOT_DIR/build/native/tool-db-runtime"
DB_SAVEFILE="$RUN_DIR/db_nonran_probe"
DB_STDOUT="$RUN_DIR/db_program.stdout.log"
DB_STDERR="$RUN_DIR/db_program.stderr.log"
required_commands=(python3 linuxcnc milltask halcmd)
missing_requirements=()
command_path() {
command -v "$1" 2>/dev/null || true
}
csv_join() {
local IFS=,
printf '%s' "$*"
}
print_kv() {
printf '%s=%s\n' "$1" "$2"
}
runtime_requirements=()
for command_name in "${required_commands[@]}"; do
path="$(command_path "$command_name")"
if [[ -n "$path" ]]; then
runtime_requirements+=("$command_name:1")
print_kv "tool_db_runtime_${command_name}_path" "$path"
else
runtime_requirements+=("$command_name:0")
missing_requirements+=("$command_name")
fi
done
source_ready=1
for rel in \
configs/sim/axis/db_demo/db_nonran.ini \
configs/sim/axis/db_demo/db.py \
lib/python/tooldb.py \
lib/python/linuxcnc.so; do
if [[ ! -e "$LINUXCNC_ROOT/$rel" ]]; then
source_ready=0
missing_requirements+=("$rel")
print_kv "tool_db_missing_source_${rel//[^A-Za-z0-9]/_}" "$LINUXCNC_ROOT/$rel"
fi
done
if [[ ! -x "$DB_PROGRAM" ]]; then
source_ready=0
missing_requirements+=("configs/sim/axis/db_demo/db_nonran.py:executable")
fi
runtime_ready=0
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
runtime_ready=1
fi
print_kv tool_db_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
print_kv tool_db_missing_requirements "-"
else
print_kv tool_db_missing_requirements "$(csv_join "${missing_requirements[@]}")"
fi
print_kv tool_db_source_proof_ready "$source_ready"
print_kv tool_db_runtime_ready "$runtime_ready"
print_kv tool_db_execution_enabled 0
print_kv tool_db_promotion_allowed 0
if [[ "$source_ready" != "1" ]]; then
print_kv tool_db_runtime_probe_status "blocked_missing_source"
exit 0
fi
if [[ "$runtime_ready" != "1" ]]; then
print_kv tool_db_runtime_probe_status "skipped_missing_host_runtime"
exit 0
fi
if [[ "${ENABLE_TOOL_DB_RUNTIME_PROBE:-0}" != "1" ]]; then
print_kv tool_db_runtime_probe_status "ready_disabled_by_default"
print_kv tool_db_runtime_probe_note "set_ENABLE_TOOL_DB_RUNTIME_PROBE_1_to_run_db_protocol_probe"
exit 0
fi
mkdir -p "$RUN_DIR"
rm -f "$DB_SAVEFILE" "$DB_STDOUT" "$DB_STDERR"
print_kv tool_db_runtime_probe_program "$DB_PROGRAM"
print_kv tool_db_runtime_probe_db_savefile "$DB_SAVEFILE"
print_kv tool_db_runtime_probe_stdout "$DB_STDOUT"
print_kv tool_db_runtime_probe_stderr "$DB_STDERR"
if python3 - "$DB_PROGRAM" "$DB_DEMO_DIR" "$LINUXCNC_ROOT/lib/python" "$DB_SAVEFILE" "$DB_STDOUT" "$DB_STDERR" <<'PY'
import os
import select
import subprocess
import sys
import time
db_program, db_demo_dir, python_path, db_savefile, stdout_log, stderr_log = sys.argv[1:]
env = os.environ.copy()
env["PYTHONPATH"] = python_path + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
stdout_file = open(stdout_log, "w", encoding="utf-8")
stderr_file = open(stderr_log, "w", encoding="utf-8")
proc = subprocess.Popen(
[db_program, "--period_minutes=999", db_savefile],
cwd=db_demo_dir,
env=env,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=stderr_file,
text=True,
bufsize=1,
)
def emit(name, value):
print(f"{name}={value}")
def read_line(timeout=5.0):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
ready, _, _ = select.select([proc.stdout], [], [], 0.1)
if ready:
line = proc.stdout.readline()
if line == "":
raise RuntimeError("db_program_stdout_closed")
line = line.rstrip("\n")
stdout_file.write(line + "\n")
stdout_file.flush()
return line
if proc.poll() is not None:
raise RuntimeError(f"db_program_exited_{proc.returncode}")
raise RuntimeError("timeout_waiting_for_db_program_reply")
def send(command):
proc.stdin.write(command + "\n")
proc.stdin.flush()
def read_until_fini(command, timeout=5.0):
send(command)
lines = []
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
line = read_line(max(0.1, deadline - time.monotonic()))
lines.append(line)
if line.startswith("FINI"):
return lines
raise RuntimeError(f"timeout_waiting_for_fini_{command.split()[0]}")
def require(condition, message):
if not condition:
raise RuntimeError(message)
ok = False
try:
version = read_line()
emit("tool_db_protocol_version", version)
require(version == "v2.1", f"version_drift:{version}")
get_all = read_until_fini("g")
tool_lines = [line for line in get_all if line.startswith("T")]
emit("tool_db_get_all_count", len(tool_lines))
require(len(tool_lines) == 10, "get_all_tool_count_drift")
for toolno in range(10, 20):
expected = f"T{toolno} "
require(any(line.startswith(expected) for line in tool_lines), f"missing_tool_{toolno}")
require(any(line.startswith(expected) and f"P{toolno + 100}" in line for line in tool_lines), f"pocket_drift_{toolno}")
emit("tool_db_get_all_fini", int(get_all[-1].startswith("FINI")))
put_reply = read_until_fini("p t11 p111 d0.33 z0.11")
emit("tool_db_put_tool_update_fini", int(put_reply[-1].startswith("FINI")))
get_after_put = read_until_fini("g")
t11_rows = [line for line in get_after_put if line.startswith("T11 ")]
require(t11_rows and "D0.33" in t11_rows[0] and "Z0.11" in t11_rows[0], "put_update_state_drift")
emit("tool_db_put_tool_update_state_ok", 1)
load_reply = read_until_fini("l t14 p0")
emit("tool_db_load_spindle_fini", int(load_reply[-1].startswith("FINI")))
t14_loaded = read_until_fini("t 14")
require(any(line.startswith("T14 ") and "P0" in line for line in t14_loaded), "load_spindle_state_drift")
emit("tool_db_load_spindle_state_ok", 1)
unload_reply = read_until_fini("u t0 p0")
emit("tool_db_unload_spindle_fini", int(unload_reply[-1].startswith("FINI")))
t14_unloaded = read_until_fini("t 14")
require(any(line.startswith("T14 ") and "P114" in line for line in t14_unloaded), "unload_spindle_state_drift")
emit("tool_db_unload_spindle_state_ok", 1)
require(os.path.exists(db_savefile), "db_savefile_missing")
with open(db_savefile, "r", encoding="utf-8") as handle:
saved = handle.read()
require("T11 P111 D0.33 Z0.11" in saved, "db_savefile_put_update_missing")
require("T14 P114" in saved, "db_savefile_unload_state_missing")
emit("tool_db_persistence_state_ok", 1)
ok = True
finally:
try:
if proc.stdin:
proc.stdin.close()
except Exception:
pass
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=2)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait(timeout=2)
stderr_file.close()
stdout_file.close()
emit("tool_db_runtime_protocol_probe_ok", int(ok))
sys.exit(0 if ok else 1)
PY
then
print_kv tool_db_runtime_probe_status "runtime_protocol_probe_passed"
print_kv tool_db_runtime_probe_note "linuxcnc_owned_DB_PROGRAM_protocol_probe_passed_without_promotion"
exit 0
fi
print_kv tool_db_runtime_probe_status "runtime_protocol_probe_failed"
print_kv tool_db_runtime_probe_note "linuxcnc_owned_DB_PROGRAM_protocol_probe_failed"
exit 1

View File

@@ -32,6 +32,8 @@ hash_build_validation_inputs() {
-o -name '*.run.stdout.log' \
-o -name '*.run.stderr.log' \
-o -name 'source-probes.tsv' \
-o -name 'native-source-proof-summary.tsv' \
-o -name 'native-runtime-probe-summary.tsv' \
-o -name 'native-probes.ok' \
-o -name 'linuxcnc_interp_minimal_harness' \
\) \
@@ -122,13 +124,195 @@ check_exitcode() {
fi
}
check_native_source_proof_summary_row() {
local boundary_class="$1"
local proof_key="$2"
local summary_file="$BUILD_DIR/native-source-proof-summary.tsv"
local row
row="$(awk -F'\t' -v boundary_class="$boundary_class" -v proof_key="$proof_key" '
NR > 1 && $1 == boundary_class && $2 == proof_key { print; count++ }
END {
if (count != 1) {
exit 1
}
}
' "$summary_file")" || {
echo "missing native source proof summary row: $boundary_class $proof_key" >&2
exit 1
}
local proof_value
local execution_enabled
local promotion_allowed
local stdout_log
IFS=$'\t' read -r _ _ proof_value execution_enabled promotion_allowed stdout_log <<< "$row"
if [[ "$proof_value" != "1" ]]; then
echo "$boundary_class native source proof is not complete: $proof_value" >&2
exit 1
fi
if [[ "$execution_enabled" != "0" || "$promotion_allowed" != "0" ]]; then
echo "$boundary_class unexpectedly enables execution or promotion" >&2
exit 1
fi
if [[ ! -f "$BUILD_DIR/$stdout_log" ]]; then
echo "$boundary_class summary references missing stdout log: $stdout_log" >&2
exit 1
fi
}
check_native_source_proof_summary() {
local summary_file="$BUILD_DIR/native-source-proof-summary.tsv"
if [[ ! -f "$summary_file" ]]; then
echo "missing native source proof summary: $summary_file" >&2
exit 1
fi
local expected_header
expected_header=$'boundary_class\tproof_key\tproof_value\texecution_enabled\tpromotion_allowed\tstdout_log'
if [[ "$(sed -n '1p' "$summary_file")" != "$expected_header" ]]; then
echo "native source proof summary header drift: $summary_file" >&2
exit 1
fi
local row_count
row_count="$(awk 'END { print NR - 1 }' "$summary_file")"
if [[ "$row_count" != "3" ]]; then
echo "native source proof summary must contain exactly 3 proof rows, got $row_count" >&2
exit 1
fi
check_native_source_proof_summary_row \
L4-USER-M-PROCESS \
millturn_user_m_native_source_state_proof
check_native_source_proof_summary_row \
L4-TOOL-DB \
tool_db_native_source_protocol_proof
check_native_source_proof_summary_row \
L4-PYTHON-REMAP \
python_remap_native_source_inventory_proof
}
check_native_runtime_probe_summary_row() {
local boundary_class="$1"
local boundary_kind="$2"
local target="$3"
local runtime_probe="$4"
local summary_file="$BUILD_DIR/native-runtime-probe-summary.tsv"
local row
row="$(awk -F'\t' \
-v boundary_class="$boundary_class" \
-v boundary_kind="$boundary_kind" \
-v target="$target" \
-v runtime_probe="$runtime_probe" '
NR > 1 && $1 == boundary_class && $2 == boundary_kind && $3 == target && $4 == runtime_probe {
print
count++
}
END {
if (count != 1) {
exit 1
}
}
' "$summary_file")" || {
echo "missing native runtime probe summary row: $boundary_class $boundary_kind $target" >&2
exit 1
}
local runtime_ready
local source_proof_ready
local probe_status
local execution_enabled
local promotion_allowed
local missing_requirements
local stdout_log
IFS=$'\t' read -r _ _ _ _ runtime_ready source_proof_ready probe_status execution_enabled promotion_allowed missing_requirements stdout_log <<< "$row"
if [[ "$source_proof_ready" != "1" ]]; then
echo "$target runtime probe lacks source proof readiness: $source_proof_ready" >&2
exit 1
fi
if [[ "$execution_enabled" != "0" || "$promotion_allowed" != "0" ]]; then
echo "$target runtime probe unexpectedly enables execution or promotion" >&2
exit 1
fi
if [[ ! "$probe_status" =~ ^(skipped_missing_host_runtime|ready_disabled_by_default|not_implemented_full_process_guard|runtime_state_probe_passed|runtime_protocol_probe_passed|runtime_lifecycle_probe_passed)$ ]]; then
echo "$target runtime probe has invalid status: $probe_status" >&2
exit 1
fi
if [[ "$runtime_ready" == "0" && "$probe_status" != "skipped_missing_host_runtime" ]]; then
echo "$target runtime probe is not ready but did not skip: $probe_status" >&2
exit 1
fi
if [[ "$runtime_ready" == "1" && "$missing_requirements" != "-" ]]; then
echo "$target runtime probe is ready but lists missing requirements: $missing_requirements" >&2
exit 1
fi
if [[ ! -f "$BUILD_DIR/$stdout_log" ]]; then
echo "$target runtime summary references missing stdout log: $stdout_log" >&2
exit 1
fi
}
check_native_runtime_probe_summary() {
local summary_file="$BUILD_DIR/native-runtime-probe-summary.tsv"
if [[ ! -f "$summary_file" ]]; then
echo "missing native runtime probe summary: $summary_file" >&2
exit 1
fi
local expected_header
expected_header=$'boundary_class\tboundary_kind\ttarget\truntime_probe\truntime_ready\tsource_proof_ready\tprobe_status\texecution_enabled\tpromotion_allowed\tmissing_requirements\tstdout_log'
if [[ "$(sed -n '1p' "$summary_file")" != "$expected_header" ]]; then
echo "native runtime probe summary header drift: $summary_file" >&2
exit 1
fi
local row_count
row_count="$(awk 'END { print NR - 1 }' "$summary_file")"
if [[ "$row_count" != "3" ]]; then
echo "native runtime probe summary must contain exactly 3 probe rows, got $row_count" >&2
exit 1
fi
check_native_runtime_probe_summary_row \
L4-USER-M-PROCESS \
external_user_m_process \
axis/vismach/millturn/example.ngc \
linuxcnc_millturn_user_m_runtime_probe
check_native_runtime_probe_summary_row \
L4-TOOL-DB \
tool_database_process \
axis/db_demo/base.ngc \
linuxcnc_tool_db_runtime_probe
check_native_runtime_probe_summary_row \
L4-PYTHON-REMAP \
python_runtime \
axis/remap/stop-lookahead/nc_files \
linuxcnc_python_remap_runtime_probe
}
check_source_probe_coverage
check_native_source_proof_summary
check_native_runtime_probe_summary
check_exitcode linuxcnc_interp_state_probe
check_exitcode linuxcnc_emc_status_probe
check_exitcode linuxcnc_emc_status_probe.run
check_exitcode linuxcnc_inifile_source_probe
check_exitcode linuxcnc_5axis_remap_asset_probe
check_exitcode linuxcnc_5axis_remap_asset_probe.run
check_exitcode linuxcnc_millturn_user_m_boundary_probe
check_exitcode linuxcnc_millturn_user_m_boundary_probe.run
check_exitcode linuxcnc_millturn_user_m_runtime_probe.run
check_exitcode linuxcnc_tool_db_boundary_probe
check_exitcode linuxcnc_tool_db_boundary_probe.run
check_exitcode linuxcnc_python_remap_boundary_probe
check_exitcode linuxcnc_python_remap_boundary_probe.run
check_exitcode linuxcnc_python_remap_runtime_probe.run
check_exitcode linuxcnc_tp_api_probe
check_exitcode linuxcnc_tp_api_probe.run
check_exitcode linuxcnc_kinematics_probe
@@ -381,6 +565,157 @@ grep -Fq "xyzac_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT
grep -Fq "xyzbc_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
grep -Fq "fiveaxis_remap_assets_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
MILLTURN_USER_M_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe.run.stdout.log"
grep -Fq "millturn_ini_open=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_RS274NGC.USER_M_PATH_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_RS274NGC.SUBROUTINE_PATH_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_DISPLAY.PYVCP_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_HAL.HALUI_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_state_mode=mill" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_guard_pin=kinstype.is-0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_script_tcl_hal_runtime=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_remap_calls_user_m_process=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_switchkins_output_pin=motion.analog-out-03" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_switchkins_target=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_work_offset_pocket=P7" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_work_offset_words=X-290 Y0 Z-160 A0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_active_g5x=G59.1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_calls_M128=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M428_source_transition_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_X_AXIS_X.MIN_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_X_AXIS_X.MAX_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_Z_AXIS_Z.MAX_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M128_source_state_targets_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_state_mode=turn" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_guard_pin=kinstype.is-1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_script_tcl_hal_runtime=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_remap_calls_user_m_process=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_switchkins_output_pin=motion.analog-out-03" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_switchkins_target=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_work_offset_pocket=P8" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_work_offset_words=X-160 Y0 Z-290 A0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_active_g5x=G59.2" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_calls_M129=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M429_source_transition_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_X_AXIS_X.MIN_LIMIT_TURN_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_Z_AXIS_Z.MAX_LIMIT_TURN_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "M129_source_state_targets_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_user_m_native_source_state_proof=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_user_m_execution_enabled=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
grep -Fq "millturn_user_m_promotion_allowed=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
MILLTURN_USER_M_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_millturn_user_m_runtime_probe.run.stdout.log"
grep -Fq "millturn_user_m_runtime_requirements=" "$MILLTURN_USER_M_RUNTIME_STDOUT"
grep -Fq "millturn_user_m_source_proof_ready=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
grep -Fq "millturn_user_m_execution_enabled=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
grep -Fq "millturn_user_m_promotion_allowed=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
if grep -Fq "millturn_user_m_runtime_ready=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"; then
grep -Eq "millturn_user_m_runtime_probe_status=(ready_disabled_by_default|runtime_state_probe_passed)" \
"$MILLTURN_USER_M_RUNTIME_STDOUT"
if grep -Fq "millturn_user_m_runtime_probe_status=runtime_state_probe_passed" "$MILLTURN_USER_M_RUNTIME_STDOUT"; then
grep -Fq "millturn_user_m_M128_runtime_state_ok=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
grep -Fq "millturn_user_m_M129_runtime_state_ok=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
fi
else
grep -Fq "millturn_user_m_runtime_ready=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
grep -Fq "millturn_user_m_runtime_probe_status=skipped_missing_host_runtime" \
"$MILLTURN_USER_M_RUNTIME_STDOUT"
fi
TOOL_DB_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_tool_db_boundary_probe.run.stdout.log"
grep -Fq "db_nonran_ini_open=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "db_nonran_EMCIO.RANDOM_TOOLCHANGER_ok=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "db_nonran_EMCIO.DB_PROGRAM_ok=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "db_nonran_tool_table_ignored_with_db_program=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_task_db_mode_init=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_task_ignores_tool_table_with_db_program=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_task_load_unload_notify=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_child_process_boundary=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_program_executable_check=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_v2_1_handshake=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_getall_g_until_fini=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_notify_l_u_p_protocol=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_program_tooldb_module=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_program_nonran_callbacks=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_program_nonran_state_targets=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_program_reload_rules=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_native_source_protocol_proof=1" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_execution_enabled=0" "$TOOL_DB_BOUNDARY_STDOUT"
grep -Fq "tool_db_promotion_allowed=0" "$TOOL_DB_BOUNDARY_STDOUT"
TOOL_DB_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_tool_db_runtime_probe.run.stdout.log"
grep -Fq "tool_db_runtime_requirements=" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_source_proof_ready=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_execution_enabled=0" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_promotion_allowed=0" "$TOOL_DB_RUNTIME_STDOUT"
if grep -Fq "tool_db_runtime_ready=1" "$TOOL_DB_RUNTIME_STDOUT"; then
grep -Eq "tool_db_runtime_probe_status=(ready_disabled_by_default|runtime_protocol_probe_passed)" \
"$TOOL_DB_RUNTIME_STDOUT"
if grep -Fq "tool_db_runtime_probe_status=runtime_protocol_probe_passed" "$TOOL_DB_RUNTIME_STDOUT"; then
grep -Fq "tool_db_runtime_protocol_probe_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_get_all_fini=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_put_tool_update_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_load_spindle_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_unload_spindle_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_persistence_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
fi
else
grep -Fq "tool_db_runtime_ready=0" "$TOOL_DB_RUNTIME_STDOUT"
grep -Fq "tool_db_runtime_probe_status=skipped_missing_host_runtime" \
"$TOOL_DB_RUNTIME_STDOUT"
fi
PYTHON_REMAP_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_python_remap_boundary_probe.run.stdout.log"
grep -Fq "python_runtime_pycall_dispatch=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_runtime_remap_phases=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_runtime_generator_finish=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_runtime_callable_lookup=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_runtime_execute_runtime=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_plugin_initializes_python=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_plugin_toplevel_exec_file=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_plugin_ini_python_path=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_plugin_callable_invoke=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_plugin_reload_on_change=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_family_axis_laser_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_family_twp_nutating_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_family_axis_remap_cycle_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_family_gmoccapy_stdglue_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_remap_native_source_inventory_proof=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_remap_execution_enabled=0" "$PYTHON_REMAP_BOUNDARY_STDOUT"
grep -Fq "python_remap_promotion_allowed=0" "$PYTHON_REMAP_BOUNDARY_STDOUT"
PYTHON_REMAP_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_python_remap_runtime_probe.run.stdout.log"
grep -Fq "python_remap_runtime_fixture_family=axis/remap/stop-lookahead/nc_files" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_runtime_fixture_id=stop_lookahead_python_runtime_lifecycle" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_runtime_fixture_scope=no_python_callables_no_ngc_only_subpaths" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_runtime_requirements=" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_runtime_modules=axis/remap/stop-lookahead/python/remap.py,axis/remap/stop-lookahead/python/toplevel.py" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_source_proof_ready=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_execution_enabled=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_promotion_allowed=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
if grep -Fq "python_remap_runtime_ready=1" "$PYTHON_REMAP_RUNTIME_STDOUT"; then
grep -Eq "python_remap_runtime_probe_status=(ready_disabled_by_default|runtime_lifecycle_probe_passed)" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
if grep -Fq "python_remap_runtime_probe_status=runtime_lifecycle_probe_passed" "$PYTHON_REMAP_RUNTIME_STDOUT"; then
grep -Fq "python_remap_runtime_lifecycle_probe_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_interpreter_sentinel_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_toplevel_imported=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_remap_imported=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_callable_lookup_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_generator_returned=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_generator_first_yield=2" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_lifecycle_generator_finish_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
fi
else
grep -Fq "python_remap_runtime_ready=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
grep -Fq "python_remap_runtime_probe_status=skipped_missing_host_runtime" \
"$PYTHON_REMAP_RUNTIME_STDOUT"
fi
REMAP_PARSE_STDOUT="$BUILD_DIR/linuxcnc_remap_parse_harness.run.stdout.log"
check_remap_descriptor() {

View File

@@ -22,7 +22,8 @@ while [[ $# -gt 0 ]]; do
Usage: $0 [--only PATH_SUBSTRING]
Runs LinuxCNC configs/sim .ngc programs through LinuxCNC's rs274 standalone
entry point and writes logs plus summary.tsv under:
entry point and writes logs plus summary.tsv, class-summary.tsv, and
path-matrix.tsv under:
$BUILD_DIR
EOF
exit 0
@@ -44,6 +45,10 @@ if [[ ! -d "$SIM_DIR" ]]; then
exit 1
fi
mkdir -p "$BUILD_DIR"
exec 9>"$BUILD_DIR/inventory.lock"
flock 9
"$ROOT_DIR/tools/build_native_probes.sh"
export LD_LIBRARY_PATH="$LINUXCNC_DIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
@@ -52,6 +57,8 @@ export PYTHONPATH="$LINUXCNC_DIR/lib/python${PYTHONPATH:+:$PYTHONPATH}"
mkdir -p "$BUILD_DIR"/{logs,out,wrapped,params}
: > "$BUILD_DIR/skipped.tsv"
SUMMARY_FILE="$BUILD_DIR/summary.tsv"
CLASS_SUMMARY_FILE="$BUILD_DIR/class-summary.tsv"
PATH_MATRIX_FILE="$BUILD_DIR/path-matrix.tsv"
printf 'path\tclass\tstatus\texpected_failure\texit_code\tseconds\tini\ttbl\toutput_lines\tstderr_summary\n' > "$SUMMARY_FILE"
relpath() {
@@ -392,9 +399,69 @@ while IFS= read -r ngc; do
"$stderr_summary" >> "$SUMMARY_FILE"
done < <(find "$SIM_DIR" -type f -name '*.ngc' | sort)
{
printf 'class\tstatus\texpected_failure\tcount\n'
awk -F '\t' '
NR > 1 {
class[$2] += 1
status[$2 "\t" $3] += 1
if ($4 != "") {
expected[$2 "\t" $4] += 1
}
}
END {
for (key in class) {
print key "\tALL\t-\t" class[key]
}
for (key in status) {
split(key, parts, "\t")
print parts[1] "\t" parts[2] "\t-\t" status[key]
}
for (key in expected) {
split(key, parts, "\t")
print parts[1] "\tEXPECTED_FAIL\t" parts[2] "\t" expected[key]
}
}
' "$SUMMARY_FILE" | sort
} > "$CLASS_SUMMARY_FILE"
awk -F '\t' '
BEGIN {
OFS = "\t"
print "path", "class", "status", "expected_failure", "ini", "tbl", "runtime_family", "blocked"
}
NR > 1 {
runtime_family = $1
sub("/[^/]+$", "", runtime_family)
blocked = ""
if ($1 ~ /^axis\/db_demo\//) {
blocked = "L4-TOOL-DB"
} else if ($1 ~ /^axis\/vismach\/millturn\// && $2 == "main") {
blocked = "L4-USER-M-PROCESS"
} else if ($4 == "upstream-demo-missing-motion-gcode") {
blocked = "UPSTREAM-DEMO"
} else if ($1 ~ /^axis\/remap\// && $2 == "main") {
blocked = "L4-PYTHON-REMAP"
} else if ($1 ~ /^axis\/vismach\/VMC_toolchange\// && $2 == "main") {
blocked = "L4-PYTHON-REMAP"
} else if ($1 ~ /^gmoccapy\//) {
blocked = "L4-PYTHON-REMAP"
} else if ($1 ~ /^axis\/laser\//) {
blocked = "L4-PYTHON-REMAP"
} else if ($1 ~ /^axis\/vismach\/5axis\/table-rotary_spindle-rotary-nutating\/demos\//) {
blocked = "L4-PYTHON-REMAP"
} else if ($2 == "remap_subroutine") {
blocked = "ASSET-ONLY"
}
print $1, $2, $3, ($4 == "" ? "-" : $4), $7, $8, runtime_family, (blocked == "" ? "-" : blocked)
}
' "$SUMMARY_FILE" > "$PATH_MATRIX_FILE"
{
printf 'sim config harness summary\n'
printf 'summary: %s\n' "$SUMMARY_FILE"
printf 'class_summary: %s\n' "$CLASS_SUMMARY_FILE"
printf 'path_matrix: %s\n' "$PATH_MATRIX_FILE"
printf 'total: %s\n' "$total"
printf 'pass: %s\n' "$pass"
printf 'fail: %s\n' "$fail"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
NATIVE_SUMMARY="$ROOT_DIR/build/native/sim-configs/summary.tsv"
NATIVE_CLASS_SUMMARY="$ROOT_DIR/build/native/sim-configs/class-summary.tsv"
NATIVE_PATH_MATRIX="$ROOT_DIR/build/native/sim-configs/path-matrix.tsv"
NATIVE_SOURCE_PROOF_SUMMARY="$ROOT_DIR/build/native/native-source-proof-summary.tsv"
NATIVE_BUILD_DIR="$ROOT_DIR/build/native/sim-configs"
NATIVE_SOURCE_PROOF_INPUTS=(
"$ROOT_DIR/tools/build_native_probes.sh"
"$ROOT_DIR/tools/source-manifest.txt"
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_millturn_user_m_boundary_probe.cpp"
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_tool_db_boundary_probe.cpp"
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_python_remap_boundary_probe.cpp"
)
native_source_proof_refresh_required() {
if [[ ! -f "$NATIVE_SOURCE_PROOF_SUMMARY" ]]; then
return 0
fi
for input in "${NATIVE_SOURCE_PROOF_INPUTS[@]}"; do
if [[ "$input" -nt "$NATIVE_SOURCE_PROOF_SUMMARY" ]]; then
return 0
fi
done
return 1
}
if [[ ! -f "$NATIVE_SUMMARY" || ! -f "$NATIVE_CLASS_SUMMARY" || ! -f "$NATIVE_PATH_MATRIX" ]]; then
"$ROOT_DIR/tests/native/verify_sim_configs.sh"
fi
if native_source_proof_refresh_required; then
"$ROOT_DIR/tools/build_native_probes.sh"
fi
mkdir -p "$NATIVE_BUILD_DIR"
exec 9>"$NATIVE_BUILD_DIR/inventory.lock"
flock 9
if [[ "${SKIP_INTERP_BUILD:-0}" != "1" ]]; then
"$ROOT_DIR/tools/build_wasm_core.sh"
fi
node "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs"

View File

@@ -4,6 +4,7 @@ import { dirname, resolve } from "node:path";
import assert from "node:assert/strict";
import {
analyzeIniRuntimeBoundaries,
createLinuxCncInterpSdk,
planIniFileContextStaging,
planSimConfigStaging,
@@ -46,6 +47,10 @@ const interp = await createLinuxCncInterpSdk({
},
});
function readSimIni(machineRel, iniFile) {
return readFileSync(resolve(vendorRoot, `configs/sim/${machineRel}/${iniFile}`), "utf8");
}
const syntheticPlan = planSimConfigStaging({
manifestText: [
"configs/sim/example/test.ini",
@@ -80,6 +85,80 @@ assert.deepEqual(
],
"synthetic sim-config staging plan",
);
const syntheticBoundary = analyzeIniRuntimeBoundaries({
manifestText: [
"configs/sim/example/test.ini",
"configs/sim/example/test.ngc",
"configs/sim/example/tool.tbl",
"configs/sim/example/M123",
].join("\n"),
sourceRootRel: "configs/sim/example",
sourceSearchRootRel: "configs/sim",
iniFile: "test.ini",
iniText: [
"[DISPLAY]",
"DISPLAY = axis",
"OPEN_FILE = test.ngc",
"[RS274NGC]",
"USER_M_PATH = .",
"[EMCIO]",
"TOOL_TABLE = tool.tbl",
].join("\n"),
});
assert.deepEqual(
syntheticBoundary,
{
dependencies: [],
recommendedBlockedKind: "-",
toolDatabaseProgram: "",
halRuntime: { values: [], requiresProcess: false },
uiRuntime: { values: ["axis"], requiresProcess: false },
haluiRuntime: { mdiCommands: [], requiresProcess: false },
userMRuntime: {
paths: ["."],
vendoredExecutableCount: 1,
executionCodes: [],
unstagedExecutionCodes: [],
requiresExternalProcess: false,
},
pythonRuntime: { references: [], remapReferences: [], uiReferences: [], requiresProcess: false },
},
"synthetic runtime-boundary analysis",
);
const mixedUserMBoundary = analyzeIniRuntimeBoundaries({
manifestText: [
"configs/sim/example/test.ini",
"configs/sim/example/test.ngc",
"configs/sim/example/M123",
].join("\n"),
sourceRootRel: "configs/sim/example",
sourceSearchRootRel: "configs/sim",
iniFile: "test.ini",
iniText: [
"[DISPLAY]",
"DISPLAY = axis",
"[RS274NGC]",
"USER_M_PATH = .",
].join("\n"),
executionTexts: ["M123\nM124\n"],
});
assert.equal(
mixedUserMBoundary.recommendedBlockedKind,
"L4-USER-M-PROCESS",
"mixed vendored and unstaged user-M calls must block",
);
assert.deepEqual(
mixedUserMBoundary.userMRuntime.executionCodes,
["M123", "M124"],
"mixed user-M execution codes",
);
assert.deepEqual(
mixedUserMBoundary.userMRuntime.unstagedExecutionCodes,
["M124"],
"only unstaged user-M execution codes require the external process boundary",
);
assert.deepEqual(
syntheticPlan.files.map((file) => [file.sourceRel, file.wasmPath]).sort(),
[
@@ -134,6 +213,111 @@ assert.deepEqual(
"generic INI file-context staging plan",
);
function simBoundary(machineRel, iniFile, executionRelFiles = []) {
return analyzeIniRuntimeBoundaries({
manifestText,
sourceRootRel: `configs/sim/${machineRel}`,
sourceSearchRootRel: "configs/sim",
iniFile,
iniText: readSimIni(machineRel, iniFile),
executionTexts: executionRelFiles.map((relFile) =>
readFileSync(resolve(vendorRoot, `configs/sim/${machineRel}/${relFile}`), "utf8"),
),
});
}
const dbDemoBoundary = simBoundary("axis/db_demo", "db_nonran.ini");
assert.deepEqual(
dbDemoBoundary.dependencies,
["python_runtime", "tool_database_process"],
"db_demo tool database boundary dependencies",
);
assert.equal(dbDemoBoundary.recommendedBlockedKind, "L4-TOOL-DB", "db_demo blocked kind");
assert.equal(dbDemoBoundary.toolDatabaseProgram, "./db_nonran.py", "db_demo DB_PROGRAM");
assert.deepEqual(
dbDemoBoundary.pythonRuntime.uiReferences,
["./db_nonran.py"],
"db_demo Python dependency is the DB program process",
);
assert.deepEqual(
dbDemoBoundary.pythonRuntime.remapReferences,
[],
"db_demo does not declare Python remap runtime",
);
const millturnBoundary = simBoundary("axis/vismach/millturn", "millturn.ini", [
"example.ngc",
"remap_subs/428remap.ngc",
"remap_subs/429remap.ngc",
]);
assert.equal(
millturnBoundary.recommendedBlockedKind,
"L4-USER-M-PROCESS",
"millturn blocked kind",
);
assert.deepEqual(
millturnBoundary.dependencies,
["external_user_m_process", "hal_process", "halui_mdi_process", "ui_process"],
"millturn full-process boundary dependencies",
);
assert.equal(
millturnBoundary.userMRuntime.vendoredExecutableCount,
0,
"millturn external user-M files are not staged",
);
assert.deepEqual(
millturnBoundary.userMRuntime.executionCodes,
["M128", "M129"],
"millturn execution chain calls external user-M processes",
);
assert.deepEqual(
millturnBoundary.userMRuntime.unstagedExecutionCodes,
["M128", "M129"],
"millturn execution chain calls unstaged user-M processes",
);
const pumaBoundary = simBoundary("axis/vismach/puma", "puma_cube.ini");
assert.equal(pumaBoundary.recommendedBlockedKind, "-", "puma_cube representative is not blocked");
assert.equal(pumaBoundary.userMRuntime.vendoredExecutableCount, 0, "puma_cube has no vendored user-M processes");
assert.equal(pumaBoundary.halRuntime.requiresProcess, true, "puma_cube declares HAL process files");
assert.equal(pumaBoundary.haluiRuntime.requiresProcess, true, "puma_cube declares HALUI MDI commands");
const melfaBoundary = simBoundary("axis/vismach/melfa-sim", "melfa.ini");
assert.equal(melfaBoundary.recommendedBlockedKind, "-", "melfa representative is not blocked");
assert.deepEqual(
melfaBoundary.dependencies,
["hal_process", "halui_mdi_process", "ui_process"],
"melfa declares HAL/UI/HALUI process dependencies",
);
assert.equal(melfaBoundary.pythonRuntime.requiresProcess, false, "melfa representative has no Python runtime");
const woodpeckerBoundary = simBoundary("woodpecker", "woodpecker.ini");
assert.equal(woodpeckerBoundary.recommendedBlockedKind, "-", "woodpecker representative is not blocked");
assert.deepEqual(
woodpeckerBoundary.dependencies,
["hal_process", "ui_process"],
"woodpecker declares HAL/UI process dependencies",
);
assert.equal(woodpeckerBoundary.haluiRuntime.requiresProcess, false, "woodpecker representative has no HALUI MDI");
const gladevcpBoundary = simBoundary("axis/gladevcp", "gladevcp_panel.ini");
assert.equal(gladevcpBoundary.recommendedBlockedKind, "-", "gladevcp probe representative is not blocked");
assert.ok(
gladevcpBoundary.dependencies.includes("ui_process"),
"gladevcp declares UI process dependency",
);
assert.equal(gladevcpBoundary.pythonRuntime.requiresProcess, true, "gladevcp declares Python UI handler");
assert.deepEqual(
gladevcpBoundary.pythonRuntime.uiReferences,
["-u hitcounter.py manual-example.ui"],
"gladevcp Python dependency is a UI handler",
);
assert.deepEqual(
gladevcpBoundary.pythonRuntime.remapReferences,
[],
"gladevcp representative must not be treated as Python remap runtime",
);
function simMachine(machineRel, iniFile, programFile = null) {
const iniText = readFileSync(
resolve(vendorRoot, `configs/sim/${machineRel}/${iniFile}`),
@@ -158,6 +342,23 @@ function simMachine(machineRel, iniFile, programFile = null) {
};
}
function wrapSimProgram(machine, wrappedName) {
const sourceFile = machine.files.find((file) => file.path === machine.programPath);
assert.ok(sourceFile, `${machine.programPath}: wrapped source file`);
return {
...machine,
programPath: `${machine.wasmDir}/${wrappedName}`,
files: [
...machine.files,
{
path: `${machine.wasmDir}/${wrappedName}`,
text: `${sourceFile.text}\nM2\n`,
executable: false,
},
],
};
}
const foam = simMachine("axis/foam", "axis_foam.ini", "foam.ngc");
verifyExpectedOutput(
"sim_axis_foam_uv_wasm",
@@ -225,6 +426,49 @@ verifyExpectedOutput(
].join("\n"),
);
const gladevcpProbe = simMachine("axis/gladevcp", "gladevcp_panel.ini", "probe.ngc");
verifyExpectedOutput(
"sim_axis_gladevcp_probe_wasm",
interp.runSimConfigProgram({
files: gladevcpProbe.files,
programPath: gladevcpProbe.programPath,
iniPath: gladevcpProbe.iniPath,
}),
[
"file_open=0",
"file_saw_error=0",
"canon_event=PROGRAM_END",
"absent=file_error_text=",
].join("\n"),
);
const externalOffsetsMacro = wrapSimProgram(
simMachine("axis/external_offsets", "dynamic_offsets.ini", "circles.ngc"),
"__wrapped_circles.ngc",
);
verifyExpectedOutput(
"sim_axis_external_offsets_circles_macro_wasm",
interp.runSimConfigProgram({
files: externalOffsetsMacro.files,
programPath: externalOffsetsMacro.programPath,
iniPath: externalOffsetsMacro.iniPath,
}),
[
"file_open=0",
"file_execute_45=1",
"statement_uri=M2",
"file_read_count=45",
"file_execute_count=45",
"file_saw_error=0",
"canon_event=COMMENT: info: Multiple circles at radius R, use 0 for current val",
"canon_event=PROGRAM_END",
"post_execute.origin_index=1",
"post_execute.mist=0",
"post_execute.flood=0",
"absent=file_error_text=",
].join("\n"),
);
for (const externalOffsetCase of [
{
name: "dyn_demo",
@@ -287,4 +531,62 @@ for (const externalOffsetCase of [
);
}
const melfaSim = simMachine("axis/vismach/melfa-sim", "melfa.ini", "example.ngc");
verifyExpectedOutput(
"sim_axis_vismach_melfa_wasm",
interp.runSimConfigProgram({
files: melfaSim.files,
programPath: melfaSim.programPath,
iniPath: melfaSim.iniPath,
executionMode: "fiveAxisRemap",
}),
[
"fiveaxis_ini_open=1",
"fiveaxis_tool_table_load=0",
"fiveaxis_file_open=0",
"fiveaxis_file_reached_exit=1",
"fiveaxis_linuxcnc_remap_file_execute=1",
].join("\n"),
);
const pumaCube = simMachine("axis/vismach/puma", "puma_cube.ini", "puma_cube.ngc");
verifyExpectedOutput(
"sim_axis_vismach_puma_cube_wasm",
interp.runSimConfigProgram({
files: pumaCube.files,
programPath: pumaCube.programPath,
iniPath: pumaCube.iniPath,
}),
[
"file_open=0",
"file_saw_error=0",
"canon_event=PROGRAM_END",
"absent=file_error_text=",
].join("\n"),
);
const woodpeckerOnAbort = simMachine("woodpecker", "woodpecker.ini", "on_abort.ngc");
verifyExpectedOutput(
"sim_woodpecker_on_abort_wasm",
interp.runSimConfigProgram({
files: woodpeckerOnAbort.files,
programPath: woodpeckerOnAbort.programPath,
iniPath: woodpeckerOnAbort.iniPath,
}),
[
"file_open=0",
"run_step phase=execute step=17 rc=1 line=17",
"statement_uri=m2",
"file_read_count=17",
"file_execute_count=17",
"file_saw_error=0",
"canon_event=ON_RESET",
"canon_event=PROGRAM_END",
"post_execute.origin_index=1",
"post_execute.mist=0",
"post_execute.flood=0",
"absent=file_error_text=",
].join("\n"),
);
console.log("sim_configs_wasm_node_smoke=ok");

View File

@@ -8,6 +8,11 @@ WRAP_DIR="$ROOT_DIR/runtime/core/linuxcnc_wrap"
SHIM_DIR="$ROOT_DIR/runtime/core/shims"
INCLUDE_DIR="$ROOT_DIR/runtime/core/include"
SOURCE_PROBE_MAP="$BUILD_DIR/source-probes.tsv"
NATIVE_SOURCE_PROOF_SUMMARY="$BUILD_DIR/native-source-proof-summary.tsv"
NATIVE_RUNTIME_PROBE_SUMMARY="$BUILD_DIR/native-runtime-probe-summary.tsv"
MILLTURN_USER_M_RUNTIME_PROBE="$ROOT_DIR/tests/native/probe_millturn_user_m_runtime.sh"
TOOL_DB_RUNTIME_PROBE="$ROOT_DIR/tests/native/probe_tool_db_runtime.sh"
PYTHON_REMAP_RUNTIME_PROBE="$ROOT_DIR/tests/native/probe_python_remap_runtime.sh"
MINIMAL_GCODE_FIXTURE="$ROOT_DIR/tests/fixtures/gcode/minimal_linear.ngc"
DO_WHILE_BREAK_FIXTURE="$ROOT_DIR/vendor/linuxcnc/tests/interp/do-while-break/test.ngc"
OWORD_BUG315_FIXTURE="$ROOT_DIR/vendor/linuxcnc/tests/interp/oword-bug315/test.ngc"
@@ -175,6 +180,31 @@ native_input_fingerprint() {
"$SHIM_DIR" \
"$INCLUDE_DIR" \
"$ROOT_DIR/tests/fixtures"
hash_tree \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/vismach/millturn/mcodes" \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/vismach/millturn/remap_subs"
sha256sum \
"$MILLTURN_USER_M_RUNTIME_PROBE" \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/vismach/millturn/millturn.ini"
hash_tree \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/db_demo"
sha256sum \
"$TOOL_DB_RUNTIME_PROBE" \
"$ROOT_DIR/../linuxcnc/src/emc/task/taskclass.cc" \
"$ROOT_DIR/../linuxcnc/src/emc/tooldata/tooldata_db.cc" \
"$ROOT_DIR/../linuxcnc/src/emc/tooldata/tooldata_common.cc"
hash_tree \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/laser" \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/remap/cycle" \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/nc_files/remap_lib/python-stdglue" \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating" \
"$ROOT_DIR/../linuxcnc/configs/sim/gmoccapy/python"
sha256sum \
"$ROOT_DIR/../linuxcnc/src/emc/rs274ngc/interp_python.cc" \
"$ROOT_DIR/../linuxcnc/src/emc/pythonplugin/python_plugin.cc" \
"$PYTHON_REMAP_RUNTIME_PROBE"
hash_tree \
"$ROOT_DIR/../linuxcnc/configs/sim/axis/remap/stop-lookahead"
} | sha256sum | awk '{ print $1 }'
}
@@ -245,6 +275,12 @@ VENDOR_ASSET_FLAGS=(
-DLINUXCNC_VENDOR_DIR=\"$VENDOR_DIR\"
)
SOURCE_CONFIG_ASSET_FLAGS=(
"${COMMON_INI_FLAGS[@]}"
-DLINUXCNC_SOURCE_DIR=\"$ROOT_DIR/../linuxcnc\"
-DLINUXCNC_SOURCE_CONFIG_DIR=\"$ROOT_DIR/../linuxcnc/configs/sim\"
)
MINIMAL_FLAGS=(
"${COMMON_INI_FLAGS[@]}"
-ffunction-sections
@@ -309,6 +345,165 @@ write_file_if_changed() {
mv "$tmp" "$file"
}
stdout_value() {
local file="$1"
local key="$2"
awk -F= -v key="$key" '$1 == key { value = substr($0, length(key) + 2) } END { print value }' "$file"
}
append_native_source_proof_summary_row() {
local tmp="$1"
local boundary="$2"
local proof_key="$3"
local execution_key="$4"
local promotion_key="$5"
local stdout_log="$6"
local proof_value
local execution_enabled
local promotion_allowed
proof_value="$(stdout_value "$stdout_log" "$proof_key")"
execution_enabled="$(stdout_value "$stdout_log" "$execution_key")"
promotion_allowed="$(stdout_value "$stdout_log" "$promotion_key")"
printf '%s\t%s\t%s\t%s\t%s\t%s\n' \
"$boundary" \
"$proof_key" \
"$proof_value" \
"$execution_enabled" \
"$promotion_allowed" \
"${stdout_log#"$BUILD_DIR"/}" >> "$tmp"
}
write_native_source_proof_summary() {
local tmp
tmp="$(mktemp)"
printf '%s\t%s\t%s\t%s\t%s\t%s\n' \
boundary_class \
proof_key \
proof_value \
execution_enabled \
promotion_allowed \
stdout_log > "$tmp"
append_native_source_proof_summary_row \
"$tmp" \
L4-USER-M-PROCESS \
millturn_user_m_native_source_state_proof \
millturn_user_m_execution_enabled \
millturn_user_m_promotion_allowed \
"$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe.run.stdout.log"
append_native_source_proof_summary_row \
"$tmp" \
L4-TOOL-DB \
tool_db_native_source_protocol_proof \
tool_db_execution_enabled \
tool_db_promotion_allowed \
"$BUILD_DIR/linuxcnc_tool_db_boundary_probe.run.stdout.log"
append_native_source_proof_summary_row \
"$tmp" \
L4-PYTHON-REMAP \
python_remap_native_source_inventory_proof \
python_remap_execution_enabled \
python_remap_promotion_allowed \
"$BUILD_DIR/linuxcnc_python_remap_boundary_probe.run.stdout.log"
if [[ -f "$NATIVE_SOURCE_PROOF_SUMMARY" ]] && cmp -s "$tmp" "$NATIVE_SOURCE_PROOF_SUMMARY"; then
rm -f "$tmp"
return 0
fi
mv "$tmp" "$NATIVE_SOURCE_PROOF_SUMMARY"
}
append_native_runtime_probe_summary_row() {
local tmp="$1"
local boundary_class="$2"
local boundary_kind="$3"
local target="$4"
local runtime_probe="$5"
local prefix="$6"
local stdout_log="$7"
local runtime_ready
local source_proof_ready
local probe_status
local execution_enabled
local promotion_allowed
local missing_requirements
runtime_ready="$(stdout_value "$stdout_log" "${prefix}_runtime_ready")"
source_proof_ready="$(stdout_value "$stdout_log" "${prefix}_source_proof_ready")"
probe_status="$(stdout_value "$stdout_log" "${prefix}_runtime_probe_status")"
execution_enabled="$(stdout_value "$stdout_log" "${prefix}_execution_enabled")"
promotion_allowed="$(stdout_value "$stdout_log" "${prefix}_promotion_allowed")"
missing_requirements="$(stdout_value "$stdout_log" "${prefix}_missing_requirements")"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$boundary_class" \
"$boundary_kind" \
"$target" \
"$runtime_probe" \
"$runtime_ready" \
"$source_proof_ready" \
"$probe_status" \
"$execution_enabled" \
"$promotion_allowed" \
"${missing_requirements:-"-"}" \
"${stdout_log#"$BUILD_DIR"/}" >> "$tmp"
}
write_native_runtime_probe_summary() {
local tmp
tmp="$(mktemp)"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
boundary_class \
boundary_kind \
target \
runtime_probe \
runtime_ready \
source_proof_ready \
probe_status \
execution_enabled \
promotion_allowed \
missing_requirements \
stdout_log > "$tmp"
append_native_runtime_probe_summary_row \
"$tmp" \
L4-USER-M-PROCESS \
external_user_m_process \
axis/vismach/millturn/example.ngc \
linuxcnc_millturn_user_m_runtime_probe \
millturn_user_m \
"$BUILD_DIR/linuxcnc_millturn_user_m_runtime_probe.run.stdout.log"
append_native_runtime_probe_summary_row \
"$tmp" \
L4-TOOL-DB \
tool_database_process \
axis/db_demo/base.ngc \
linuxcnc_tool_db_runtime_probe \
tool_db \
"$BUILD_DIR/linuxcnc_tool_db_runtime_probe.run.stdout.log"
append_native_runtime_probe_summary_row \
"$tmp" \
L4-PYTHON-REMAP \
python_runtime \
axis/remap/stop-lookahead/nc_files \
linuxcnc_python_remap_runtime_probe \
python_remap \
"$BUILD_DIR/linuxcnc_python_remap_runtime_probe.run.stdout.log"
if [[ -f "$NATIVE_RUNTIME_PROBE_SUMMARY" ]] && cmp -s "$tmp" "$NATIVE_RUNTIME_PROBE_SUMMARY"; then
rm -f "$tmp"
return 0
fi
mv "$tmp" "$NATIVE_RUNTIME_PROBE_SUMMARY"
}
write_ccomp_ini() {
local file="$1"
local tool_table="$2"
@@ -692,6 +887,20 @@ FIVEAXIS_REMAP_ASSET_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_5axis_remap_asset_probe.cpp"
)
MILLTURN_USER_M_BOUNDARY_PROBE_SOURCES=(
"$VENDOR_DIR/src/emc/ini/inifile.cc"
"$WRAP_DIR/linuxcnc_millturn_user_m_boundary_probe.cpp"
)
TOOL_DB_BOUNDARY_PROBE_SOURCES=(
"$VENDOR_DIR/src/emc/ini/inifile.cc"
"$WRAP_DIR/linuxcnc_tool_db_boundary_probe.cpp"
)
PYTHON_REMAP_BOUNDARY_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_python_remap_boundary_probe.cpp"
)
STATE_PROBE_SOURCES=(
"$WRAP_DIR/linuxcnc_interp_state_probe.cpp"
)
@@ -1102,6 +1311,71 @@ else
"$BUILD_DIR/linuxcnc_5axis_remap_asset_probe.run.stderr.log"
fi
build_binary_target \
linuxcnc_millturn_user_m_boundary_probe \
"$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe" \
SOURCE_CONFIG_ASSET_FLAGS \
MILLTURN_USER_M_BOUNDARY_PROBE_SOURCES \
NO_LINK_FLAGS \
-lfmt
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe.exitcode")" == "0" ]]; then
run_logged_command \
linuxcnc_millturn_user_m_boundary_probe \
"$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe"
run_logged_command \
linuxcnc_millturn_user_m_runtime_probe \
bash \
"$MILLTURN_USER_M_RUNTIME_PROBE"
else
clear_logged_command linuxcnc_millturn_user_m_boundary_probe
clear_logged_command linuxcnc_millturn_user_m_runtime_probe
fi
build_binary_target \
linuxcnc_tool_db_boundary_probe \
"$BUILD_DIR/linuxcnc_tool_db_boundary_probe" \
SOURCE_CONFIG_ASSET_FLAGS \
TOOL_DB_BOUNDARY_PROBE_SOURCES \
NO_LINK_FLAGS \
-lfmt
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_tool_db_boundary_probe.exitcode")" == "0" ]]; then
run_logged_command \
linuxcnc_tool_db_boundary_probe \
"$BUILD_DIR/linuxcnc_tool_db_boundary_probe"
run_logged_command \
linuxcnc_tool_db_runtime_probe \
bash \
"$TOOL_DB_RUNTIME_PROBE"
else
clear_logged_command linuxcnc_tool_db_boundary_probe
clear_logged_command linuxcnc_tool_db_runtime_probe
fi
build_binary_target \
linuxcnc_python_remap_boundary_probe \
"$BUILD_DIR/linuxcnc_python_remap_boundary_probe" \
SOURCE_CONFIG_ASSET_FLAGS \
PYTHON_REMAP_BOUNDARY_PROBE_SOURCES \
NO_LINK_FLAGS
if [[ "$(tr -d '[:space:]' < "$BUILD_DIR/linuxcnc_python_remap_boundary_probe.exitcode")" == "0" ]]; then
run_logged_command \
linuxcnc_python_remap_boundary_probe \
"$BUILD_DIR/linuxcnc_python_remap_boundary_probe"
run_logged_command \
linuxcnc_python_remap_runtime_probe \
bash \
"$PYTHON_REMAP_RUNTIME_PROBE"
else
clear_logged_command linuxcnc_python_remap_boundary_probe
clear_logged_command linuxcnc_python_remap_runtime_probe
fi
write_native_source_proof_summary
write_native_runtime_probe_summary
build_object_target \
linuxcnc_inifile_source_probe \
"$BUILD_DIR/linuxcnc_inifile_source_probe.o" \

View File

@@ -496,11 +496,19 @@ configs/sim/axis/external_offsets/jwp_z.ini
configs/sim/axis/external_offsets/jwp_z.ngc
configs/sim/axis/external_offsets/opa.ini
configs/sim/axis/external_offsets/opa_demo.ngc
configs/sim/axis/db_demo/base.ngc
configs/sim/axis/db_demo/db_nonran.ini
configs/sim/axis/foam/axis_foam.ini
configs/sim/axis/foam/foam.ngc
configs/sim/axis/gladevcp/gladevcp_panel.ini
configs/sim/axis/gladevcp/probe.ngc
configs/sim/axis/gladevcp/sim.tbl
configs/sim/axis/geometry/M110
configs/sim/axis/geometry/xyzc.ini
configs/sim/axis/geometry/xyzc.ngc
configs/sim/axis/rose_engine/rcone.ngc
configs/sim/axis/rose_engine/rcone_demo.ngc
configs/sim/axis/rose_engine/rose_engine.ini
configs/sim/axis/vismach/5axis/bridgemill/5axis.ini
configs/sim/axis/vismach/5axis/bridgemill/5axis.tbl
configs/sim/axis/vismach/5axis/bridgemill/5axis.xml
@@ -511,6 +519,25 @@ configs/sim/axis/vismach/5axis/bridgemill/README
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc
configs/sim/axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc
configs/sim/axis/vismach/melfa-sim/example.ngc
configs/sim/axis/vismach/melfa-sim/melfa.ini
configs/sim/axis/vismach/melfa-sim/melfa.tbl
configs/sim/axis/vismach/melfa-sim/remap_subs/428remap.ngc
configs/sim/axis/vismach/melfa-sim/remap_subs/429remap.ngc
configs/sim/axis/vismach/melfa-sim/remap_subs/430remap.ngc
configs/sim/axis/vismach/millturn/example.ngc
configs/sim/axis/vismach/millturn/millturn.ini
configs/sim/axis/vismach/millturn/millturn.tbl
configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc
configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc
configs/sim/axis/vismach/puma/puma.ini
configs/sim/axis/vismach/puma/puma.tbl
configs/sim/axis/vismach/puma/puma_cube.ini
configs/sim/axis/vismach/puma/puma_cube.ngc
configs/sim/axis/vismach/puma/puma_seam_weld.ngc
configs/sim/axis/vismach/puma/remap_subs/428remap.ngc
configs/sim/axis/vismach/puma/remap_subs/429remap.ngc
configs/sim/axis/vismach/puma/remap_subs/430remap.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/README
configs/sim/axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc
configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc
@@ -550,6 +577,27 @@ configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.tbl
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.txt
configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.xml
configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc
configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini
configs/sim/qtdragon/qtdragon_multi_joint/tool.tbl
configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc
configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini
configs/sim/qtdragon/qtdragon_xyz/tool.tbl
configs/sim/qtdragon/qtdragon_xyz45/on_abort.ngc
configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini
configs/sim/qtdragon/qtdragon_xyz45/tool.tbl
configs/sim/qtdragon_hd/qtdragon_hd_xyz/on_abort.ngc
configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini
configs/sim/qtdragon_hd/qtdragon_hd_xyz/tool.tbl
configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc
configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini
configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/tool.tbl
configs/sim/qtvcp_screens/qtdragon/on_abort.ngc
configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini
configs/sim/qtvcp_screens/qtdragon/tool.tbl
configs/sim/woodpecker/on_abort.ngc
configs/sim/woodpecker/tool.tbl
configs/sim/woodpecker/woodpecker.ini
nc_files/3D_Chips.ngc
nc_files/arcspiral.ngc
nc_files/factorial.ngc

View File

@@ -0,0 +1,17 @@
%
#<toolno> = 10
#<ct> = 0
#<howmany> = 5
g49
o100 while [[#<ct> lt #<howmany>] and [#<_task> ne 0]]
#<ct> = [#<ct> +1]
t#<toolno> m6 g43
(debug,ct=#<ct> zoff=#5403)
g4p[0.05*60] ;approx 0.05 minutes
t0m6
g10l0 ; reload tooldata (apply_db_rules)
o100 endwhile
g49
(debug, fini)
%

View File

@@ -0,0 +1,17 @@
#INCLUDE base.inc
[EMC]
VERSION = 1.1
MACHINE = db_nonran NONRANDOM toolchanger
[RS274NGC]
PARAMETER_FILE = db_nonran.var
SUBROUTINE_PATH = .
[EMCIO]
RANDOM_TOOLCHANGER = 0
DB_PROGRAM = ./db_nonran.py
# alternate spec using args:
# DB_PROGRAM = ./db_nonran.py --period_minutes=10 /tmp/db_nonran_special
# TOOL_TABLE= is not used with DB_PROGRAM

View File

@@ -0,0 +1,125 @@
[EMC]
VERSION = 1.1
MACHINE = LinuxCNC-PANEL-GLADEVCP
# Debug level, 0 means no messages. See src/emc/nml_int/emcglb.h for others
DEBUG = 0
[DISPLAY]
GLADEVCP= -u hitcounter.py manual-example.ui
DISPLAY = axis
CYCLE_TIME = 0.100
HELP_FILE = doc/help.txt
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 1.2
MAX_SPINDLE_OVERRIDE = 1.0
MAX_LINEAR_VELOCITY = 1.2
DEFAULT_LINEAR_VELOCITY = .25
PROGRAM_PREFIX = ../../nc_files/
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
#EDITOR = geany
TOOL_EDITOR = tooledit
INCREMENTS = 1 in, 0.1 in, 10 mil, 1 mil, 1mm, .1mm, 1/8000 in
[FILTER]
PROGRAM_EXTENSION = .png,.gif,.jpg Grayscale Depth Image
PROGRAM_EXTENSION = .py Python Script
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[RS274NGC]
PARAMETER_FILE = sim.var
SUBROUTINE_PATH = ../../nc_files/gladevcp_lib
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TASK]
TASK = milltask
CYCLE_TIME = 0.001
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
POSTGUI_HALFILE= manual-example.hal
[TRAJ]
COORDINATES = X Y Z
HOME = 0 0 0
LINEAR_UNITS = inch
ANGULAR_UNITS = degree
DEFAULT_LINEAR_VELOCITY = 1.2
POSITION_FILE = position.txt
MAX_LINEAR_VELOCITY = 1.2
NO_FORCE_HOMING = 1
[EMCIO]
TOOL_TABLE = sim.tbl
TOOL_CHANGE_POSITION = 0 0 0
TOOL_CHANGE_QUILL_UP = 1
[KINS]
KINEMATICS = trivkins
JOINTS = 3
[AXIS_X]
HOME = 0.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
[JOINT_0]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
HOME_OFFSET = 0.0
HOME_SEARCH_VEL = 20.0
HOME_LATCH_VEL = 20.0
HOME_SEQUENCE = 1
[AXIS_Y]
HOME = 0.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
[JOINT_1]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
HOME_OFFSET = 0.0
HOME_SEARCH_VEL = 20.0
HOME_LATCH_VEL = 20.0
HOME_SEQUENCE = 1
[AXIS_Z]
HOME = 0.0
MIN_LIMIT = -8.0
MAX_LIMIT = 0.0001
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
[JOINT_2]
TYPE = LINEAR
HOME = 0.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 100.0
MIN_LIMIT = -8.0
MAX_LIMIT = 0.0001
HOME_OFFSET = 1.0
HOME_SEARCH_VEL = 20.0
HOME_LATCH_VEL = 20.0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,57 @@
; caveat - this changes feed and abs/relative mode
O<probe> SUB
(print, _Probe_Axis= #<_Probe_Axis>)
(print, _Probe_Speed = #<_Probe_Speed>)
(print, _Probe_Retract = #<_Probe_Retract>)
(print, _Probe_Distance = #<_Probe_Distance>)
(print, _Probe_Diameter = #<_Probe_Diameter>)
(print, _Probe_System = #<_Probe_System>)
O<xaxis> if [#<_Probe_Axis> eq 0]
G91 G38.3 X#<_Probe_Distance> F#<_Probe_Speed>
O<xresult> if [#5070]
(MSG, probe succeeded)
G10 L20 P#<_Probe_System> X#<_Probe_Diameter>
G90 G0 X#<_Probe_Retract>
O<xresult> else
(MSG,probe failed)
G91 G0 X[0 - #<_Probe_Distance>]
O<xresult> endif
G90
O<xaxis> endif
O<yaxis> if [#<_Probe_Axis> eq 1]
G91 G38.3 y#<_Probe_Distance> F#<_Probe_Speed>
O<yresult> if [#5070]
(MSG, probe succeeded)
G10 L20 P#<_Probe_System> y#<_Probe_Diameter>
G90 G0 y#<_Probe_Retract>
O<yresult> else
(MSG,probe failed)
G91 G0 y[0 - #<_Probe_Distance>]
O<yresult> endif
G90
O<yaxis> endif
O<zaxis> if [#<_Probe_Axis> eq 2]
G91 G38.3 z#<_Probe_Distance> F#<_Probe_Speed>
O<zresult> if [#5070]
(MSG, probe succeeded)
G10 L20 P#<_Probe_System> z#<_Probe_Diameter>
G90 G0 z#<_Probe_Retract>
O<zresult> else
(MSG,probe failed)
G91 G0 z[0 - #<_Probe_Distance>]
O<zresult> endif
G90
O<zaxis> endif
O<probe> endsub
M2

View File

@@ -0,0 +1,4 @@
T1 P1 D0.125000 Z+0.511000 ;1/8 end mill
T2 P2 D0.062500 Z+0.100000 ;1/16 end mill
T3 P3 D0.201000 Z+1.273000 ;#7 tap drill
T98876 P543 Z+0.100000 ;big tool number

View File

@@ -0,0 +1,27 @@
o<rcone> sub
#<rmax> = #1 (= 10)
#<rmin> = #2 (= 1)
#<del_r> = #3 (= 0.001)
#<del_z> = #4 (= -0.001)
#<del_theta> = #5 (= +1 1:CCW -1:CW)
#<frate> = #6 (=100)
#<r> = #<rmax>
#<z> = 0
#<theta> = 0
f #<frate>
g0 x#<r> y0
o<10wh> while [#<r> gt #<rmin>]
#<r> = [#<r> - #<del_r>]
#<theta> = [#<theta> + #<del_theta>]
#<x> = [#<r> * cos[#<theta>]]
#<y> = [#<r> * sin[#<theta>]]
#<z> = [#<z> + #<del_z>]
;#<x> = [#<rmax> * cos[#<theta>]]
;#<y> = [#<rmax> * sin[#<theta>]]
;#<z> = [0 + #<del_z>]
g1 x#<x> y#<y> z#<z>
o<10wh> endwhile
o<rcone> endsub

View File

@@ -0,0 +1,11 @@
f1000
#<v> = 10
g0 x #<v> y 0 z 0
g1 x #<v> y #<v>
g1 x -#<v> y #<v>
g1 x -#<v> y -#<v>
g1 x #<v> y -#<v>
g1 x #<v> y 0
g0 z 0
o<rcone> call [#<v>][1][0.001][-0.001][+1][100]
m2

View File

@@ -0,0 +1,84 @@
[APPLICATIONS]
APP = halshow rose_engine.halshow
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = inch
ANGULAR_UNITS = degree
DEFAULT_LINEAR_VELOCITY = 10
MAX_LINEAR_VELOCITY = 10
[KINS]
KINEMATICS = rosekins
JOINTS = 3
[EMC]
VERSION = 1.1
MACHINE = Roseengine
[DISPLAY]
DISPLAY = axis
OPEN_FILE = ./rcone_demo.ngc
POSITION_OFFSET = RELATIVE
MAX_LINEAR_VELOCITY = 10
DEFAULT_LINEAR_VELOCITY = 10
MAX_ANGULAR_VELOCITY = 72
DEFAULT_ANGULAR_VELOCITY = 72
MAX_FEED_OVERRIDE = 2
TOOL_EDITOR = tooledit
INCREMENTS = 1 in,0.1in,10mil,1mil
TKPKG = Ngcgui 1.0
NGCGUI_SUBFILE = rcone.ngc
NGCGUI_FONT = Helvetica -14 normal
[RS274NGC]
PARAMETER_FILE = /tmp/rose.var
SUBROUTINE_PATH = .
[TASK]
TASK = milltask
CYCLE_TIME = 0.001
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
[EMCIO]
TOOL_TABLE = rose.tbl
[AXIS_X]
MAX_VELOCITY = 3
MAX_ACCELERATION = 30
[AXIS_Y]
MAX_VELOCITY = 3
MAX_ACCELERATION = 30
[AXIS_Z]
MAX_VELOCITY = 3
MAX_ACCELERATION = 30
# Notes:
# HOME_SEARCH_VEL=0 for immediate homing
# HOME_SEQUENCE=0 for homeall in gui
[JOINT_0]
TYPE = LINEAR
MAX_VELOCITY = 3
MAX_ACCELERATION = 30
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = LINEAR
MAX_VELOCITY = 3
MAX_ACCELERATION = 30
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = ANGULAR
MAX_VELOCITY = 72
MAX_ACCELERATION = 360
HOME_SEARCH_VEL = 0
HOME_SEQUENCE = 0

View File

@@ -0,0 +1,93 @@
(Preamble)
G90 G64 P0.1 Q1
(Switch to Joint mode trivial kinematics)
M429
(When using "Joint" mode we need to make sure that)
(the offsets are set correctly for the pose we used)
(when we set up the Modified DH-Parameters for the )
("genserkins" kinematic where we cannot define 'Theta')
(-values.)
("M429" sets offsets to "G59.2" and resets those)
(to "G10 L2 P8 X0 Y-90 Z0 A0 B0 C0" so we match the DH-)
(Parameter model used in the genserkins kinematics)
(Note that this pose leaves Joint_3 and Joint_5 collinear)
(and that will cause the inverse kinematics to fail so we)
(need to make sure that the wrist does not start out at)
(zero degrees.)
(Note that we also change speed settings through HAL when)
(we switch kinematics)
(Set the start pose to make sure the kinematics can handle it)
G01 X0 Y0 Z0 A0 B0 C0 F1000
(Switch to Coordinated, i.e. cartesian, world mode)
M428
("M428" sets offsets to "G59.1" and resets those)
(to "G10 L2 P7 X0 Y0 Z0 A0 B0 C0")
(Origin is at bottom center of the robot base)
(So to use other, nonzero, offsets we need to declare after)
(each switch of the kinematics)
G0 X450 Y200 Z350 B10 C45
(Draw a cube of 150mm)
G91
G0 Y150
X150
Y-150
X-150
Z150
Y150
Z-150
Z150
X150
Z-150
Z150
Y-150
Z-150
Z150
X-150
(Switch to Joint mode trivial kinematics)
M429
(Go different pose)
G90
G0 X90 Y0 Z0 A0
(Switch to Coordinated, i.e. cartesian, world mode)
M428
(Draw a cube of 150mm)
G91
G0
Z-150
Y150
X150
Y-150
X-150
Z150
Y150
Z-150
Z150
X150
Z-150
Z150
Y-150
Z-150
Z150
X-150
(Switch to Joint mode trivial kinematics)
M429
(Go to start pose)
G90
G0 X0 Y0 Z0 A0
M2

View File

@@ -0,0 +1,143 @@
[EMC]
VERSION = 1.1
MACHINE = melfa (mm)
DEBUG = 0
[KINS]
KINEMATICS= genserkins
JOINTS= 6
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
HALFILE = melfa_dh.hal
HALCMD = loadusr -W melfagui
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
POSTGUI_HALFILE = melfa-postgui.hal
[RS274NGC]
PARAMETER_FILE = melfa.var
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
RS274NGC_STARTUP_CODE = G10 L2 P7 X0 Y0 Z0 A-180 B0 C0 G59.1 (debug, ini: startup offsets)
[HALUI]
MDI_COMMAND = M429
MDI_COMMAND = M428
MDI_COMMAND = M430
[DISPLAY]
DISPLAY = axis
GEOMETRY = XYZABC
CYCLE_TIME = 0.200
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
DEFAULT_LINEAR_VELOCITY = 60.0
DEFAULT_ANGULAR_VELOCITY = 40.0
MAX_FEED_OVERRIDE = 2.0
PROGRAM_PREFIX = ./
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
PYVCP = melfa.xml
EDITOR = geany
OPEN_FILE = example.ngc
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TRAJ]
COORDINATES = X Y Z A B C
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 60.0
DEFAULT_ANGULAR_VELOCITY = 60.0
MAX_LINEAR_VELOCITY = 200.0
MAX_ANGULAR_VELOCITY = 100.0
DEFAULT_LINEAR_ACCELERATION = 200.0
MAX_LINEAR_ACCELERATION = 400.0
[EMCIO]
TOOL_TABLE = melfa.tbl
[JOINT_0]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -170.0
MAX_LIMIT = 170.0
HOME_SEQUENCE = 0
HOME_OFFSET = 0
HOME = 0
[JOINT_1]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -182.0
MAX_LIMIT = 45.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = -90.001
[JOINT_2]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -219.0
MAX_LIMIT = 76.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0.001
[JOINT_3]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -160.0
MAX_LIMIT = 160.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0.001
[JOINT_4]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -120.0
MAX_LIMIT = 120.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 90.001
[JOINT_5]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0.001
[AXIS_X]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
[AXIS_Y]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
[AXIS_Z]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
[AXIS_A]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
[AXIS_B]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
[AXIS_C]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0

View File

@@ -0,0 +1,4 @@
T1 P1 Z100 D0.125 ;1/8 end mill
T2 P2 Z0.1 D0.0625 ;1/16 end mill
T3 P3 Z1.273 D0.201 ;#7 tap drill
T99999 P99999 Z0.1 ;big tool number

View File

@@ -0,0 +1,28 @@
;M428 by remap: select genserkins
o<428remap>sub
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
#<kinstype> = 0 ; genserkins
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]FEATURE==8)
(debug,STOP)
M2
o1 endif
M66 E0 L0 ; force synch
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
G10 L2 P7 X0 Y0 Z0 A-180 B0 C0
G59.1
M66 E0 L0 ; force synch
; (debug, M428:genserkins)
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE 0]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,28 @@
;M429 by remap: select identity kins
o<429remap>sub
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
#<kinstype> = 1 ; identity kins
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]FEATURE==8)
(debug,STOP)
M2
o1 endif
M66 E0 L0 ; force synch
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
G10 L2 P8 X0 Y-90 Z0 A0 B90 C0
G59.2
M66 E0 L0 ; force synch
; (debug, M429:identity kins)
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE 1]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,26 @@
;M430 by remap: select gensertool kins
o<430remap>sub
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
#<kinstype> = 2 ; gensertool kins
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M430:Missing [RS274NGC]FEATURE==8)
(debug,STOP)
M2
o1 endif
M66 E0 L0 ; force synch
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
; (debug, M429:identity kins)
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE 2]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,212 @@
(setup work offsets to run sim w/o .var file)
G10 L2 P1 X-160 Y0 Z-230 (setup G54 for mill)
G10 L2 P2 X-275 Y0 Z-140 (setup G55 for turn)
(actual code starts here)
G21
G40
G64
M429 (turning)
G18 G8
G54
T05 M6 G43
G00 X20 Z25
G00 X13.5 Z1.0 S1000 M3
Z0.488
G94 G01 X-1.0 F1000.0
Z0.975
G00 X0.383 Z1.269
X13.5
Z0.0
G01 X-1.0
Z0.488
G00 X0.383 Z0.782
X13.5
Z1.0
Z2.0
X11.237
G01 Z-34.973 F1000.0
X12.2 Z-35.95
Z-37.95
X12.625
G00 X13.625 Z-36.95
Z2.0
X9.849
G01 Z-19.832
G00 X10.849 Z-18.832
Z2.0
X8.461
G01 Z-19.832
X9.849
G00 X10.849 Z-18.832
Z2.0
X7.073
G01 Z-10.296
G00 X8.073 Z-9.296
Z2.0
X5.685
G01 Z-8.784
G03 X7.073 Z-10.296 I-0.98513 K-2.29772
G00 X8.073 Z-9.296
Z2.0
X4.297
G01 Z-8.582
X4.7
G03 X5.685 Z-8.784 I-0.0 K-2.5
G00 X6.685 Z-7.784
Z2.0
X2.909
G01 Z-0.559
G00 X3.909 Z0.441
Z2.0
X1.521
G01 Z0.829
X2.909 Z-0.559
G00 X4.909 Z1.441
Z0.441
X2.909
G01 Z-0.559
X3.2 Z-0.85
Z-4.15
X2.909 Z-4.654
Z-8.11
G02 X4.2 Z-8.582 I1.29082 K1.52767
G01 X4.297
G00 X5.297 Z-7.582
Z-4.654
X3.909
G01 X2.909
X2.468 Z-5.418
G02 X2.2 Z-6.418 I1.73205 K-1.0
G01 Z-6.582
G02 X2.909 Z-8.11 I2.0 K0.0
G00 X3.909 Z-7.11
X7.073
Z-9.296
G01 Z-10.296
G03 X7.2 Z-11.082 I-2.3731 K-0.78638
G01 Z-11.382
G03 X7.073 Z-12.168 I-2.5 K0.0
G01 Z-19.832
X8.461
G00 X9.461 Z-18.832
Z-12.168
X8.073
G01 X7.073
G03 X6.485 Z-13.132 I-2.3731 K0.78638
G02 X5.685 Z-14.204 I3.57071 K-3.5
G01 Z-18.76
G02 X6.485 Z-19.832 I4.37094 K2.42793
G01 X7.073
G00 X8.073 Z-18.832
Z-14.204
X6.685
G01 X5.685
G02 X5.058 Z-16.482 I4.37075 K-2.42793
G02 X5.685 Z-18.76 I4.99775 K0.15
G00 X6.685 Z-17.76
X9.849
Z-18.832
G01 Z-19.832
X10.2
Z-20.132
X9.849 Z-20.74
Z-24.42
G00 X10.849 Z-23.42
Z-20.74
G01 X9.849
X8.787 Z-22.58
X9.849 Z-24.42
G00 X10.849 Z-23.42
X9.849
G01 Z-24.42
X10.2 Z-25.028
Z-27.328
G02 X9.849 Z-28.029 I5.70735 K-3.29514
G01 Z-32.917
G02 X11.214 Z-34.95 I6.0583 K2.594
G01 X11.237 Z-34.973
G00 X12.237 Z-33.973
Z-28.029
X10.849
G01 X9.849
G02 X9.319 Z-30.473 I6.05858 K-2.594
G02 X9.849 Z-32.917 I6.58858 K0.15
G00 X10.849 Z-31.917
Z-29.029
X11.237
Z2.0
X0.534 Z3.241
G01 X0.202 Z3.041 F150.0
G02 X1.081 Z0.919 I3.0 K0.0
G01 X3.0 Z-1.0
Z-4.0
X2.268 Z-5.268
G02 X2.0 Z-6.268 I1.73205 K-1.0
G01 Z-6.732
G02 X4.0 Z-8.732 I2.0 K0.0
G01 X4.5
G03 X6.285 Z-12.982 I-0.0 K-2.5
G02 Z-19.982 I3.57071 K-3.5
G01 X10.0
X8.5 Z-22.58
X10.0 Z-25.178
Z-27.178
G02 X11.014 Z-35.1 I5.70735 K-3.29514
G01 X12.0 Z-36.1
Z-38.1
G00 X15.0
Z10.0
M428 (milling)
g55
T10 m6 G43
g21 g17 g64 g90
s3400 m3
g0 z10
g0 x5 y0
g2 x-5 y0 i-5 j0 z-1 f500
g2 x5 y0 i5 j0 z-2
g2 x-5 y0 i-5 j0 z-3
g2 x5 y0 i5 j0 z-4
g2 x-5 y0 i-5 j0 z-4
g0 z10
g0 a90
g0 x5 y0
g2 x-5 y0 i-5 j0 z-1
g2 x5 y0 i5 j0 z-2
g2 x-5 y0 i-5 j0 z-3
g2 x5 y0 i5 j0 z-4
g2 x-5 y0 i-5 j0 z-4
g0 z10
g0 a180
g0 x5 y0
g2 x-5 y0 i-5 j0 z-1
g2 x5 y0 i5 j0 z-2
g2 x-5 y0 i-5 j0 z-3
g2 x5 y0 i5 j0 z-4
g2 x-5 y0 i-5 j0 z-4
g0 z10
g0 a270
g0 x5 y0
g2 x-5 y0 i-5 j0 z-1
g2 x5 y0 i5 j0 z-2
g2 x-5 y0 i-5 j0 z-3
g2 x5 y0 i5 j0 z-4
g2 x-5 y0 i-5 j0 z-4
g0 z10
g0 a360
M428 (milling)
G54
G0 X0 Z100 A0
M2
%

View File

@@ -0,0 +1,145 @@
[APPLICATIONS]
APP = halshow ./millturn.halshow
[EMC]
VERSION = 1.1
MACHINE = millturn (mm)
DEBUG = 0
[KINS]
KINEMATICS = millturn
JOINTS= 4
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
HALFILE = millturn.hal
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
POSTGUI_HALFILE = millturn-postgui.hal
[RS274NGC]
USER_M_PATH = ./mcodes
PARAMETER_FILE = millturn.var
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
# Set startup offsets
RS274NGC_STARTUP_CODE = G10 L2 P7 X-290 Y0 Z-160 A0 G59.1
[HALUI]
# MDI-COMMANDS 00, 01 (remapped) for switching kinematics and limits:
# M428: mill (kinstype==0 startupDEFAULT)
# M429: turn (kinstype==1)
MDI_COMMAND = M428
MDI_COMMAND = M429
# MDI-COMMANDS 02, 03 are for altering limits when switching
# Note that M129 and M129 are not meant to be called directly.
MDI_COMMAND = M128
MDI_COMMAND = M129
[DISPLAY]
DISPLAY = axis
GEOMETRY = XYZA
CYCLE_TIME = 0.200
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
DEFAULT_LINEAR_VELOCITY = 60.0
DEFAULT_ANGULAR_VELOCITY = 40.0
MAX_FEED_OVERRIDE = 2.0
PROGRAM_PREFIX = ./
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
PYVCP = millturn.xml
EDITOR = geany
OPEN_FILE = example.ngc
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TRAJ]
COORDINATES = X Y Z A
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 60.0
DEFAULT_ANGULAR_VELOCITY = 60.0
MAX_LINEAR_VELOCITY = 200.0
MAX_ANGULAR_VELOCITY = 100.0
DEFAULT_LINEAR_ACCELERATION = 200.0
MAX_LINEAR_ACCELERATION = 400.0
[EMCIO]
TOOL_TABLE = millturn.tbl
[JOINT_0]
TYPE = LINEAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -300
MAX_LIMIT = 300
HOME_SEQUENCE = 0
HOME_OFFSET = 0
HOME = 0
[JOINT_1]
TYPE = LINEAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -100
MAX_LIMIT = 100
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0
[JOINT_2]
TYPE = LINEAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
MIN_LIMIT = -240
MAX_LIMIT = 0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0
[JOINT_3]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
HOME_OFFSET = 0.0
HOME_SEQUENCE = 0
HOME = 0.001
[AXIS_X]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
# define softlimits for default kinematic (mill)
MIN_LIMIT = -300
MAX_LIMIT = 300
# define softlimits for alternate kinematic (turn)
MIN_LIMIT_TURN = -240
MAX_LIMIT_TURN = 0
[AXIS_Y]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
# define softlimits for default kinematic (mill)
MIN_LIMIT = -100
MAX_LIMIT = 100
# define softlimits for alternate kinematic (turn)
MIN_LIMIT_TURN = -100
MAX_LIMIT_TURN = 100
[AXIS_Z]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0
# define softlimits for default kinematic (mill)
MIN_LIMIT = -240
MAX_LIMIT = 0
# define softlimits for alternate kinematic (turn)
MIN_LIMIT_TURN = -300
MAX_LIMIT_TURN = 300
[AXIS_A]
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 400.0

View File

@@ -0,0 +1,11 @@
T1 P1 X30 Z30 D0.1 I95.000000 J155.000000 Q1
T2 P2 X40 Z40 D0.1 I85.000000 J25.000000 Q2
T3 P3 X50 Z50 D0.1 I275.000000 J335.000000 Q3
T4 P4 X30 Z30 D0.1 I265.000000 J205.000000 Q4
T5 P5 X40 Z40 D0.1 I210.000000 J150.000000 Q5
T6 P6 X50 Z50 D0.1 I120.000000 J60.000000 Q6
T7 P7 X30 Z30 D0.1 I-30.000000 J30.000000 Q7
T8 P8 X40 Z40 D0.1 I240.000000 J300.000000 Q8
T9 P9 X50 Z50 D0.1 Q9
T10 P10 Z50 D5 ;5 mm end mill
T11 P11 Z80 D10

View File

@@ -0,0 +1,29 @@
;M428 by remap: select mill kins
o<428remap>sub
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
#<kinstype> = 0 ; mill
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing)
(debug,STOP)
M2
o1 endif
M66 E0 L0 ; force synch
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M128 ; switch limits
G10 L2 P7 X-290 Y0 Z-160 A0 ; reset home offset
G59.1 ; activate home offset
M66 E0 L0 ; force synch
;(debug, M428: mill)
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE 0]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,29 @@
;M429 by remap: select turn kins
o<429remap>sub
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
#<kinstype> = 1 ; turn kins
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]FEATURE==8)
(debug,STOP)
M2
o1 endif
M66 E0 L0 ; force synch
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M129 ; switch limits
G10 L2 P8 X-160 Y0 Z-290 A0 ; reset home offset
G59.2 ; activate home offset
M66 E0 L0 ; force synch
;(debug, M429: turn)
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE 1]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,159 @@
[EMC]
VERSION = 1.1
MACHINE = PUMA (pumakins,switchkins)
DEBUG = 0
[KINS]
KINEMATICS = pumakins
JOINTS = 6
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
HALFILE = puma_dh.hal
HALCMD = loadusr -W pumagui
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
POSTGUI_HALFILE = puma_postgui.hal
[RS274NGC]
USER_M_PATH = ./mcodes
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
PARAMETER_FILE = puma.var
# G21 reqd here since this is mm config and default G20
RS274NGC_STARTUP_CODE = G21 G10L2P0 x450 y100 z-495 a-180 (debug, ini: startup offsets)
[HALUI]
# MDI-COMMANDS 00,01,02 (remapped) do not alter limits when switching:
# M428:pumakins (kinstype==0 startupDEFAULT)
# M429:identity kins (kinstype==1)
# M430:userk kins (kinstype==2)
MDI_COMMAND = M428
MDI_COMMAND = M429
MDI_COMMAND = M430
# MDI-COMMANDS 03,04,05 ALTER limits when switching
MDI_COMMAND = M128
MDI_COMMAND = M129
MDI_COMMAND = M130
[DISPLAY]
DISPLAY = axis
CYCLE_TIME = 0.200
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
DEFAULT_LINEAR_VELOCITY = 30.0
DEFAULT_ANGULAR_VELOCITY = 20.0
MAX_FEED_OVERRIDE = 2.0
PROGRAM_PREFIX = ../../nc_files/
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 5
PYVCP = puma.xml
EDITOR = geany
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = X Y Z A B C
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 30.0
DEFAULT_ANGULAR_VELOCITY = 30.0
MAX_LINEAR_VELOCITY = 100.0
MAX_ANGULAR_VELOCITY = 50.0
DEFAULT_LINEAR_ACCELERATION = 100.0
MAX_LINEAR_ACCELERATION = 200.0
[EMCIO]
TOOL_TABLE = puma.tbl
[JOINT_0]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -170.0
MAX_LIMIT = 170.0
HOME_SEQUENCE = 0
HOME_OFFSET = 0
HOME = 0
[JOINT_1]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -85
MAX_LIMIT = 50
HOME_OFFSET = 0
HOME = 0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -70
MAX_LIMIT = 75
HOME_OFFSET = 0
HOME = 0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -250
MAX_LIMIT = 250
HOME_SEQUENCE = 0
HOME = 0.000
[JOINT_4]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -120
MAX_LIMIT = 120
HOME = 0.000
HOME_SEQUENCE = 0
[JOINT_5]
TYPE = ANGULAR
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
MIN_LIMIT = -250
HOME = 0.000
HOME_SEQUENCE = 0
[AXIS_X]
MIN_LIMIT = 0
MAX_LIMIT = 650
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_Y]
MIN_LIMIT = -400
MAX_LIMIT = 400
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_Z]
MIN_LIMIT = -600
MAX_LIMIT = 400
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_A]
MIN_LIMIT = -250.0
MAX_LIMIT = 250.0
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_B]
MIN_LIMIT = -135.0
MAX_LIMIT = 135.0
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_C]
MIN_LIMIT = -250.0
MAX_LIMIT = 250.0
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0

View File

@@ -0,0 +1,4 @@
T1 P1 D0.125000 Z+0.511000 ;1/8 end mill
T2 P2 D0.062500 Z+0.100000 ;1/16 end mill
T3 P3 D0.201000 Z+1.273000 ;#7 tap drill
T99999 P99999 Z+0.100000 ;big tool number

View File

@@ -0,0 +1,138 @@
# NOTES:
# 1) [JOINT_4]HOME is a small value to avoid a singularity detected by pumakins
# 2) No [JOINT_N] or [AXIS_L] MIN_LIMIT,MAX_LIMIT items are used so that
# big system defaults apply and allow operation for many conditions that
# may not be representative of real hardware
# 3) ini vel/accel settings are for convenience and not realistic
# 4) To offset the initial homed position (0,0,0,0,0,0) for the coordinate
# coordinate system (p0), use coordinate setting commands:
# g10l2p0 x 450
# g10l2p0 y 100
# g10l2p0 z -495
# g10l2p0 a 180
# g10l2p0 b 0
# g10l2p0 c 0
[JOINT_0]
TYPE = ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[JOINT_1]
TYPE = ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[JOINT_2]
TYPE = ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[JOINT_3]
TYPE= ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[JOINT_4]
TYPE = ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[JOINT_5]
TYPE = ANGULAR
MAX_VELOCITY = 300.0
MAX_ACCELERATION = 2000.0
HOME_SEQUENCE = 0
[AXIS_X]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_Y]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_Z]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_A]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_B]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[AXIS_C]
MAX_VELOCITY = 30.0
MAX_ACCELERATION = 200.0
[DISPLAY]
OPEN_FILE = ./puma_cube.ngc
#alternate: OPEN_FILE = ./puma_seam_weld.ngc
DISPLAY = axis
CYCLE_TIME = 0.200
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
MAX_FEED_OVERRIDE = 2.0
PROGRAM_PREFIX = ../../nc_files
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 1
PYVCP = puma.xml
[EMC]
VERSION = 1.1
MACHINE = puma_cube.ini (pumakins)
[RS274NGC]
USER_M_PATH = ./mcodes
SUBROUTINE_PATH = ./remap_subs
HAL_PIN_VARS = 1
REMAP = M428 modalgroup=10 ngc=428remap
REMAP = M429 modalgroup=10 ngc=429remap
REMAP = M430 modalgroup=10 ngc=430remap
PARAMETER_FILE = puma.var
[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 1.0
SERVO_PERIOD = 1000000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[HAL]
HALUI = halui
HALFILE = LIB:basic_sim.tcl
HALFILE = puma_dh.hal
HALCMD = loadusr -W pumagui
HALCMD = net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type
POSTGUI_HALFILE = puma_postgui.hal
[HALUI]
# MDI-COMMANDS 00,01,02 (remapped) do not alter limits when switching:
# M428:pumakins (kinstype==0 startupDEFAULT)
# M429:identity kins (kinstype==1)
# M430:userk kins (kinstype==2)
MDI_COMMAND = M428
MDI_COMMAND = M429
MDI_COMMAND = M430
# MDI-COMMANDS 03,04,05 ALTER limits when switching
MDI_COMMAND = M128
MDI_COMMAND = M129
MDI_COMMAND = M130
[TRAJ]
COORDINATES = X Y Z A B C
LINEAR_UNITS = mm
ANGULAR_UNITS = deg
DEFAULT_LINEAR_VELOCITY = 30.0
MAX_LINEAR_VELOCITY = 1000.0
MAX_ANGULAR_VELOCITY = 10
DEFAULT_LINEAR_ACCELERATION = 100.0
MAX_LINEAR_ACCELERATION = 2000.0
[EMCIO]
TOOL_TABLE = puma.tbl
[KINS]
KINEMATICS = pumakins
JOINTS = 6

View File

@@ -0,0 +1,57 @@
; set offsets for current coordinate system (p0)
; pumakins JOINT HOME positions:
; [JOINT_0]HOME=0
; [JOINT_1]HOME=0
; [JOINT_2]HOME=0
; [JOINT_3]HOME=0
; [JOINT_4]HOME=0
; [JOINT_5]HOME=0
; pumakins hal settings:
; 400 pumakins.A2
; 50 pumakins.A3
; 100 pumakins.D3
; 400 pumakins.D4
; 95 pumakins.D6
;
; The following g10l2 commands set offsets for the
; above HOME positions and hal settings to establish
; (x,y,z,a,b,c)=(0,0,0,0,0,0) for the current system (p0):
g10l2p0 x 450
g10l2p0 y 100
g10l2p0 z -495
g10l2p0 a 180
g10l2p0 b 0
g10l2p0 c 0
(debug, puma_cube.ngc Set G54 offsets)
#<xmin> = -100
#<xmax> = 100
#<ymin> = -100
#<ymax> = 100
#<zmin> = -100
#<zmax> = 100
#<feedrate> = 1000
f #<feedrate>
g0 x#<xmin> y#<ymin> z#<zmin>
g1 x#<xmax>
g1 y#<ymax>
g1 x#<xmin>
g1 y#<ymin>
g1 z#<zmax>
g1 x#<xmax>
g1 y#<ymax>
g1 x#<xmin>
g1 y#<ymin>
g0 x#<xmax> y#<ymax>
g1 z#<zmin>
g0 x#<xmin>
g1 z#<zmax>
g0 x#<xmax> y#<ymin>
g1 z#<zmin>
g0 x#<xmin> y#<ymin> z#<zmin>
m2

View File

@@ -0,0 +1,20 @@
;useable with sim config: puma.ini
;This is a test plot nc program to be run on backplot
;Author Rdp 21-Dec-2017
g0 x0 y0 z10
g0 x50 y50
a-30
g1 z-10 f500
x-50
a0 b-30
y-50
a30 b0
x50
a0 b30
y50
a-30 b0
g0 z30
x0 y0 a0 b0
m30

View File

@@ -0,0 +1,24 @@
;M428 by remap: select kinstype=0 (default)
o<428remap>sub
#<kinstype> = 0
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M428:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M428: Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<428remap>endsub

View File

@@ -0,0 +1,24 @@
;M429 by remap: select kinstype==1 (Identity kinematics)
o<429remap>sub
#<kinstype> = 1
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M429:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M429:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<429remap>endsub

View File

@@ -0,0 +1,24 @@
;M430 by remap: select kinstype==2 (userk kins)
o<430remap>sub
#<kinstype> = 2
#<SWITCHKINS_PIN> = 3 ; set N as required: motion.analog-out-0N
o1 if [exists [#<_hal[motion.switchkins-type]>]]
o1 else
(debug,M30:Missing [RS274NGC]HAL_PIN_VARS=1)
(debug,STOP)
M2
o1 endif
M68 E#<SWITCHKINS_PIN> Q#<kinstype> ; set kinstype value
M66 E0 L0 ; force synch
o2 if [[#<_task> EQ 1] AND [#<_hal[motion.switchkins-type]> NE #<kinstype>]]
(debug,M430:Wrong motion.switchkins-type)
(debug,or missing hal net to analog-out-0x)
(debug,STOP)
M2
o2 else
o2 endif
o<430remap>endsub

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,255 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon
DEBUG = 0x00000000
[DISPLAY]
# sets qtdragon as screen. for debug output to terminal add -d or -v
# sets window title
# sets icon in task manager
DISPLAY = qtvcp qtdragon
TITLE = QtDragon XYYZ
ICON = silver_dragon.png
# qtdragon saves most preference to this file
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon.pref
# min/max percentage overrides allowed in qtdragon 1 = 100%
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
# manual spindle speed will start at this RPM
DEFAULT_SPINDLE_0_SPEED = 12000
# spindle up/down increment in RPM
SPINDLE_INCREMENT = 200
# min max apindle speed manually allowed
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
# max spindle power in Watts
MAX_SPINDLE_POWER = 2000
# min/max/default jog velocities in qtdragon in units/sec
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.0
# incremental jog step length options
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
CYCLE_TIME = 100
INTRO_GRAPHIC = silver_dragon.png
INTRO_TIME = 2
# default program search path
PROGRAM_PREFIX = ~/linuxcnc/nc_files
# NGCGUI subroutine path.
# Thr path must also be in [RS274NGC] SUBROUTINE_PATH
NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/
# pre selected programs tabs
# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH
NGCGUI_SUBFILE = slot.ngc
NGCGUI_SUBFILE = qpocket.ngc
# qtdragon saves MDI cxommands to this file
MDI_HISTORY_FILE = mdi_history.dat
# qtdragon saves rnning logs to this file
LOG_FILE = qtdragon.log
[MDI_COMMAND_LIST]
# for macro buttons on main oage up to 10 possible
MDI_COMMAND_MACRO0 = G0 Z25;X0 Y0;Z0, Goto\nUser\nZero
MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero
[FILTER]
# Controls what programs are shown inqtdragon file manager
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
# specifies what special 'filter' programs runs based on program ending
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[KINS]
KINEMATICS = trivkins coordinates=XYYZ kinstype=BOTH
JOINTS = 4
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
# motion controller saves parameters to this file
PARAMETER_FILE = qtdragon.var
# start up G/M codes when first loaded
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9
# subroutine/remap path list
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs
# on abort, this ngc file is called. required for basic/versa probe
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYYZ
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALBRIDGE = hal_bridge
# loads the HAL machine simulation
HALFILE = gantrysim.hal
HALFILE = simulated-xyyz-home.hal
# this file is loaded after qtdragon has made it's HAl pins
# you can add multiple entries
POSTGUI_HALFILE = qtdragon_postgui.hal
# this command is run after qtdragon has made it's HAl pins
# any HAL conmmand can be used
# you can add multiple entries
# uncomment this one to print all HAL pins that start with qt
#POSTGUI_HALCMD = show pin qt
[HALUI]
# no content
[PROBE]
# pick basic probe or versa probe or remove for none
#USE_PROBE = versaprobe
USE_PROBE = basicprobe
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
# used by external offsets for auto spindle lift
OFFSET_AV_RATIO = 0.2
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = -0.1
HOME_SEARCH_VEL = -20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = -0.1
HOME_SEARCH_VEL = -20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = -1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = -0.1
HOME_SEARCH_VEL = -20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = -1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_3]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.1
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,266 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon_inch
DEBUG = 0x00000000
[DISPLAY]
# sets qtdragon as screen. for debug output to terminal add -d or -v
# sets window title
# sets icon in task manager
DISPLAY = qtvcp qtdragon
TITLE = QtDragon XYZ Inch
ICON = silver_dragon.png
# qtdragon saves most preference to this file
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon.pref
# min/max percentage overrides allowed in qtdragon 1 = 100%
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
# manual spindle speed will start at this RPM
DEFAULT_SPINDLE_0_SPEED = 12000
# spindle up/down increment in RPM
SPINDLE_INCREMENT = 200
# min max apindle speed manually allowed
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
# max spindle power in Watts
MAX_SPINDLE_POWER = 2000
# min/max/default jog velocities in qtdragon in units/second
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 1.00
DEFAULT_LINEAR_VELOCITY = 0.25
# incremental jog step length options
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
# Display grid increments
GRIDS = 0, .1 mm, 1 mm, 2 mm, 5 mm, 10 mm, .25 in, .5 in
CYCLE_TIME = 100
INTRO_GRAPHIC = silver_dragon.png
INTRO_TIME = 2
# default program search path
PROGRAM_PREFIX = ~/linuxcnc/nc_files
# NGCGUI subroutine path.
# Thr path must also be in [RS274NGC] SUBROUTINE_PATH
NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/
# pre selected programs tabs
# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH
NGCGUI_SUBFILE = slot.ngc
NGCGUI_SUBFILE = qpocket.ngc
# qtdragon saves MDI cxommands to this file
MDI_HISTORY_FILE = mdi_history.dat
# qtdragon saves rnning logs to this file
LOG_FILE = qtdragon.log
# optional user dialogs (3), controlled by HAL pins
# persistent
MESSAGE_BOLDTEXT = Critical and Persistent
MESSAGE_TEXT = This is a persistent dialog test
MESSAGE_DETAILS = There seems to be something wrong\n You must fix it to clear message
MESSAGE_TYPE = nonedialog
MESSAGE_PINNAME = nonedialogtest
MESSAGE_ICON = CRITICAL
# yes no choice
MESSAGE_BOLDTEXT = Do You Want To Make A Choice?
MESSAGE_TEXT = This is a yes no dialog test
MESSAGE_DETAILS = Y/N DETAILS
MESSAGE_TYPE = yesnodialog
MESSAGE_PINNAME = yndialogtest
MESSAGE_ICON = QUESTION
# acknowledge
MESSAGE_BOLDTEXT = This is an information message
MESSAGE_TEXT = This is low priority
MESSAGE_DETAILS = press ok to clear
MESSAGE_TYPE = okdialog status
MESSAGE_PINNAME = bothtest
MESSAGE_ICON = INFO
# optional tab showing an external qtvcp panel
EMBED_TAB_NAME=Vismach demo
EMBED_TAB_COMMAND=qtvcp vismach_mill_xyz
EMBED_TAB_LOCATION=tabWidget_utilities
[MDI_COMMAND_LIST]
# for macro buttons on main oage up to 10 possible
MDI_COMMAND_MACRO0 = G0 Z2;X0 Y0;Z0, Goto\nUser\nZero
MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero
[FILTER]
# Controls what programs are shown inqtdragon file manager
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
# specifies what special 'filter' programs runs based on program ending
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[KINS]
KINEMATICS = trivkins coordinates=XYZ
JOINTS = 3
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
# motion controller saves parameters to this file
PARAMETER_FILE = qtdragon.var
# start up G/M codes when first loaded
RS274NGC_STARTUP_CODE = G17 G20 G40 G43H0 G54 G64P0.0005 G80 G90 G94 G97 M5 M9
# subroutine/remap path list
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs
# on abort, this ngc file is called. required for basic/versa probe
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = inch
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALBRIDGE = hal_bridge
# loads the HAL machine simulation
HALFILE = core_sim.hal
HALFILE = simulated_home.hal
# this file is loaded after qtdragon has made it's HAl pins
# you can add multiple entries
POSTGUI_HALFILE = qtdragon_postgui.hal
# this command is run after qtdragon has made it's HAl pins
# any HAL conmmand can be used
# you can add multiple entries
# uncomment this one to print all HAL pins that start with qt
#POSTGUI_HALCMD = show pin qt
[HALUI]
# no content
[PROBE]
# pick basic probe or versa probe or remove for none
#USE_PROBE = versaprobe
USE_PROBE = basicprobe
[AXIS_X]
MIN_LIMIT = -0.01
MAX_LIMIT = 20.0
MAX_VELOCITY = 2.5
MAX_ACCELERATION = 20
[AXIS_Y]
MIN_LIMIT = -0.01
MAX_LIMIT = 25.0
MAX_VELOCITY = 2.5
MAX_ACCELERATION = 20.0
[AXIS_Z]
# used by external offsets for auto spindle lift
OFFSET_AV_RATIO = 0.2
MIN_LIMIT = -4.5
MAX_LIMIT = 0.5
MAX_VELOCITY = 1.5
MAX_ACCELERATION = 20.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.01
MAX_LIMIT = 20.0
MAX_VELOCITY = 2.5
MAX_ACCELERATION = 20.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 2.75
STEPGEN_MAX_ACC = 24.0
FERROR = 0.050
MIN_FERROR = 0.010
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 0.75
HOME_OFFSET = 0.00000
HOME_SEARCH_VEL = 0.75
HOME_LATCH_VEL = 0.5
HOME_SEQUENCE = 1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.01
MAX_LIMIT = 25.0
MAX_VELOCITY = 2.5
MAX_ACCELERATION = 20.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 2.75
STEPGEN_MAX_ACC = 24.0
FERROR = 0.050
MIN_FERROR = 0.010
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 0.75
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 0.75
HOME_LATCH_VEL = 0.5
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -4.5
MAX_LIMIT = 0.5
MAX_VELOCITY = 1.5
MAX_ACCELERATION = 20.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 1.5
STEPGEN_MAX_ACC = 24.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -0.5
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 0.75
HOME_LATCH_VEL = 0.5
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,255 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon
DEBUG = 0x00000000
[DISPLAY]
# sets qtdragon as screen. for debug output to terminal add -d or -v
# sets window title
# sets icon in task manager
DISPLAY = qtvcp qtdragon
TITLE = QtDragon XYZA Rotational Axis
ICON = silver_dragon.png
# qtdragon saves most preference to this file
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon.pref
# min/max percentage overrides allowed in qtdragon 1 = 100%
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
# manual spindle speed will start at this RPM
DEFAULT_SPINDLE_0_SPEED = 12000
# spindle up/down increment in RPM
SPINDLE_INCREMENT = 200
# min max apindle speed manually allowed
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
# max spindle power in Watts
MAX_SPINDLE_POWER = 2000
# min/max/default jog velocities in qtdragon in units/sec
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 25.0
DEFAULT_ANGULAR_VELOCITY = 10
MIN_ANGULAR_VELOCITY = 1
MAX_ANGULAR_VELOCITY = 360
# incremental jog step length options
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
CYCLE_TIME = 100
INTRO_GRAPHIC = silver_dragon.png
INTRO_TIME = 2
# default program search path
PROGRAM_PREFIX = ~/linuxcnc/nc_files
# NGCGUI subroutine path.
# Thr path must also be in [RS274NGC] SUBROUTINE_PATH
NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/
# pre selected programs tabs
# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH
NGCGUI_SUBFILE = slot.ngc
NGCGUI_SUBFILE = qpocket.ngc
# qtdragon saves MDI cxommands to this file
MDI_HISTORY_FILE = mdi_history.dat
# qtdragon saves rnning logs to this file
LOG_FILE = qtdragon.log
[MDI_COMMAND_LIST]
# for macro buttons on main oage up to 10 possible
MDI_COMMAND_MACRO0 = G0 Z25;X0 Y0;Z0, Goto\nUser\nZero
MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero
[FILTER]
# Controls what programs are shown inqtdragon file manager
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
# specifies what special 'filter' programs runs based on program ending
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[KINS]
KINEMATICS = trivkins coordinates=XYZA
JOINTS = 4
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
# motion controller saves parameters to this file
PARAMETER_FILE = qtdragon.var
# start up G/M codes when first loaded
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9
# subroutine/remap path list
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs
# on abort, this ngc file is called. required for basic/versa probe
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
#NUM_AIO = 12
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZA
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALBRIDGE = hal_bridge
# loads the HAL machine simulation
HALFILE = gantrysim.hal
HALFILE = simulated-gantry-home.hal
# this file is loaded after qtdragon has made it's HAl pins
# you can add multiple entries
POSTGUI_HALFILE = qtdragon_postgui.hal
# this command is run after qtdragon has made it's HAl pins
# any HAL conmmand can be used
# you can add multiple entries
# uncomment this one to print all HAL pins that start with qt
#POSTGUI_HALCMD = show pin qt
[HALUI]
# no content
[PROBE]
# pick basic probe or versa probe or remove for none
#USE_PROBE = versaprobe
USE_PROBE = basicprobe
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[AXIS_A]
MAX_VELOCITY = 60
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = -0.1
HOME_SEARCH_VEL = -20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = -0.1
HOME_SEARCH_VEL = -20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = -1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.1
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_3]
TYPE = ANGULAR
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
INPUT_SCALE = 40
OUTPUT_SCALE = 1.0
FERROR = 5.0
MIN_FERROR = 1.0
HOME = 0
HOME_SEARCH_VEL = 0.0
HOME_LATCH_VEL = 0.0
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,241 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon
DEBUG = 0x00000000
[DISPLAY]
# sets qtdragon_hd as screen. for debug output to terminal add -d or -v
# sets window title
# sets icon in task manager
DISPLAY = qtvcp qtdragon_hd_vert
TITLE = QtDragon HD Vertical: XYZ
ICON = silver_dragon.png
# qtdragon saves most preference to this file
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon_hd_vert.pref
# min/max percentage overrides allowed in qtdragon 1 = 100%
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
# manual spindle speed will start at this RPM
DEFAULT_SPINDLE_0_SPEED = 12000
# spindle up/down increment in RPM
SPINDLE_INCREMENT = 200
# min max apindle speed manually allowed
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
# max spindle power in Watts
MAX_SPINDLE_POWER = 2000
# min/max/default jog velocities in qtdragon in units/sec
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.0
#Prevent tool mark disappearing with small tool diameter in g-code preview widget
GCODE_VIEW_TOOL_MIN_DIA = 2.0
# incremental jog step length options
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
# Display grid increments
GRIDS = 0, .1 mm, 1 mm, 2 mm, 5 mm, 10 mm, .25 in, .5 in
CYCLE_TIME = 100
INTRO_GRAPHIC = silver_dragon.png
INTRO_TIME = 2
# default program search path
PROGRAM_PREFIX = ~/linuxcnc/nc_files
# NGCGUI subroutine path.
# Thr path must also be in [RS274NGC] SUBROUTINE_PATH
NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/
# pre selected programs tabs
# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH
NGCGUI_SUBFILE = slot.ngc
NGCGUI_SUBFILE = qpocket.ngc
# qtdragon saves MDI cxommands to this file
MDI_HISTORY_FILE = mdi_history.dat
# qtdragon saves rnning logs to this file
LOG_FILE = qtdragon_hd.log
[MDI_COMMAND_LIST]
# for macro buttons
MDI_COMMAND = G0 Z25 X0 Y0;Z0,Goto\nZero
MDI_COMMAND = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMach\nZero
[FILTER]
# Controls what programs are shown inqtdragon file manager
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
# specifies what special 'filter' programs runs based on program ending
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[KINS]
KINEMATICS = trivkins coordinates=XYZ
JOINTS = 3
[EMCIO]
EMCIO = io
CYCLE_TIME = 0.100
TOOL_TABLE = tool.tbl
[RS274NGC]
# motion controller saves parameters to this file
PARAMETER_FILE = qtdragon.var
# start up G/M codes when first loaded
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9
# subroutine/remap path list
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs
# on abort, this ngc file is called. required for basic/versa probe
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALBRIDGE = hal_bridge
HALFILE = core_sim.hal
HALFILE = simulated_home.hal
# this file is loaded after qtdragon has made it's HAl pins
# you can add multiple entries
POSTGUI_HALFILE = qtdragon_hd_postgui.hal
# this command is run after qtdragon has made it's HAl pins
# any HAL conmmand can be used
# you can add multiple entries
# uncomment this one to print all HAL pins that start with qt
#POSTGUI_HALCMD = show pin qt
# uncomment to simulate probing
#POSTGUI_HALCMD = loadusr qtvcp test_probe
[HALUI]
# no content
[PROBE]
# pick basic probe or versa probe or remove for none
#USE_PROBE = versaprobe
USE_PROBE = basicprobe
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
# used by external offsets for auto spindle lift and auto leveling
OFFSET_AV_RATIO = 0.2
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.00000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,233 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon
DEBUG = 0x00000000
[DISPLAY]
# sets qtdragon_hd as screen. for debug output to terminal add -d or -v
# sets window title
# sets icon in task manager
DISPLAY = qtvcp -d qtdragon_hd
TITLE = QtDragon HD: XYZ
ICON = silver_dragon.png
# qtdragon saves most preference to this file
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon_hd.pref
# min/max percentage overrides allowed in qtdragon 1 = 100%
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
# manual spindle speed will start at this RPM
DEFAULT_SPINDLE_0_SPEED = 12000
# spindle up/down increment in RPM
SPINDLE_INCREMENT = 200
# min max apindle speed manually allowed
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
# max spindle power in Watts
MAX_SPINDLE_POWER = 2000
# min/max/default jog velocities in qtdragon in units/sec
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.0
# incremental jog step length options
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
CYCLE_TIME = 100
INTRO_GRAPHIC = silver_dragon.png
INTRO_TIME = 2
# default program search path
PROGRAM_PREFIX = ~/linuxcnc/nc_files
# NGCGUI subroutine path.
# Thr path must also be in [RS274NGC] SUBROUTINE_PATH
NGCGUI_SUBFILE_PATH = ../../../nc_files/ngcgui_lib/
# pre selected programs tabs
# specify filenames only, files must be in the NGCGUI_SUBFILE_PATH
NGCGUI_SUBFILE = slot.ngc
NGCGUI_SUBFILE = qpocket.ngc
# qtdragon saves MDI cxommands to this file
MDI_HISTORY_FILE = mdi_history.dat
# qtdragon saves rnning logs to this file
LOG_FILE = qtdragon_hd.log
[MDI_COMMAND_LIST]
# for macro buttons
MDI_COMMAND_MACRO0 = G0 Z25 X0 Y0;Z0,Goto\nZero
MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMach\nZero
[FILTER]
# Controls what programs are shown inqtdragon file manager
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
# specifies what special 'filter' programs runs based on program ending
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python
[KINS]
KINEMATICS = trivkins coordinates=XYZ
JOINTS = 3
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
# motion controller saves parameters to this file
PARAMETER_FILE = qtdragon.var
# start up G/M codes when first loaded
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.0127 G80 G90 G94 G97 M5 M9
# subroutine/remap path list
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib:~/linuxcnc/nc_files/examples/ngcgui_lib/utilitysubs
# on abort, this ngc file is called. required for basic/versa probe
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALBRIDGE = hal_bridge
HALFILE = core_sim.hal
HALFILE = simulated_home.hal
# this file is loaded after qtdragon has made it's HAl pins
# you can add multiple entries
POSTGUI_HALFILE = qtdragon_hd_postgui.hal
# this command is run after qtdragon has made it's HAl pins
# any HAL conmmand can be used
# you can add multiple entries
# uncomment this one to print all HAL pins that start with qt
#POSTGUI_HALCMD = show pin qt
# uncomment to simulate probing
#POSTGUI_HALCMD = loadusr qtvcp test_probe
[HALUI]
# no content
[PROBE]
# pick basic probe or versa probe or remove for none
#USE_PROBE = versaprobe
USE_PROBE = basicprobe
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
# used by external offsets for auto spindle lift and auto leveling
OFFSET_AV_RATIO = 0.2
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.00000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,239 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = qtdragon
DEBUG = 0x00000000
[DISPLAY]
DISPLAY = qtvcp qtdragon
PREFERENCE_FILE_PATH = WORKINGFOLDER/qtdragon.pref
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
GRIDS = 10mm 20mm 50mm 100mm 1in 2in 5in 10in
MAX_FEED_OVERRIDE = 1.2
MAX_RAPID_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
DEFAULT_SPINDLE_0_SPEED = 12000
SPINDLE_INCREMENT = 200
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.0
DEFAULT_LINEAR_JOG_VEL = 50.0
DEFAULT_ANGULAR_VELOCITY = 0
MIN_ANGULAR_VELOCITY = 0
MAX_ANGULAR_VELOCITY = 0
CYCLE_TIME = 100
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 2
PROGRAM_PREFIX = ~/linuxcnc/nc_files
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
MDI_HISTORY_FILE = mdi_history.dat
LOG_FILE = qtdragon.log
TOOL_EDITOR = tooledit
CONFIRM_EXIT = True
MESSAGE_BOLDTEXT = Critical and Persistent
MESSAGE_TEXT = This is a persistent dialog test
MESSAGE_DETAILS = There seems to be something wrong\n You must fix it to clear message
MESSAGE_TYPE = nonedialog
MESSAGE_PINNAME = nonedialogtest
MESSAGE_ICON = CRITICAL
MESSAGE_BOLDTEXT = Do You Want To Make A Choice?
MESSAGE_TEXT = This is a yes no dialog test
MESSAGE_DETAILS = Y/N DETAILS
MESSAGE_TYPE = yesnodialog
MESSAGE_PINNAME = yndialogtest
MESSAGE_ICON = QUESTION
MESSAGE_BOLDTEXT = This is an information message
MESSAGE_TEXT = This is low priority
MESSAGE_DETAILS = press ok to clear
MESSAGE_TYPE = okdialog status
MESSAGE_PINNAME = bothtest
MESSAGE_ICON = INFO
EMBED_TAB_NAME=Vismach demo
EMBED_TAB_COMMAND=qtvcp vismach_mill_xyz
EMBED_TAB_LOCATION=tabWidget_utilities
[MDI_COMMAND_LIST]
# for macro buttons
MDI_COMMAND = G0 Z25;X0 Y0;Z0, Goto\nUser\nZero
MDI_COMMAND = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero
[FILTER]
PROGRAM_EXTENSION = .ngc,.nc,.tap G-Code File (*.ngc,*.nc,*.tap)
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python
[KINS]
KINEMATICS = trivkins coordinates=XYZ
JOINTS = 3
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
PARAMETER_FILE = qtdragon.var
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros:~/linuxcnc/nc_files/examples/ngcgui_lib
FEATURES=12
ON_ABORT_COMMAND=O <on_abort> call
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALFILE = core_sim.hal
HALFILE = simulated_home.hal
#HALFILE = custom.hal
POSTGUI_HALFILE = qtdragon_postgui.hal
[HALUI]
# no content
[PROBE]
USE_PROBE = versaprobe
#USE_PROBE = basicprobe
[TOOLSENSOR]
X = 5.00
Y = 71.50
TOUCH_HEIGHT = 29.3
SENSOR_HEIGHT = 59.8
MAXPROBE = -40
SEARCH_VEL = 200
PROBE_VEL = 50
[LASER]
X = 106.9
Y = -16.85
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
OFFSET_AV_RATIO = 0.2
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.00000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[SPINDLE]
SPINDLE_TYPE = openLoop
SCALE =
PWM_FREQUENCY = 2000
MAX_RPM = 18000
MIN_RPM = 8000
DEADBAND = 0
P = 0
I = 0
D = 0
FF0 = 1
FF1 = 0
FF2 = 0
BIAS = 0
MAX_ERROR = 0

View File

@@ -0,0 +1,4 @@
T1 P1 X0 Y0 Z0.51100 A0 B0 C0 U0 V0 W0 D10.00000 I0 J0 Q0 ;1/8 end mill
T2 P2 X0 Y0 Z0.10000 A0 B0 C0 U0 V0 W0 D0.06250 I0 J0 Q0 ;1/16 end mill
T3 P3 X0 Y0 Z1.27300 A0 B0 C0 U0 V0 W0 D0.20100 I0 J0 Q0 ;#7 tap drill
T4 P4 X0 Y0 Z3.00000 A0 B0 C0 U0 V0 W0 D4.00000 I0 J0 Q0 ;4" Face Mill

View File

@@ -0,0 +1,31 @@
o<on_abort> sub
o100 if [#1 eq 5]
(machine on)
o100 elseif [#1 eq 6]
(machine off)
o100 elseif [#1 eq 7]
(estopped)
o100 elseif [#1 eq 8]
(msg,Process Aborted)
o100 else
(DEBUG,Abort Parameter is %d[#1])
o100 endif
o<on_abort> endsub
m2
These are potential abort number:
EMC_ABORT_TASK_EXEC_ERROR = 1,
EMC_ABORT_AUX_ESTOP = 2,
EMC_ABORT_MOTION_OR_IO_RCS_ERROR = 3,
EMC_ABORT_TASK_STATE_OFF = 4,
EMC_ABORT_TASK_STATE_ESTOP_RESET = 5,
EMC_ABORT_TASK_STATE_ESTOP = 6,
EMC_ABORT_TASK_STATE_NOT_ON = 7,
EMC_ABORT_TASK_ABORT = 8,
EMC_ABORT_INTERPRETER_ERROR = 9, // interpreter failed during readahead
EMC_ABORT_INTERPRETER_ERROR_MDI = 10, // interpreter failed during MDI execution
EMC_ABORT_USER = 100 // user-defined abort codes start here

View File

@@ -0,0 +1,29 @@
T90 P90 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D3.00000 I0 J0 Q0 ;PROBE
T0 P0 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D0 I0 J0 Q0 ;NO TOOL LOADED
T1 P1 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D1.58750 I0 J0 Q0 ;1/16" end mill
T2 P2 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D3.16000 I0 J0 Q0 ;1/8" end mill
T3 P3 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D2.86000 I0 J0 Q0 ;1/8" router bit
T4 P4 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.35000 I0 J0 Q0 ;1/4" straight router bit
T6 P5 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D0.12670 I0 J0 Q0 ;5/16" straight 25 mm flute
T6 P6 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D7.93750 I0 J0 Q0 ;5/16" straight 30 mm flute
T7 P7 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D12.70000 I0 J0 Q0 ;1/2" straight router bit
T8 P8 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D19.05000 I0 J0 Q0 ;3/4" bottom clearing
T9 P9 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.35000 I0 J0 Q0 ;1/4" single flute
T10 P10 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D3.17500 I0 J0 Q0 ;1/8" spot drill
T11 P11 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D3.17500 I0 J0 Q0 ;1/8" ball end
T12 P12 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.35000 I0 J0 Q0 ;1/4" ball end
T13 P13 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D9.52500 I0 J0 Q0 ;3/8" ball end
T14 P14 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D12.70000 I0 J0 Q0 ;1/2" ball end
T15 P15 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D12.70000 I0 J0 Q0 ;90 deg v-bit
T16 P16 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.35000 I0 J0 Q0 ;45/60 v-bit
T17 P17 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.35000 I0 J0 Q0 ;45/60 v-bit
T21 P21 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;6 mm straight ball end
T22 P22 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;6 mm straight ball end
T23 P23 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D1.00000 I0 J0 Q0 ;1 mm tapered ball end
T24 P24 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D1.00000 I0 J0 Q0 ;1 mm tapered ball end
T25 P25 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;60 deg v-bit 6mm shank
T26 P26 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;60 deg v-bit 6 mm shank
T31 P31 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D3.00000 I0 J0 Q0 ;3 mm router bit
T32 P32 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;6 mm router bit
T33 P33 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;6 mm drill
T34 P34 X0 Y0 Z0 A0 B0 C0 U0 V0 W0 D6.00000 I0 J0 Q0 ;6 mm 4 flute spiral upcut

View File

@@ -0,0 +1,202 @@
# This file was created with the 7i96 Wizard on Jun 10 2019 11:12:47
# Changes to most things are ok and will be read by the wizard
[EMC]
VERSION = 1.1
MACHINE = woodpecker
DEBUG = 0x00000000
[DISPLAY]
DISPLAY = qtvcp woodpecker
PREFERENCE_FILE_PATH = WORKINGFOLDER/woodpecker.pref
POSITION_OFFSET = RELATIVE
POSITION_FEEDBACK = ACTUAL
GRIDS = 10mm 20mm 50mm 100mm 1in 2in 5in 10in
MAX_FEED_OVERRIDE = 1.2
MIN_SPINDLE_0_OVERRIDE = 0.5
MAX_SPINDLE_0_OVERRIDE = 1.2
DEFAULT_SPINDLE_0_SPEED = 12000
SPINDLE_INCREMENT = 200
MIN_SPINDLE_0_SPEED = 1000
MAX_SPINDLE_0_SPEED = 20000
MIN_LINEAR_VELOCITY = 0
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.0
DEFAULT_LINEAR_JOG_VEL = 50.0
DEFAULT_ANGULAR_VELOCITY = 0
MIN_ANGULAR_VELOCITY = 0
MAX_ANGULAR_VELOCITY = 0
CYCLE_TIME = 100
INTRO_GRAPHIC = linuxcnc.gif
INTRO_TIME = 2
PROGRAM_PREFIX = ~/linuxcnc/nc_files
INCREMENTS = 10 mm, 1.0 mm, 0.10 mm, 0.01 mm, 1.0 inch, 0.1 inch, 0.01 inch
MDI_HISTORY_FILE = mdi_history.dat
LOG_FILE = woodpecker.log
TOOL_EDITOR = tooledit
CONFIRM_EXIT = True
[FILTER]
PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
PROGRAM_EXTENSION = .py Python Script
PROGRAM_EXTENSION = .nc,.tap G-Code File
png = image-to-gcode
gif = image-to-gcode
jpg = image-to-gcode
py = python3
[KINS]
KINEMATICS = trivkins coordinates=XYZ
JOINTS = 3
[EMCIO]
TOOL_TABLE = tool.tbl
[RS274NGC]
PARAMETER_FILE = woodpecker.var
RS274NGC_STARTUP_CODE = G17 G21 G40 G43H0 G54 G64P0.005 G80 G90 G94 G97 M5 M9
SUBROUTINE_PATH = ../../../../nc_files/probe/basic_probe/macros
FEATURES=12
[EMCMOT]
EMCMOT = motmod
SERVO_PERIOD = 1000000
COMM_TIMEOUT = 1.0
COMM_WAIT = 0.010
BASE_PERIOD = 100000
[TASK]
TASK = milltask
CYCLE_TIME = 0.010
[TRAJ]
COORDINATES = XYZ
LINEAR_UNITS = metric
ANGULAR_UNITS = degree
MAX_LINEAR_VELOCITY = 60.00
DEFAULT_LINEAR_VELOCITY = 50.00
SPINDLES = 1
[HAL]
HALUI = halui
HALFILE = core_sim.hal
HALFILE = simulated_home.hal
#HALFILE = custom.hal
POSTGUI_HALFILE = woodpecker_postgui.hal
[HALUI]
# no content
[TOOLSENSOR]
X = 5.00
Y = 71.50
TOUCH_HEIGHT = 29.3
SENSOR_HEIGHT = 59.8
MAXPROBE = -40
SEARCH_VEL = 200
PROBE_VEL = 50
[LASER]
X = 106.9
Y = -16.85
[AXIS_X]
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Y]
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
[AXIS_Z]
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
[JOINT_0]
AXIS = X
MIN_LIMIT = -0.001
MAX_LIMIT = 520.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.00000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.000
HOME_SEQUENCE = 1
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_1]
AXIS = Y
MIN_LIMIT = -0.001
MAX_LIMIT = 630.0
MAX_VELOCITY = 60.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 72.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = 20.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.00
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 2
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[JOINT_2]
AXIS = Z
MIN_LIMIT = -115.0
MAX_LIMIT = 10.0
MAX_VELOCITY = 40.0
MAX_ACCELERATION = 500.0
TYPE = LINEAR
SCALE = 160.0
STEPGEN_MAX_VEL = 48.0
STEPGEN_MAX_ACC = 600.0
FERROR = 1.0
MIN_FERROR = 0.5
MAX_OUTPUT = 0
MAX_ERROR = 0.0127
HOME = -10.0
HOME_OFFSET = 0.000000
HOME_SEARCH_VEL = 20.000000
HOME_LATCH_VEL = 10.00
HOME_SEQUENCE = 0
HOME_USE_INDEX = False
HOME_IGNORE_LIMITS = False
[SPINDLE]
SPINDLE_TYPE = openLoop
SCALE =
PWM_FREQUENCY = 2000
MAX_RPM = 18000
MIN_RPM = 8000
DEADBAND = 0
P = 0
I = 0
D = 0
FF0 = 1
FF1 = 0
FF2 = 0
BIAS = 0
MAX_ERROR = 0