Compare commits
349 Commits
40a63c76f7
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c81f9d0111 | ||
|
|
c75eec1057 | ||
|
|
23e67bb6cd | ||
|
|
42e5b0784d | ||
|
|
64f336d6f2 | ||
|
|
fc56b11d8f | ||
|
|
fb9561ccc7 | ||
|
|
4e246738ac | ||
|
|
92562db29f | ||
|
|
de5f28f7ee | ||
|
|
82f222ba44 | ||
|
|
cdc30dda7e | ||
|
|
1d96aa8a55 | ||
|
|
25cb6885bf | ||
|
|
ccd51ff373 | ||
|
|
10bf0a5897 | ||
|
|
ced3e5de0e | ||
|
|
7ba3a22441 | ||
|
|
5aa328b413 | ||
|
|
586c28656d | ||
|
|
6efb77b8e4 | ||
|
|
ebb29f8cb6 | ||
|
|
8544872198 | ||
|
|
e320d6d420 | ||
|
|
ba2d680500 | ||
|
|
9af3443d95 | ||
|
|
4adcd82b74 | ||
|
|
66ea34a76d | ||
|
|
5bc568eaa9 | ||
|
|
23a4679c28 | ||
|
|
3c05202097 | ||
|
|
ba0d973f4f | ||
|
|
f69e10bedf | ||
|
|
a8f6a9d907 | ||
|
|
0850954ca8 | ||
|
|
6bd1c6a429 | ||
|
|
e928b32e69 | ||
|
|
36763c6bcd | ||
|
|
03080afe24 | ||
|
|
120a294f62 | ||
|
|
a3daa829fc | ||
|
|
71c61fca84 | ||
|
|
ff2980569c | ||
|
|
695186ddfc | ||
|
|
8394042d18 | ||
|
|
7e18c6cd40 | ||
|
|
09e2259669 | ||
|
|
867bf09c5d | ||
|
|
d35766e387 | ||
|
|
9c73577ade | ||
|
|
55149b0a0a | ||
|
|
6a886be52d | ||
|
|
acbf5b4686 | ||
|
|
77c6674905 | ||
|
|
eb91ced792 | ||
|
|
1b60bc2b2e | ||
|
|
37879f2a67 | ||
|
|
a7cd889b3a | ||
|
|
4887b2f64e | ||
|
|
cb315ce1cd | ||
|
|
9a4e0e3712 | ||
|
|
98755528e4 | ||
|
|
504b9b6d23 | ||
|
|
284afa1c64 | ||
|
|
428fc46f4e | ||
|
|
d5c6b7555a | ||
|
|
b773946c45 | ||
|
|
7a2a80ea71 | ||
|
|
41db47f440 | ||
|
|
27ac0bfb25 | ||
|
|
cd71eff8a5 | ||
|
|
eb1d31bfee | ||
|
|
2892f2ca9d | ||
|
|
a301965452 | ||
|
|
0737d5ea65 | ||
|
|
3a478ca335 | ||
|
|
a144576e90 | ||
|
|
60745adeef | ||
|
|
6506d23dc2 | ||
|
|
440a61be32 | ||
|
|
9b9e942dd6 | ||
|
|
3c72356c92 | ||
|
|
a89c107676 | ||
|
|
035b25862a | ||
|
|
167703b87a | ||
|
|
b600d6a516 | ||
|
|
0a2d37fae8 | ||
|
|
111cb5f9b9 | ||
|
|
218ac523b8 | ||
|
|
abaebe7940 | ||
|
|
77e92b0116 | ||
|
|
cf3154b043 | ||
|
|
9da6ffcd6a | ||
|
|
c71d2964ee | ||
|
|
c1a130f5fb | ||
|
|
baf8429736 | ||
|
|
2e2fb34cc3 | ||
|
|
810bd92ddc | ||
|
|
6d99ca67a9 | ||
|
|
6a2f63c894 | ||
|
|
bc80d74d1f | ||
|
|
71676ac1be | ||
|
|
89af73298e | ||
|
|
dc5cdeacc2 | ||
|
|
b170ccd95a | ||
|
|
29197b25cc | ||
|
|
5ce3c18103 | ||
|
|
79077fa695 | ||
|
|
f64db24060 | ||
|
|
fb2b5c4920 | ||
|
|
9c52e426f7 | ||
|
|
d80405ccb3 | ||
|
|
a48c02f5cc | ||
|
|
f56468b664 | ||
|
|
ba2d576f8b | ||
|
|
7f45abe93c | ||
|
|
ae7de73a7c | ||
|
|
7471444781 | ||
|
|
f36e2a96c4 | ||
|
|
aaa6dce99a | ||
|
|
b89d6311ff | ||
|
|
a12c0166b5 | ||
|
|
9fd23192dd | ||
|
|
a46910b6c0 | ||
|
|
0b387db8ca | ||
|
|
22c1c311ff | ||
|
|
3079656cfb | ||
|
|
7502684780 | ||
|
|
340966b6f7 | ||
|
|
1f314b7e9e | ||
|
|
1bfb7426d4 | ||
|
|
abd96dfdde | ||
|
|
7b171c605b | ||
|
|
cb22ecd8ef | ||
|
|
a0f6228908 | ||
|
|
8fe468ba3c | ||
|
|
b3b1117ec9 | ||
|
|
4eb694164f | ||
|
|
59b8e2a832 | ||
|
|
f9ac38251b | ||
|
|
002c8a2d53 | ||
|
|
decc008609 | ||
|
|
3c2df90872 | ||
|
|
81c7b061a8 | ||
|
|
2223e6d601 | ||
|
|
708b2bee17 | ||
|
|
0a270c73a0 | ||
|
|
52d7a49861 | ||
|
|
802e85cd63 | ||
|
|
0de612651e | ||
|
|
6f21d22912 | ||
|
|
f8902b3f8d | ||
|
|
3d368b2564 | ||
|
|
8b89b5b4c6 | ||
|
|
21c242c9a4 | ||
|
|
945e839e9d | ||
|
|
feb04102e7 | ||
|
|
aaa2573bba | ||
|
|
d7b9006ba5 | ||
|
|
51b415a701 | ||
|
|
856b526acb | ||
|
|
bc54b5f8f8 | ||
|
|
8151829643 | ||
|
|
5fb041f1a5 | ||
|
|
bba306ccfe | ||
|
|
4a3d87045e | ||
|
|
951dcc7980 | ||
|
|
aa6e79ac64 | ||
|
|
39f6f9133c | ||
|
|
bc7b947d14 | ||
|
|
1ce460d1d5 | ||
|
|
96b5973e1b | ||
|
|
c8b834e36b | ||
|
|
32b4a96a9f | ||
|
|
ee0a3130bf | ||
|
|
c031bc0a2c | ||
|
|
dcf246c0a0 | ||
|
|
1f4044efe2 | ||
|
|
3cc7590121 | ||
|
|
180c0f6dbe | ||
|
|
702f94cc52 | ||
|
|
b366d220f5 | ||
|
|
3090b9a79a | ||
|
|
c851476007 | ||
|
|
ddc20eeb98 | ||
|
|
1ef3f2c7df | ||
|
|
eef30e1831 | ||
|
|
1433435121 | ||
|
|
46807f05a5 | ||
|
|
77f9754833 | ||
|
|
457557dee8 | ||
|
|
aff6f85d8a | ||
|
|
4086445900 | ||
|
|
18f14ca111 | ||
|
|
7d28d0a025 | ||
|
|
0d4e248811 | ||
|
|
5481ab3bff | ||
|
|
8ff22065dd | ||
|
|
5c2d5cfa05 | ||
|
|
f98a715ed7 | ||
|
|
1928ff3b6a | ||
|
|
6cf7c73392 | ||
|
|
028825cd9c | ||
|
|
e778a37fdb | ||
|
|
6cc07c2950 | ||
|
|
c5a1d655b0 | ||
|
|
0895c04ab1 | ||
|
|
c932e10801 | ||
|
|
d1e0152eb8 | ||
|
|
a134dcef7d | ||
|
|
bbd5739e7a | ||
|
|
611e6417b4 | ||
|
|
fa4296d730 | ||
|
|
2dd9847a7b | ||
|
|
9bf9206869 | ||
|
|
090a5fb89c | ||
|
|
2f7a46758b | ||
|
|
1b16d3e0b5 | ||
|
|
d0a7a9fcec | ||
|
|
dbf27a4e6b | ||
|
|
e71b9146e1 | ||
|
|
59287b9920 | ||
|
|
33e1ee5a06 | ||
|
|
b26620dc32 | ||
|
|
74cb5f826c | ||
|
|
2ba8cd7fb8 | ||
|
|
e3d47e8267 | ||
|
|
3df61e8da5 | ||
|
|
28aa1956b7 | ||
|
|
4e3df07b8a | ||
|
|
b7610d1b96 | ||
|
|
55c75ffe80 | ||
|
|
ad3720713e | ||
|
|
ba526a6042 | ||
|
|
93f2a903b5 | ||
|
|
c52ecc09eb | ||
|
|
cc05532528 | ||
|
|
ecec27aa64 | ||
|
|
c25b0eff22 | ||
|
|
777d29651c | ||
|
|
138fe862ae | ||
|
|
d985b13a8e | ||
|
|
030074b8c5 | ||
|
|
84fdc8a1c5 | ||
|
|
9c03f91fa8 | ||
|
|
868f20382a | ||
|
|
cde0bdaba6 | ||
|
|
3a60624108 | ||
|
|
4d0cf788b1 | ||
|
|
e875496fe0 | ||
|
|
7e15a99d28 | ||
|
|
3435c3556a | ||
|
|
318220b766 | ||
|
|
43a3e66106 | ||
|
|
4f1042c548 | ||
|
|
cc708b1ccc | ||
|
|
25519b5bc4 | ||
|
|
a44199eb48 | ||
|
|
9a9b931982 | ||
|
|
7bd1dc640f | ||
|
|
b83bc47c45 | ||
|
|
6ffcada028 | ||
|
|
b2945cf57f | ||
|
|
05ece027c4 | ||
|
|
b4d0bfae46 | ||
|
|
3f5c3faf25 | ||
|
|
dd4c62fce6 | ||
|
|
4861287138 | ||
|
|
7319e18810 | ||
|
|
df5c459b1d | ||
|
|
23284e528f | ||
|
|
952d3ecfd2 | ||
|
|
6e0a5627f0 | ||
|
|
6266887fec | ||
|
|
b8ad3a0346 | ||
|
|
0abf801856 | ||
|
|
31e1e4499e | ||
|
|
4780dd8621 | ||
|
|
303b6bfa36 | ||
|
|
854cc682b3 | ||
|
|
dda5b4973e | ||
|
|
ce0605d20d | ||
|
|
67154a70fa | ||
|
|
5c7093ba39 | ||
|
|
0e1e22a864 | ||
|
|
cee1bf3a3f | ||
|
|
d807464cf7 | ||
|
|
303b7f7a72 | ||
|
|
154fc7578a | ||
|
|
08978b82de | ||
|
|
dfd41bb7fc | ||
|
|
1f37c979e9 | ||
|
|
23f88a619a | ||
|
|
34aa884a22 | ||
|
|
56f78b3054 | ||
|
|
c3ec85196f | ||
|
|
c2e5e8f2c8 | ||
|
|
10c1b70ed8 | ||
|
|
68b6c19392 | ||
|
|
e1fe284078 | ||
|
|
082495d3ad | ||
|
|
e117ac8a5b | ||
|
|
518628bfea | ||
|
|
89f9930ec4 | ||
|
|
7bf4300c84 | ||
|
|
16ac5cbfef | ||
|
|
820ac7e72b | ||
|
|
5f4e918663 | ||
|
|
de13d8efeb | ||
|
|
8826f2ee73 | ||
|
|
e1708c96ee | ||
|
|
cc7faef3a7 | ||
|
|
d8c2364816 | ||
|
|
93e83d52bf | ||
|
|
c4e174f011 | ||
|
|
00d62bd61a | ||
|
|
c9c5db8e9c | ||
|
|
26da1e6d9d | ||
|
|
d5c99f99c0 | ||
|
|
158fd343c6 | ||
|
|
35d341de70 | ||
|
|
d6cae8bf56 | ||
|
|
0a0083b2d3 | ||
|
|
ad7a461b3e | ||
|
|
dab7b9e2ef | ||
|
|
0db23b4a5d | ||
|
|
fbe1c31961 | ||
|
|
87fcf74135 | ||
|
|
f5013ec745 | ||
|
|
1250638f22 | ||
|
|
37c2f08dfb | ||
|
|
c474d45cdc | ||
|
|
04b3bc3a47 | ||
|
|
110c3ba76e | ||
|
|
57733f424a | ||
|
|
f98aa9ebb1 | ||
|
|
8387f48130 | ||
|
|
d8909b5d8a | ||
|
|
2c24909a47 | ||
|
|
d7cac10c3b | ||
|
|
bbaf9f4da6 | ||
|
|
89fd49c604 | ||
|
|
5ec10abf38 | ||
|
|
6f9431a389 | ||
|
|
4c55ab3435 | ||
|
|
1498d9830d | ||
|
|
c2d1aa6fe3 | ||
|
|
de273bf830 | ||
|
|
b40914747d |
@@ -116,19 +116,13 @@ The first useful target is:
|
||||
|
||||
公共 API 使用同一个入口解析程序,后端通过 JSON 配置选择:
|
||||
|
||||
```json
|
||||
{"backend":"smoke"}
|
||||
```
|
||||
|
||||
`smoke` 是默认后端,用于 wasm 和 UI 联调。
|
||||
|
||||
native 构建启用 LinuxCNC 后端后,可以使用:
|
||||
|
||||
```json
|
||||
{"backend":"linuxcnc-rs274"}
|
||||
```
|
||||
|
||||
网页面板右上角的 `BACKEND` 下拉框会把该配置传给 wasm/core。当前默认 wasm 构建不包含 LinuxCNC 后端,选择 `LINUXCNC` 会返回明确错误;native API 测试已验证该后端可用。
|
||||
`linuxcnc-rs274` 是默认后端,wasm 和 UI 默认通过 LinuxCNC RS274 源码路径解析;`smoke` 仅用于显式编译/选择的 legacy 联调路径。
|
||||
|
||||
网页面板右上角的 `BACKEND` 下拉框会把该配置传给 wasm/core。`./build-wasm.sh` 会生成 `web/public/cnc_sim.js` 和 `web/public/cnc_sim.wasm`,随后运行 `test-web-wasm-node-smoke.cjs` 和 `test-web-wasm-browser-smoke.sh`;这些 smoke 会验证 wasm 中的 LinuxCNC RS274 后端可在 Node 和 Chromium 浏览器中加载、可解析基础运动,并保留 `M428/M429/M430` remap 触发的运动学切换事件。
|
||||
|
||||
## RTCP 配置
|
||||
|
||||
@@ -143,11 +137,19 @@ RTCP 默认关闭。开启后,原有 `rapid`、`linear-feed`、`arc-feed` 事
|
||||
"toolLengths": {
|
||||
"7": 125
|
||||
}
|
||||
},
|
||||
"xyzbcTrt": {
|
||||
"xRotPoint": 0,
|
||||
"yRotPoint": 0,
|
||||
"zRotPoint": 0,
|
||||
"xOffset": -20,
|
||||
"zOffset": -15,
|
||||
"conventionalDirections": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当前 RTCP 内核是第一版头头/摆头类几何模型:编程 XYZ 视为刀尖点,刀长沿本地 `-Z`,A/B/C 按 `Rz(C) * Ry(B) * Rx(A)` 旋转。后续会继续加入机型拓扑、旋转中心偏置、刀表刀长和不同五轴构型。
|
||||
RTCP pivot 事件只在已知 LinuxCNC switchkins 类型下输出。`M428` 切换到 `XYZBC_TRT` 后,`xyzbcTrt` 对应 LinuxCNC `xyzbc-trt-kins` 的 HAL pin:`x-rot-point`、`y-rot-point`、`z-rot-point`、`x-offset`、`z-offset`、`conventional-directions`;刀长仍来自 `toolLength` / `toolLengths`。`M430` 使用 LinuxCNC `userkfuncs.c` 经 `kins_util.c` identity 运动学路径。未支持或未知的 switchkins 类型不会回退到自研 RTCP 几何。
|
||||
|
||||
RTCP G 码控制已开始标准化:
|
||||
|
||||
@@ -161,11 +163,11 @@ RTCP G 码控制已开始标准化:
|
||||
|
||||
core 已对原型中的运动学切换 M 码做标准化解析:
|
||||
|
||||
- `M429`:切换到三轴恒等运动学 `IDENTITY`,关闭 RTCP。
|
||||
- `M428`:恢复到原始五轴运动学,开启 RTCP。
|
||||
- `M430`:切换到 `FIVEAXIS_BC`,开启 RTCP。
|
||||
- `M429`:切换到三轴恒等运动学 `IDENTITY`。
|
||||
- `M428`:切换到 LinuxCNC `xyzbc-trt-kins` 的 XYZBC TRT 运动学。
|
||||
- `M430`:切换到 LinuxCNC 默认 `userk` 运动学;当前对齐 `userkfuncs.c` 的 identity 正/逆解。
|
||||
|
||||
解析后会发出 `kinematics-switch` 事件。事件中的 `reserved` 字段表示运动学类型:`0=IDENTITY`、`1=ORIGINAL`、`2=FIVEAXIS_BC`;`feed` 字段临时表示 RTCP 状态:`0=关闭`、`1=开启`。同一行中的 `M428 M429 M430` 会按出现顺序产生三个切换事件。
|
||||
解析后会发出 `kinematics-switch` 事件。事件中的 `reserved` 字段表示运动学类型:`0=IDENTITY`、`1=XYZBC_TRT`、`2=USERK_IDENTITY`。这些 M 码对齐 LinuxCNC `remap_subs/428remap.ngc`、`429remap.ngc`、`430remap.ngc`,只设置 `motion.switchkins-type`,不隐式开启或关闭 RTCP;RTCP 状态仍由 `G43.4`、`G43.5`、`G49` 控制。同一行中的 `M428 M429 M430` 会按出现顺序产生三个切换事件。
|
||||
|
||||
`linuxcnc-rs274` native API backend 会在送入 LinuxCNC 解释器前拦截只包含这些切换 M 码的行,避免 LinuxCNC 去查找外部用户 M-code 文件。
|
||||
|
||||
|
||||
@@ -3,20 +3,21 @@ set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this blocker scan is constrained to the RS274/WASM
|
||||
# manifest. Python and Boost.Python blockers come from
|
||||
# src/emc/rs274ngc/gcodemodule.cc, interp_namedparams.cc, interp_o_word.cc,
|
||||
# and the py*.cc module bindings; tooldata/native-backend blockers come from
|
||||
# src/emc/tooldata/tooldata_mmap.cc and tooldata_db.cc; native filesystem
|
||||
# coverage comes from LinuxCNC RS274 sources such as interp_o_word.cc
|
||||
# directory traversal and rs274ngc_pre.cc parameter-file replacement.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
if [[ ! -f "$manifest" ]]; then
|
||||
echo "missing manifest: $manifest" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$linuxcnc_root" ]]; then
|
||||
echo "missing LinuxCNC root: $linuxcnc_root" >&2
|
||||
exit 1
|
||||
fi
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest"
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
python_blockers=()
|
||||
python_compile_covered=()
|
||||
core_python_sources=()
|
||||
dlopen_blockers=()
|
||||
core_dlopen_sources=()
|
||||
@@ -30,30 +31,83 @@ core_native_fs_sources=()
|
||||
core_count=0
|
||||
blocked_count=0
|
||||
blocked_replacements=()
|
||||
core_source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_core_sources.XXXXXX.txt")
|
||||
blocked_source_list=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_blocker_blocked_sources.XXXXXX.txt")
|
||||
trap 'rm -f "$core_source_list" "$blocked_source_list"' EXIT
|
||||
shim_source_output=$(./list-linuxcnc-wasm-safe-shims.sh)
|
||||
mapfile -t wasm_safe_shims <<<"$shim_source_output"
|
||||
|
||||
blocked_replacement_for() {
|
||||
case "$1" in
|
||||
src/emc/tooldata/tooldata_mmap.cc)
|
||||
./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc
|
||||
;;
|
||||
src/emc/rs274ngc/canonmodule.cc|src/emc/rs274ngc/gcodemodule.cc|src/emc/rs274ngc/interpmodule.cc)
|
||||
./list-linuxcnc-wasm-safe-shims.sh linuxcnc_runtime_shim.cc
|
||||
;;
|
||||
src/emc/rs274ngc/pyarrays.cc|src/emc/rs274ngc/pyblock.cc|src/emc/rs274ngc/pyemctypes.cc|src/emc/rs274ngc/pyinterp1.cc|src/emc/rs274ngc/pyparamclass.cc)
|
||||
./list-linuxcnc-wasm-safe-shims.sh python_c_api_shim.cc
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$core_source_list"
|
||||
./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$blocked_source_list"
|
||||
core_count=$(wc -l < "$core_source_list")
|
||||
blocked_count=$(wc -l < "$blocked_source_list")
|
||||
wasm_safe_shim_in_build() {
|
||||
local shim=$1
|
||||
local candidate
|
||||
for candidate in "${wasm_safe_shims[@]}"; do
|
||||
if [[ "$candidate" == "$shim" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
python_compile_probe_covers() {
|
||||
grep -F "$1" test-linuxcnc-wasm-python-c-api-symbols.sh >/dev/null
|
||||
}
|
||||
|
||||
core_sources=()
|
||||
blocked_sources=()
|
||||
manifest_line_number=0
|
||||
while IFS= read -r manifest_line || [[ -n "$manifest_line" ]]; do
|
||||
manifest_line_number=$((manifest_line_number + 1))
|
||||
case "$manifest_line" in
|
||||
""|\#*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
IFS=: read -r group path note extra <<<"$manifest_line"
|
||||
if [[ -z "$group" || -z "$path" || -z "$note" || -n "${extra:-}" ]]; then
|
||||
echo "bad manifest line $manifest_line_number: $manifest_line" >&2
|
||||
exit 1
|
||||
fi
|
||||
case "$group" in
|
||||
core)
|
||||
core_sources+=("$path")
|
||||
;;
|
||||
blocked)
|
||||
blocked_sources+=("$path")
|
||||
;;
|
||||
header|metadata|blocked-header)
|
||||
;;
|
||||
*)
|
||||
echo "unknown manifest group: $group" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done < "$manifest"
|
||||
core_count=${#core_sources[@]}
|
||||
blocked_count=${#blocked_sources[@]}
|
||||
|
||||
scan_source() {
|
||||
local group=$1
|
||||
local path=$2
|
||||
full_path="$linuxcnc_root/$path"
|
||||
if [[ ! -f "$full_path" ]]; then
|
||||
echo "missing manifest source: $path" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$group" == "blocked" ]]; then
|
||||
if ! replacement=$(blocked_replacement_for "$path"); then
|
||||
echo "missing blocked replacement mapping: $path" >&2
|
||||
@@ -63,6 +117,10 @@ scan_source() {
|
||||
echo "missing blocked replacement source: $replacement" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! wasm_safe_shim_in_build "$replacement"; then
|
||||
echo "blocked replacement is not in wasm shim build set: $path -> $replacement" >&2
|
||||
exit 1
|
||||
fi
|
||||
blocked_replacements+=("$path -> $replacement")
|
||||
fi
|
||||
|
||||
@@ -81,6 +139,9 @@ scan_source() {
|
||||
if grep -Eq 'Python\.h|boost/python|pythonplugin|PyObject|PyInit_' "$full_path"; then
|
||||
if [[ "$group" == "blocked" ]]; then
|
||||
python_blockers+=("$path")
|
||||
if python_compile_probe_covers "$path"; then
|
||||
python_compile_covered+=("$path")
|
||||
fi
|
||||
else
|
||||
core_python_sources+=("$path")
|
||||
fi
|
||||
@@ -111,15 +172,15 @@ scan_source() {
|
||||
fi
|
||||
}
|
||||
|
||||
while IFS= read -r path; do
|
||||
for path in "${core_sources[@]}"; do
|
||||
[[ -z "$path" ]] && continue
|
||||
scan_source core "$path"
|
||||
done < "$core_source_list"
|
||||
done
|
||||
|
||||
while IFS= read -r path; do
|
||||
for path in "${blocked_sources[@]}"; do
|
||||
[[ -z "$path" ]] && continue
|
||||
scan_source blocked "$path"
|
||||
done < "$blocked_source_list"
|
||||
done
|
||||
|
||||
print_group() {
|
||||
local title=$1
|
||||
@@ -139,6 +200,7 @@ echo "blocked=$blocked_count"
|
||||
echo
|
||||
|
||||
print_group "python" "${python_blockers[@]}"
|
||||
print_group "python-compile-covered" "${python_compile_covered[@]}"
|
||||
print_group "dlopen" "${dlopen_blockers[@]}"
|
||||
print_group "tooldata" "${tooldata_blockers[@]}"
|
||||
print_group "tooldata-users" "${shimmed_tooldata_users[@]}"
|
||||
|
||||
105
build-linuxcnc-native-bridge-objects.sh
Executable file
105
build-linuxcnc-native-bridge-objects.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: native bridge object caches compile only project
|
||||
# canon/kinematics bridge sources that wrap LinuxCNC src/emc/nml_intf/canon.hh
|
||||
# and src/emc/kinematics implementations; G-code behavior remains in
|
||||
# LinuxCNC RS274 objects linked by the caller.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
cxx=${CXX:-g++}
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
cxx="ccache $cxx"
|
||||
fi
|
||||
build_jobs=${CNC_SIM_BUILD_JOBS:-8}
|
||||
if ! [[ "$build_jobs" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CNC_SIM_BUILD_JOBS must be a positive integer: $build_jobs" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=${CNC_SIM_NATIVE_BRIDGE_OBJECT_CACHE_DIR-build/native-bridge-object-cache}
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
echo "CNC_SIM_NATIVE_BRIDGE_OBJECT_CACHE_DIR must not be empty" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_NATIVE_BRIDGE_OBJECT_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_NATIVE_BRIDGE_OBJECT_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
exec 8>"$cache_dir/native-bridge-objects.lock"
|
||||
flock 8
|
||||
|
||||
preflight_cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-"$cache_dir/preflight-cache"}
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" --root-only
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
source_output=$(./list-linuxcnc-bridge-smoke-project-sources.sh)
|
||||
mapfile -t sources <<<"$source_output"
|
||||
common_flag_output=$(
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" \
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-common-cxxflags.sh \
|
||||
--no-ulapi \
|
||||
--core-include \
|
||||
--core-src
|
||||
)
|
||||
mapfile -t common_flags <<<"$common_flag_output"
|
||||
|
||||
objects=()
|
||||
source_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
objects+=("$cache_dir/source_${source_index}.o")
|
||||
source_index=$((source_index + 1))
|
||||
done
|
||||
|
||||
signature="$cache_dir/native-bridge-objects.signature"
|
||||
next_signature="$cache_dir/native-bridge-objects.signature.next"
|
||||
{
|
||||
printf 'CXX=%s\n' "$cxx"
|
||||
printf 'PWD=%s\n' "$PWD"
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'BUILD_RULE_VERSION=1\n'
|
||||
printf 'COMMON_FLAGS='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n'
|
||||
printf 'SOURCES:\n'
|
||||
printf '%s\n' "${sources[@]}"
|
||||
} > "$next_signature"
|
||||
if [[ ! -f "$signature" ]] || ! cmp -s "$signature" "$next_signature"; then
|
||||
rm -f "$cache_dir"/source_*.o "$cache_dir"/source_*.d
|
||||
fi
|
||||
mv "$next_signature" "$signature"
|
||||
|
||||
makefile="$cache_dir/native-bridge-objects.mk"
|
||||
{
|
||||
printf 'CXX := %s\n' "$cxx"
|
||||
printf 'COMMON_FLAGS :='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n\n'
|
||||
printf 'OBJECTS :='
|
||||
printf ' %s' "${objects[@]}"
|
||||
printf '\n\n'
|
||||
printf 'DEP_FILES :=\n'
|
||||
for object in "${objects[@]}"; do
|
||||
printf 'DEP_FILES += %s.d\n' "$object"
|
||||
done
|
||||
printf '\n.PHONY: all\n'
|
||||
printf 'all: $(OBJECTS)\n\n'
|
||||
|
||||
source_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
printf '%s: %s\n' "${objects[$source_index]}" "$source"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS) -MMD -MP -MF %s.d -c %s -o %s\n\n' \
|
||||
"${objects[$source_index]}" "$source" "${objects[$source_index]}"
|
||||
source_index=$((source_index + 1))
|
||||
done
|
||||
printf '\n-include $(DEP_FILES)\n'
|
||||
} > "$makefile"
|
||||
make --output-sync=target -j"$build_jobs" -f "$makefile" >/dev/null
|
||||
|
||||
printf '%s\n' "${objects[@]}"
|
||||
152
build-linuxcnc-wasm-link-probe.sh
Executable file
152
build-linuxcnc-wasm-link-probe.sh
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: link probe modes reuse wasm-safe objects built from
|
||||
# linuxcnc-rs274-wasm-source-files.txt and add only a narrow probe main that
|
||||
# asserts LinuxCNC rs274ngc_pre/runtime symbols stay linked.
|
||||
usage() {
|
||||
echo "usage: $0 --mode rs274ngc-pre|runtime [manifest]" >&2
|
||||
}
|
||||
|
||||
mode=
|
||||
manifest=linuxcnc-rs274-wasm-source-files.txt
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--mode)
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
echo "missing --mode value" >&2
|
||||
exit 1
|
||||
fi
|
||||
mode=$2
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--*)
|
||||
usage
|
||||
echo "unknown wasm link probe option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
manifest=$1
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
case "$mode" in
|
||||
rs274ngc-pre|runtime)
|
||||
;;
|
||||
"")
|
||||
usage
|
||||
echo "missing --mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
echo "unknown wasm link probe mode: $mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
cxx=${CXX:-g++}
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
cxx="ccache $cxx"
|
||||
fi
|
||||
build_jobs=${CNC_SIM_BUILD_JOBS:-8}
|
||||
if ! [[ "$build_jobs" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CNC_SIM_BUILD_JOBS must be a positive integer: $build_jobs" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=${CNC_SIM_WASM_LINK_PROBE_CACHE_DIR-build/wasm-link-probe-cache}
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
echo "CNC_SIM_WASM_LINK_PROBE_CACHE_DIR must not be empty" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_WASM_LINK_PROBE_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_WASM_LINK_PROBE_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preflight_cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-"$cache_dir/preflight-cache"}
|
||||
object_mode=$mode
|
||||
main_source=core/wasm_shims/rs274ngc_pre_probe_main.cc
|
||||
target_name=rs274ngc_pre_probe
|
||||
common_flag_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-common-cxxflags.sh --profile core20-sections)
|
||||
mapfile -t common_flags <<<"$common_flag_output"
|
||||
case "$mode" in
|
||||
rs274ngc-pre)
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc provides' "$main_source" >/dev/null
|
||||
;;
|
||||
runtime)
|
||||
object_mode=runtime
|
||||
main_source=core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc
|
||||
target_name=cnc_sim_wasm_runtime_probe
|
||||
common_flags+=(-DCNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/rs274ngc_pre.cc provides read(),' "$main_source" >/dev/null
|
||||
;;
|
||||
esac
|
||||
|
||||
object_output=$(CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" LINUXCNC_ROOT="$linuxcnc_root" ./build-linuxcnc-wasm-probe-objects.sh --mode "$object_mode" "$manifest")
|
||||
mapfile -t objects <<<"$object_output"
|
||||
manifest=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
mode_dir="$cache_dir/$mode"
|
||||
mkdir -p "$mode_dir"
|
||||
exec 8>"$mode_dir/link.lock"
|
||||
flock 8
|
||||
|
||||
main_object="$mode_dir/main.o"
|
||||
target="$mode_dir/$target_name"
|
||||
signature="$mode_dir/link.signature"
|
||||
next_signature="$mode_dir/link.signature.next"
|
||||
{
|
||||
printf 'CXX=%s\n' "$cxx"
|
||||
printf 'PWD=%s\n' "$PWD"
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'MANIFEST=%s\n' "$manifest"
|
||||
printf 'MODE=%s\n' "$mode"
|
||||
printf 'BUILD_RULE_VERSION=1\n'
|
||||
printf 'COMMON_FLAGS='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n'
|
||||
printf 'MAIN_SOURCE=%s\n' "$main_source"
|
||||
printf 'OBJECTS:\n'
|
||||
printf '%s\n' "${objects[@]}"
|
||||
} > "$next_signature"
|
||||
if [[ ! -f "$signature" ]] || ! cmp -s "$signature" "$next_signature"; then
|
||||
rm -f "$main_object" "$main_object.d" "$target" "$mode_dir/runtime.symbols"
|
||||
fi
|
||||
mv "$next_signature" "$signature"
|
||||
|
||||
makefile="$mode_dir/link.mk"
|
||||
{
|
||||
printf 'CXX := %s\n' "$cxx"
|
||||
printf 'COMMON_FLAGS :='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n\n'
|
||||
printf 'OBJECTS :='
|
||||
printf ' %s' "${objects[@]}"
|
||||
printf '\n\n'
|
||||
printf '.PHONY: all\n'
|
||||
printf 'all: %s\n\n' "$target"
|
||||
printf '%s: %s\n' "$main_object" "$main_source"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS) -MMD -MP -MF %s.d -c %s -o %s\n\n' "$main_object" "$main_source" "$main_object"
|
||||
printf '%s: $(OBJECTS) %s\n' "$target" "$main_object"
|
||||
printf '\t@$(CXX) $(OBJECTS) %s -Wl,--gc-sections -lfmt -o %s\n\n' "$main_object" "$target"
|
||||
printf '\n-include %s.d\n' "$main_object"
|
||||
} > "$makefile"
|
||||
make --output-sync=target -j"$build_jobs" -f "$makefile" >/dev/null
|
||||
|
||||
printf '%s\n' "$target"
|
||||
197
build-linuxcnc-wasm-probe-objects.sh
Executable file
197
build-linuxcnc-wasm-probe-objects.sh
Executable file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: object probes compile the core entries selected from
|
||||
# linuxcnc-rs274-wasm-source-files.txt, including src/emc/rs274ngc,
|
||||
# src/emc/tooldata/tooldata_common.cc, src/emc/ini/inifile.cc, and
|
||||
# src/emc/nml_intf/emcops.cc, together with CMake-listed wasm-safe project
|
||||
# bridge sources and shims that replace the manifest's blocked Python, dlopen,
|
||||
# tooldata mmap, HAL, and runtime edges.
|
||||
usage() {
|
||||
echo "usage: $0 --mode source-objects|rs274ngc-pre|runtime [manifest]" >&2
|
||||
}
|
||||
|
||||
mode=
|
||||
manifest=linuxcnc-rs274-wasm-source-files.txt
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--mode)
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
echo "missing --mode value" >&2
|
||||
exit 1
|
||||
fi
|
||||
mode=$2
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--*)
|
||||
usage
|
||||
echo "unknown wasm probe object cache option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
manifest=$1
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
case "$mode" in
|
||||
source-objects|rs274ngc-pre|runtime)
|
||||
;;
|
||||
"")
|
||||
usage
|
||||
echo "missing --mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
echo "unknown wasm probe object cache mode: $mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
cxx=${CXX:-g++}
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
cxx="ccache $cxx"
|
||||
fi
|
||||
build_jobs=${CNC_SIM_BUILD_JOBS:-8}
|
||||
if ! [[ "$build_jobs" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CNC_SIM_BUILD_JOBS must be a positive integer: $build_jobs" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=${CNC_SIM_WASM_PROBE_OBJECT_CACHE_DIR-build/wasm-probe-object-cache}
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
echo "CNC_SIM_WASM_PROBE_OBJECT_CACHE_DIR must not be empty" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_WASM_PROBE_OBJECT_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_WASM_PROBE_OBJECT_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preflight_cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-"$cache_dir/preflight-cache"}
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" "$manifest" --require-rs274-complete
|
||||
manifest=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
common_flag_profile=core20-sections
|
||||
case "$mode" in
|
||||
source-objects)
|
||||
common_flag_profile=core20
|
||||
;;
|
||||
esac
|
||||
common_flag_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-common-cxxflags.sh --profile "$common_flag_profile")
|
||||
mapfile -t common_flags <<<"$common_flag_output"
|
||||
case "$mode" in
|
||||
runtime)
|
||||
common_flags+=(-DCNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
;;
|
||||
esac
|
||||
|
||||
grep -F 'LinuxCNC source basis: wasm-safe project probe sources are the thin bridge' list-linuxcnc-wasm-safe-project-sources.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: wasm-safe shim probe sources are limited to the' list-linuxcnc-wasm-safe-shims.sh >/dev/null
|
||||
|
||||
sources=()
|
||||
shim_output=$(./list-linuxcnc-wasm-safe-shims.sh)
|
||||
mapfile -t shim_sources <<<"$shim_output"
|
||||
sources+=("${shim_sources[@]}")
|
||||
case "$mode" in
|
||||
source-objects)
|
||||
;;
|
||||
rs274ngc-pre|runtime)
|
||||
project_source_output=$(./list-linuxcnc-wasm-safe-project-sources.sh)
|
||||
if [[ -n "$project_source_output" ]]; then
|
||||
mapfile -t project_sources <<<"$project_source_output"
|
||||
sources+=("${project_sources[@]}")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
source_output=$(CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core full)
|
||||
mapfile -t linuxcnc_sources <<<"$source_output"
|
||||
sources+=("${linuxcnc_sources[@]}")
|
||||
for source in "${sources[@]}"; do
|
||||
if [[ -z "$source" ]]; then
|
||||
echo "wasm probe object source list contains an empty path" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
mode_dir="$cache_dir/$mode"
|
||||
mkdir -p "$mode_dir"
|
||||
exec 8>"$mode_dir/objects.lock"
|
||||
flock 8
|
||||
|
||||
objects=()
|
||||
object_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
objects+=("$mode_dir/source_${object_index}.o")
|
||||
object_index=$((object_index + 1))
|
||||
done
|
||||
|
||||
signature="$mode_dir/objects.signature"
|
||||
next_signature="$mode_dir/objects.signature.next"
|
||||
{
|
||||
printf 'CXX=%s\n' "$cxx"
|
||||
printf 'PWD=%s\n' "$PWD"
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'MANIFEST=%s\n' "$manifest"
|
||||
printf 'MODE=%s\n' "$mode"
|
||||
printf 'BUILD_RULE_VERSION=1\n'
|
||||
printf 'COMMON_FLAGS='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n'
|
||||
printf 'SOURCES:\n'
|
||||
printf '%s\n' "${sources[@]}"
|
||||
} > "$next_signature"
|
||||
if [[ ! -f "$signature" ]] || ! cmp -s "$signature" "$next_signature"; then
|
||||
rm -f "$mode_dir"/source_*.o "$mode_dir"/source_*.d
|
||||
fi
|
||||
mv "$next_signature" "$signature"
|
||||
|
||||
makefile="$mode_dir/objects.mk"
|
||||
{
|
||||
printf 'CXX := %s\n' "$cxx"
|
||||
printf 'COMMON_FLAGS :='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n\n'
|
||||
printf 'OBJECTS :='
|
||||
printf ' %s' "${objects[@]}"
|
||||
printf '\n\n'
|
||||
printf 'DEP_FILES :=\n'
|
||||
for object in "${objects[@]}"; do
|
||||
printf 'DEP_FILES += %s.d\n' "$object"
|
||||
done
|
||||
printf '\n.PHONY: all\n'
|
||||
printf 'all: $(OBJECTS)\n\n'
|
||||
|
||||
object_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
source_flags=()
|
||||
case "$source" in
|
||||
core/src/linuxcnc_corexykins_adapter.c|core/src/linuxcnc_genserfuncs_adapter.c|core/src/linuxcnc_xyzab_tdr_kins_adapter.c)
|
||||
source_flags+=(-fpermissive)
|
||||
;;
|
||||
esac
|
||||
printf '%s: %s\n' "${objects[$object_index]}" "$source"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS)'
|
||||
printf ' %s' "${source_flags[@]}"
|
||||
printf ' -MMD -MP -MF %s.d -c %s -o %s\n\n' "${objects[$object_index]}" "$source" "${objects[$object_index]}"
|
||||
object_index=$((object_index + 1))
|
||||
done
|
||||
printf '\n-include $(DEP_FILES)\n'
|
||||
} > "$makefile"
|
||||
make --output-sync=target -j"$build_jobs" -f "$makefile" >/dev/null
|
||||
|
||||
printf '%s\n' "${objects[@]}"
|
||||
211
build-linuxcnc-wasm-standalone-probe.sh
Executable file
211
build-linuxcnc-wasm-standalone-probe.sh
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: standalone probe modes either compile LinuxCNC
|
||||
# rs274/tooldata sources directly or link wasm-safe shims whose source basis is
|
||||
# checked against LinuxCNC source comments before building.
|
||||
usage() {
|
||||
echo "usage: $0 --mode tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|python-plugin-inittab-link|rs274ngc-pre-object" >&2
|
||||
}
|
||||
|
||||
mode=
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--mode)
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
echo "missing --mode value" >&2
|
||||
exit 1
|
||||
fi
|
||||
mode=$2
|
||||
shift 2
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
echo "unknown wasm standalone probe option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
case "$mode" in
|
||||
tooldata-link|tooldata-common-link|interp-base-link|python-plugin-link|python-plugin-inittab-link|rs274ngc-pre-object)
|
||||
;;
|
||||
"")
|
||||
usage
|
||||
echo "missing --mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
echo "unknown wasm standalone probe mode: $mode" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
cxx=${CXX:-g++}
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
cxx="ccache $cxx"
|
||||
fi
|
||||
build_jobs=${CNC_SIM_BUILD_JOBS:-8}
|
||||
if ! [[ "$build_jobs" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CNC_SIM_BUILD_JOBS must be a positive integer: $build_jobs" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=${CNC_SIM_WASM_STANDALONE_PROBE_CACHE_DIR-build/wasm-standalone-probe-cache}
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
echo "CNC_SIM_WASM_STANDALONE_PROBE_CACHE_DIR must not be empty" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_WASM_STANDALONE_PROBE_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_WASM_STANDALONE_PROBE_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preflight_cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-"$cache_dir/preflight-cache"}
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" --root-only
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
common_flag_args=()
|
||||
sources=()
|
||||
target_name=
|
||||
case "$mode" in
|
||||
tooldata-link|tooldata-common-link)
|
||||
if [[ "$mode" == "tooldata-common-link" ]]; then
|
||||
common_flag_args+=(--tooldata-include)
|
||||
fi
|
||||
tooldata_mmap_backend_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_mmap_backend.cc)
|
||||
tooldata_runtime_stubs_shim=$(./list-linuxcnc-wasm-safe-shims.sh tooldata_runtime_stubs.cc)
|
||||
tooldata_common_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/tooldata/tooldata_common.cc)
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_common.cc provides' core/wasm_shims/tooldata/tooldata_common_probe_main.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_mmap.cc, tooldata_nml.cc,' core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
sources+=(
|
||||
"$tooldata_common_source"
|
||||
"$tooldata_mmap_backend_shim"
|
||||
"$tooldata_runtime_stubs_shim"
|
||||
)
|
||||
if [[ "$mode" == "tooldata-link" ]]; then
|
||||
sources+=(core/wasm_shims/tooldata/tooldata_probe_main.cc)
|
||||
target_name=tooldata_probe
|
||||
else
|
||||
sources+=(core/wasm_shims/tooldata/tooldata_common_probe_main.cc)
|
||||
target_name=tooldata_common_probe
|
||||
fi
|
||||
;;
|
||||
interp-base-link)
|
||||
dlfcn_shim=$(./list-linuxcnc-wasm-safe-shims.sh dlfcn.cc)
|
||||
interp_base_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/rs274ngc/interp_base.cc)
|
||||
grep -F 'LinuxCNC source basis: src/emc/rs274ngc/interp_base.cc provides' core/wasm_shims/interp_base_probe_main.cc >/dev/null
|
||||
sources+=(
|
||||
"$dlfcn_shim"
|
||||
"$interp_base_source"
|
||||
core/wasm_shims/interp_base_probe_main.cc
|
||||
)
|
||||
target_name=interp_base_probe
|
||||
;;
|
||||
python-plugin-link|python-plugin-inittab-link)
|
||||
python_plugin_shim=$(./list-linuxcnc-wasm-safe-shims.sh python_plugin.cc)
|
||||
if [[ "$mode" == "python-plugin-link" ]]; then
|
||||
probe_source=core/wasm_shims/pythonplugin/python_plugin_probe_main.cc
|
||||
target_name=python_plugin_probe
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc and' "$probe_source" >/dev/null
|
||||
else
|
||||
probe_source=core/wasm_shims/pythonplugin/python_plugin_inittab_probe_main.cc
|
||||
target_name=python_plugin_inittab_probe
|
||||
grep -F 'LinuxCNC source basis: src/emc/pythonplugin/python_plugin.cc' "$probe_source" >/dev/null
|
||||
fi
|
||||
sources+=(
|
||||
"$python_plugin_shim"
|
||||
"$probe_source"
|
||||
)
|
||||
;;
|
||||
rs274ngc-pre-object)
|
||||
rs274ngc_pre_source=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-source-files.sh src/emc/rs274ngc/rs274ngc_pre.cc)
|
||||
grep -F 'core:src/emc/rs274ngc/rs274ngc_pre.cc:Interp implementation covered by rs274ngc_pre link probe' linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
sources+=("$rs274ngc_pre_source")
|
||||
target_name=rs274ngc_pre.o
|
||||
;;
|
||||
esac
|
||||
|
||||
common_flag_output=$(LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-common-cxxflags.sh "${common_flag_args[@]}")
|
||||
mapfile -t common_flags <<<"$common_flag_output"
|
||||
|
||||
mode_dir="$cache_dir/$mode"
|
||||
mkdir -p "$mode_dir"
|
||||
exec 8>"$mode_dir/probe.lock"
|
||||
flock 8
|
||||
|
||||
objects=()
|
||||
object_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
objects+=("$mode_dir/source_${object_index}.o")
|
||||
object_index=$((object_index + 1))
|
||||
done
|
||||
target="$mode_dir/$target_name"
|
||||
if [[ "$mode" == "rs274ngc-pre-object" ]]; then
|
||||
target=${objects[0]}
|
||||
fi
|
||||
|
||||
signature="$mode_dir/probe.signature"
|
||||
next_signature="$mode_dir/probe.signature.next"
|
||||
{
|
||||
printf 'CXX=%s\n' "$cxx"
|
||||
printf 'PWD=%s\n' "$PWD"
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'MODE=%s\n' "$mode"
|
||||
printf 'BUILD_RULE_VERSION=1\n'
|
||||
printf 'COMMON_FLAGS='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n'
|
||||
printf 'SOURCES:\n'
|
||||
printf '%s\n' "${sources[@]}"
|
||||
} > "$next_signature"
|
||||
if [[ ! -f "$signature" ]] || ! cmp -s "$signature" "$next_signature"; then
|
||||
rm -f "$mode_dir"/source_*.o "$mode_dir"/source_*.d "$target"
|
||||
fi
|
||||
mv "$next_signature" "$signature"
|
||||
|
||||
makefile="$mode_dir/probe.mk"
|
||||
{
|
||||
printf 'CXX := %s\n' "$cxx"
|
||||
printf 'COMMON_FLAGS :='
|
||||
printf ' %s' "${common_flags[@]}"
|
||||
printf '\n\n'
|
||||
printf 'OBJECTS :='
|
||||
printf ' %s' "${objects[@]}"
|
||||
printf '\n\n'
|
||||
printf 'DEP_FILES :=\n'
|
||||
for object in "${objects[@]}"; do
|
||||
printf 'DEP_FILES += %s.d\n' "$object"
|
||||
done
|
||||
printf '\n.PHONY: all\n'
|
||||
printf 'all: %s\n\n' "$target"
|
||||
|
||||
object_index=0
|
||||
for source in "${sources[@]}"; do
|
||||
printf '%s: %s\n' "${objects[$object_index]}" "$source"
|
||||
printf '\t@$(CXX) $(COMMON_FLAGS) -MMD -MP -MF %s.d -c %s -o %s\n\n' \
|
||||
"${objects[$object_index]}" "$source" "${objects[$object_index]}"
|
||||
object_index=$((object_index + 1))
|
||||
done
|
||||
|
||||
if [[ "$mode" != "rs274ngc-pre-object" ]]; then
|
||||
printf '%s: $(OBJECTS)\n' "$target"
|
||||
printf '\t@$(CXX) $(OBJECTS) -o %s\n\n' "$target"
|
||||
fi
|
||||
printf '\n-include $(DEP_FILES)\n'
|
||||
} > "$makefile"
|
||||
make --output-sync=target -j"$build_jobs" -f "$makefile" >/dev/null
|
||||
|
||||
printf '%s\n' "$target"
|
||||
211
build-wasm.sh
211
build-wasm.sh
@@ -3,99 +3,208 @@ set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: the wasm build preflights and compiles the
|
||||
# linuxcnc-rs274-wasm-source-files.txt manifest entries from
|
||||
# src/emc/rs274ngc/tooldata plus source-basis-checked shims before copying the
|
||||
# browser artifacts; it must not add independent interpreter behavior.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
if [[ ! -f "$manifest" ]]; then
|
||||
echo "missing manifest: $manifest" >&2
|
||||
build_jobs=${CNC_SIM_BUILD_JOBS:-8}
|
||||
if ! [[ "$build_jobs" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "CNC_SIM_BUILD_JOBS must be a positive integer: $build_jobs" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$linuxcnc_root" ]]; then
|
||||
echo "missing LinuxCNC root: $linuxcnc_root" >&2
|
||||
exit 1
|
||||
cmake_compiler_launcher_mode=none
|
||||
cmake_compiler_launcher_args=()
|
||||
if [[ -z ${CXX:-} ]] && command -v ccache >/dev/null 2>&1; then
|
||||
cmake_compiler_launcher_mode=ccache
|
||||
cmake_compiler_launcher_args+=(
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
)
|
||||
fi
|
||||
|
||||
preflight_cache_dir=build/wasm-preflight-cache
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" "$manifest"
|
||||
./check-linuxcnc-rs274-source-map.sh
|
||||
./check-linuxcnc-kinematics-source-map.sh
|
||||
./check-linuxcnc-opfs-source-map.sh
|
||||
./check-linuxcnc-switchkins-remap-source-map.sh
|
||||
./check-linuxcnc-wasm-smoke-source-map.sh
|
||||
./check-linuxcnc-build-source-map.sh
|
||||
./check-linuxcnc-browser-app-source-map.sh
|
||||
./check-linuxcnc-workstreams-source-map.sh
|
||||
./check-linuxcnc-tooldata-source-map.sh
|
||||
./check-linuxcnc-wasm-shims-source-map.sh
|
||||
./check-linuxcnc-wasm-blockers-source-map.sh
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table-cached.sh --cache-dir "$preflight_cache_dir" linuxcnc-kinematics-source-files.txt
|
||||
manifest=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
default_manifest="$PWD/linuxcnc-rs274-wasm-source-files.txt"
|
||||
|
||||
count_nonempty_lines() {
|
||||
local text=${1-}
|
||||
local count=0
|
||||
local line
|
||||
|
||||
while IFS= read -r line; do
|
||||
if [[ -n "$line" ]]; then
|
||||
count=$((count + 1))
|
||||
fi
|
||||
done <<<"$text"
|
||||
|
||||
printf '%s\n' "$count"
|
||||
}
|
||||
|
||||
parallel_probe_labels=()
|
||||
parallel_probe_logs=()
|
||||
parallel_probe_pids=()
|
||||
|
||||
run_parallel_wasm_probe() {
|
||||
local label=$1
|
||||
shift
|
||||
local probe_index=${#parallel_probe_pids[@]}
|
||||
local log_dir=build/wasm-preflight-cache/parallel-probe-logs
|
||||
local log="$log_dir/probe_${probe_index}.log"
|
||||
|
||||
mkdir -p "$log_dir"
|
||||
(
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" "$@"
|
||||
) >"$log" 2>&1 &
|
||||
parallel_probe_labels+=("$label")
|
||||
parallel_probe_logs+=("$log")
|
||||
parallel_probe_pids+=("$!")
|
||||
}
|
||||
|
||||
wait_parallel_wasm_probes() {
|
||||
local failed=0
|
||||
local probe_index
|
||||
local status
|
||||
|
||||
for probe_index in "${!parallel_probe_pids[@]}"; do
|
||||
echo "${parallel_probe_labels[$probe_index]}"
|
||||
if wait "${parallel_probe_pids[$probe_index]}"; then
|
||||
cat "${parallel_probe_logs[$probe_index]}"
|
||||
else
|
||||
status=$?
|
||||
cat "${parallel_probe_logs[$probe_index]}" >&2 || true
|
||||
echo "${parallel_probe_labels[$probe_index]} failed with status $status" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
parallel_probe_labels=()
|
||||
parallel_probe_logs=()
|
||||
parallel_probe_pids=()
|
||||
|
||||
if [[ "$failed" -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# This script writes fixed build and public artifact paths, so serialize it.
|
||||
if [[ "${CNC_SIM_BUILD_WASM_SKIP_LOCK:-0}" != "1" ]]; then
|
||||
exec 9>"${TMPDIR:-/tmp}/cnc_sim_build_wasm.lock"
|
||||
flock 9
|
||||
fi
|
||||
|
||||
manifest_core_count=0
|
||||
manifest_blocked_count=0
|
||||
manifest_core_sources=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_manifest_core.XXXXXX.txt")
|
||||
manifest_blocked_sources=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_manifest_blocked.XXXXXX.txt")
|
||||
trap 'rm -f "$manifest_core_sources" "$manifest_blocked_sources"' EXIT
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core > "$manifest_core_sources"
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked > "$manifest_blocked_sources"
|
||||
manifest_core_count=$(wc -l < "$manifest_core_sources")
|
||||
manifest_blocked_count=$(wc -l < "$manifest_blocked_sources")
|
||||
manifest_core_output=$(CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" core)
|
||||
manifest_blocked_output=$(CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" LINUXCNC_ROOT="$linuxcnc_root" ./list-linuxcnc-wasm-manifest-sources.sh "$manifest" blocked)
|
||||
manifest_core_count=$(count_nonempty_lines "$manifest_core_output")
|
||||
manifest_blocked_count=$(count_nonempty_lines "$manifest_blocked_output")
|
||||
|
||||
if [[ "$manifest_core_count" -eq 0 || "$manifest_blocked_count" -eq 0 ]]; then
|
||||
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$manifest" == "$default_manifest" ]] && [[ "$manifest_core_count" -ne 25 || "$manifest_blocked_count" -ne 1 ]]; then
|
||||
if [[ "$manifest" == "$default_manifest" ]] && [[ "$manifest_core_count" -ne 26 || "$manifest_blocked_count" -ne 9 ]]; then
|
||||
echo "unexpected wasm manifest partition: core=$manifest_core_count blocked=$manifest_blocked_count" >&2
|
||||
exit 1
|
||||
fi
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh --cache-dir "$preflight_cache_dir" "$manifest" --require-rs274-complete
|
||||
|
||||
echo "LinuxCNC wasm blocker scan"
|
||||
./test-linuxcnc-wasm-blockers.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-blockers.sh "$manifest"
|
||||
|
||||
echo "LinuxCNC wasm-safe source syntax probe"
|
||||
./test-linuxcnc-wasm-source-syntax.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-source-syntax.sh "$manifest"
|
||||
|
||||
echo "LinuxCNC wasm-safe source object probe"
|
||||
./test-linuxcnc-wasm-source-objects.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-source-objects.sh "$manifest"
|
||||
|
||||
echo "LinuxCNC wasm-safe CMake probe target"
|
||||
./test-linuxcnc-wasm-cmake-safe-probe.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-cmake-safe-probe.sh "$manifest"
|
||||
|
||||
echo "LinuxCNC wasm tooldata shim link probe"
|
||||
./test-linuxcnc-wasm-tooldata-link.sh
|
||||
|
||||
echo "LinuxCNC wasm tooldata_common link probe"
|
||||
./test-linuxcnc-wasm-tooldata-common-link.sh
|
||||
|
||||
echo "LinuxCNC wasm tooldata_mmap symbol probe"
|
||||
./test-linuxcnc-wasm-tooldata-mmap-symbols.sh
|
||||
|
||||
echo "LinuxCNC wasm tooldata runtime symbol probe"
|
||||
./test-linuxcnc-wasm-tooldata-runtime-symbols.sh
|
||||
|
||||
echo "LinuxCNC wasm interp_base link probe"
|
||||
./test-linuxcnc-wasm-interp-base-link.sh
|
||||
|
||||
echo "LinuxCNC wasm interp_find link probe"
|
||||
./test-linuxcnc-wasm-interp-find-link.sh
|
||||
|
||||
echo "LinuxCNC wasm python_plugin link probe"
|
||||
./test-linuxcnc-wasm-python-plugin-link.sh
|
||||
|
||||
echo "LinuxCNC wasm rs274ngc_pre object probe"
|
||||
./test-linuxcnc-wasm-rs274ngc-pre-object.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe" ./test-linuxcnc-wasm-tooldata-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm tooldata_common link probe" ./test-linuxcnc-wasm-tooldata-common-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm tooldata_mmap symbol probe" ./test-linuxcnc-wasm-tooldata-mmap-symbols.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm tooldata runtime symbol probe" ./test-linuxcnc-wasm-tooldata-runtime-symbols.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm interp_base link probe" ./test-linuxcnc-wasm-interp-base-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm interp_find link probe" ./test-linuxcnc-wasm-interp-find-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm python_plugin link probe" ./test-linuxcnc-wasm-python-plugin-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm Python C API symbol probe" ./test-linuxcnc-wasm-python-c-api-symbols.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm Python binding link probe" ./test-linuxcnc-wasm-python-binding-link.sh
|
||||
run_parallel_wasm_probe "LinuxCNC wasm rs274ngc_pre object probe" ./test-linuxcnc-wasm-rs274ngc-pre-object.sh
|
||||
wait_parallel_wasm_probes
|
||||
|
||||
echo "LinuxCNC wasm rs274ngc_pre link blocker scan"
|
||||
./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-rs274ngc-pre-link-blockers.sh "$manifest"
|
||||
|
||||
echo "LinuxCNC wasm rs274ngc_pre link probe"
|
||||
./test-linuxcnc-wasm-rs274ngc-pre-link.sh "$manifest"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-rs274ngc-pre-link.sh "$manifest"
|
||||
|
||||
if ! command -v emcmake >/dev/null 2>&1; then
|
||||
echo "Emscripten is required. Install/activate emsdk so emcmake and emcc are in PATH." >&2
|
||||
echo "LinuxCNC wasm runtime link probe"
|
||||
CNC_SIM_PREFLIGHT_CACHE_DIR="$preflight_cache_dir" ./test-linuxcnc-wasm-runtime-link.sh "$manifest"
|
||||
|
||||
missing_tools=()
|
||||
for required_tool in cmake emcmake emcc node; do
|
||||
if ! command -v "$required_tool" >/dev/null 2>&1; then
|
||||
missing_tools+=("$required_tool")
|
||||
fi
|
||||
done
|
||||
if ((${#missing_tools[@]} > 0)); then
|
||||
echo "WASM build tools are required. Missing: ${missing_tools[*]}." >&2
|
||||
echo "Install/activate cmake, emsdk, and Node.js so cmake, emcmake, emcc, and node are in PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
wasm_build_signature=build/wasm/wasm-build.signature
|
||||
wasm_build_next_signature=$(mktemp "${TMPDIR:-/tmp}/cnc_sim_wasm_build.signature.XXXXXX")
|
||||
{
|
||||
printf 'CXX=%s\n' "${CXX:-g++}"
|
||||
printf 'PWD=%s\n' "$PWD"
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'MANIFEST=%s\n' "$manifest"
|
||||
printf 'MANIFEST_HASH='
|
||||
sha256sum "$manifest"
|
||||
printf 'COMPILER_LAUNCHER=%s\n' "$cmake_compiler_launcher_mode"
|
||||
printf 'CMAKE_LISTS='
|
||||
sha256sum core/CMakeLists.txt
|
||||
printf 'CONFIGURE_RULE_VERSION=2\n'
|
||||
} > "$wasm_build_next_signature"
|
||||
configure_wasm=1
|
||||
if [[ ! -f "$wasm_build_signature" ]] || ! cmp -s "$wasm_build_signature" "$wasm_build_next_signature"; then
|
||||
mkdir -p build/wasm
|
||||
elif [[ -f build/wasm/CMakeCache.txt ]]; then
|
||||
configure_wasm=0
|
||||
fi
|
||||
|
||||
if [[ "$configure_wasm" == "1" ]]; then
|
||||
emcmake cmake -S core -B build/wasm \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCNC_SIM_LINUXCNC_ROOT="$linuxcnc_root" \
|
||||
-DCNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST="$manifest" \
|
||||
-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON
|
||||
cmake --build build/wasm
|
||||
|
||||
-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON \
|
||||
-DCNC_SIM_ENABLE_SMOKE_BACKEND=OFF \
|
||||
"${cmake_compiler_launcher_args[@]}"
|
||||
fi
|
||||
mv "$wasm_build_next_signature" "$wasm_build_signature"
|
||||
cmake --build build/wasm --target cnc_sim_wasm_runtime_probe cnc_sim_wasm --parallel "$build_jobs"
|
||||
mkdir -p web/public
|
||||
cp build/wasm/cnc_sim.js web/public/
|
||||
cp build/wasm/cnc_sim.wasm web/public/
|
||||
cp build/wasm/cnc_sim.js web/public/cnc_sim.js
|
||||
cp build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm
|
||||
cmp -s build/wasm/cnc_sim.js web/public/cnc_sim.js
|
||||
cmp -s build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm
|
||||
./test-web-wasm-node-smoke.sh
|
||||
./test-web-wasm-browser-smoke.sh
|
||||
|
||||
130
check-linuxcnc-browser-app-source-map.sh
Executable file
130
check-linuxcnc-browser-app-source-map.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the browser app entry point to
|
||||
# LinuxCNC RS274 parameter-file defaults, rs274ngc_pre.cc restore/save/read
|
||||
# file semantics, and the existing OPFS-backed wasm-core bridge. It validates
|
||||
# app integration policy only; it does not add CNC behavior or expand smoke
|
||||
# parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC browser app source map' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC behavior' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F '`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F '`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
grep -F 'orders parameter saves as backup unlink' \
|
||||
docs/linuxcnc-browser-app-source-map.md >/dev/null
|
||||
|
||||
grep -F '<script type="module" src="/src/app.js"></script>' web/index.html >/dev/null
|
||||
grep -F '<option value="linuxcnc-rs274">LINUXCNC</option>' web/index.html >/dev/null
|
||||
if [[ "$(grep -Fc '<option value=' web/index.html)" -ne 1 ]]; then
|
||||
echo "browser app backend selector must expose only the LinuxCNC RS274 backend" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep -F 'import { createWasmSimulator } from "./wasm-core.js";' web/src/app.js >/dev/null
|
||||
grep -F 'const programPath = "programs/current.ngc";' web/src/app.js >/dev/null
|
||||
grep -F 'const linuxCncParameterFileName = "rs274ngc.var";' web/src/app.js >/dev/null
|
||||
grep -F 'const parameterPath = `parameters/${linuxCncParameterFileName}`;' web/src/app.js >/dev/null
|
||||
grep -F 'const linuxCncBackend = "linuxcnc-rs274";' web/src/app.js >/dev/null
|
||||
grep -F 'const opfsOptions = { required: true, mountPoint: "/cnc", workspacePath: "cnc-simulator" };' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'simulatorPromise = createWasmSimulator({' web/src/app.js >/dev/null
|
||||
grep -F 'opfs: opfsOptions,' web/src/app.js >/dev/null
|
||||
grep -F 'OPFS workspace is required for browser program parsing' web/src/app.js >/dev/null
|
||||
grep -F 'await simulator.fs.opfs.writeFile(programPath, elements.input.value);' web/src/app.js >/dev/null
|
||||
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'elements.backendSelect.value = linuxCncBackend;' web/src/app.js >/dev/null
|
||||
grep -F 'globalThis.__cncSimulatorForTest = simulatorPromise;' web/src/app.js >/dev/null
|
||||
|
||||
grep -F 'app frame did not persist current program into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter state into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'OPFS PROGRAM RESTORED' web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not reload LinuxCNC parameter state from OPFS after reload' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'runSection("browser app opfs save"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-browser-app-source-map.md").read_text(encoding="utf-8")
|
||||
for entry in [
|
||||
"web/index.html",
|
||||
"web/src/app.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing app entry: {entry}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"existing `createWasmSimulator()` OPFS API",
|
||||
"programs/current.ngc",
|
||||
"parameters/rs274ngc.var",
|
||||
"visible backend selector must stay limited",
|
||||
"./check-linuxcnc-browser-app-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-browser-app-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-browser-app-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-browser-app-source-map.sh")
|
||||
|
||||
app = Path("web/src/app.js").read_text(encoding="utf-8")
|
||||
if "parse(" in app.replace("parseProgram", ""):
|
||||
raise SystemExit("browser app should route program execution through parseFileWithParameterFile, not direct parse")
|
||||
if app.count("elements.backendSelect.value = linuxCncBackend;") != 2:
|
||||
raise SystemExit("browser app backend selector must only be forced to the LinuxCNC backend")
|
||||
if "backendSelect.value" in app.replace("elements.backendSelect.value = linuxCncBackend;", ""):
|
||||
raise SystemExit("browser app must not read the backend selector as a dynamic backend source")
|
||||
if 'backend: linuxCncBackend' not in app:
|
||||
raise SystemExit("browser app parse options must force the LinuxCNC backend")
|
||||
PY
|
||||
202
check-linuxcnc-build-source-map.sh
Executable file
202
check-linuxcnc-build-source-map.sh
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties native/source-link/WASM build entry
|
||||
# points to LinuxCNC Submakefile source ownership, source manifests, persistent
|
||||
# build signatures, and source-backed WASM artifact ordering. It validates
|
||||
# build policy only; it does not add CNC behavior, expand smoke parsing, or
|
||||
# interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LIBRS274SRCS := $(addprefix emc/rs274ngc/,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'rs274ngc_pre.cc \' "$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F '../lib/libtooldata.so.0' "$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_mmap.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_db.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBLCNCINISRCS := emc/ini/inifile.cc' \
|
||||
"$linuxcnc_root/src/emc/ini/Submakefile" >/dev/null
|
||||
grep -F 'LIBPPSRCS := $(addprefix emc/pythonplugin/,' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/Submakefile" >/dev/null
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC build source map' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`src/emc/rs274ngc/Submakefile` defines `LIBRS274SRCS`' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/Submakefile` defines the LinuxCNC tooldata' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F 'Default WASM manifest partition must remain 26 wasm-safe `core` sources and' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`build-wasm.sh` must configure with `CNC_SIM_ENABLE_SMOKE_BACKEND=OFF`' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
grep -F '`test-native.sh`, `test-linuxcnc-source-link.sh`, and `build-wasm.sh` must' \
|
||||
docs/linuxcnc-build-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: the wasm build preflights and compiles the' build-wasm.sh >/dev/null
|
||||
source_map_guards=(
|
||||
'./check-linuxcnc-rs274-source-map.sh'
|
||||
'./check-linuxcnc-kinematics-source-map.sh'
|
||||
'./check-linuxcnc-opfs-source-map.sh'
|
||||
'./check-linuxcnc-switchkins-remap-source-map.sh'
|
||||
'./check-linuxcnc-wasm-smoke-source-map.sh'
|
||||
'./check-linuxcnc-build-source-map.sh'
|
||||
'./check-linuxcnc-browser-app-source-map.sh'
|
||||
'./check-linuxcnc-workstreams-source-map.sh'
|
||||
'./check-linuxcnc-tooldata-source-map.sh'
|
||||
'./check-linuxcnc-wasm-shims-source-map.sh'
|
||||
'./check-linuxcnc-wasm-blockers-source-map.sh'
|
||||
)
|
||||
for guarded_entry in test-native.sh test-linuxcnc-source-link.sh build-wasm.sh; do
|
||||
for source_map_guard in "${source_map_guards[@]}"; do
|
||||
grep -F "$source_map_guard" "$guarded_entry" >/dev/null
|
||||
done
|
||||
done
|
||||
grep -F 'manifest_core_count=$(count_nonempty_lines "$manifest_core_output")' build-wasm.sh >/dev/null
|
||||
grep -F 'manifest_blocked_count=$(count_nonempty_lines "$manifest_blocked_output")' build-wasm.sh >/dev/null
|
||||
grep -F 'manifest_core_count" -ne 26 || "$manifest_blocked_count" -ne 9' build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe" ./test-linuxcnc-wasm-tooldata-link.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm rs274ngc_pre object probe" ./test-linuxcnc-wasm-rs274ngc-pre-object.sh' build-wasm.sh >/dev/null
|
||||
grep -F 'wait_parallel_wasm_probes' build-wasm.sh >/dev/null
|
||||
grep -F 'for required_tool in cmake emcmake emcc node; do' build-wasm.sh >/dev/null
|
||||
grep -F 'CONFIGURE_RULE_VERSION=2' build-wasm.sh >/dev/null
|
||||
grep -F -- '-DCNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE=ON' build-wasm.sh >/dev/null
|
||||
grep -F -- '-DCNC_SIM_ENABLE_SMOKE_BACKEND=OFF' build-wasm.sh >/dev/null
|
||||
grep -F 'cmake --build build/wasm --target cnc_sim_wasm_runtime_probe cnc_sim_wasm --parallel "$build_jobs"' build-wasm.sh >/dev/null
|
||||
grep -F 'cmp -s build/wasm/cnc_sim.js web/public/cnc_sim.js' build-wasm.sh >/dev/null
|
||||
grep -F 'cmp -s build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm' build-wasm.sh >/dev/null
|
||||
grep -F './test-web-wasm-node-smoke.sh' build-wasm.sh >/dev/null
|
||||
grep -F './test-web-wasm-browser-smoke.sh' build-wasm.sh >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: this source-link test compiles the manifest-selected' \
|
||||
test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'BUILD_RULE_VERSION=1' test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'make --output-sync=target -j"$build_jobs" -f "$source_link_makefile"' \
|
||||
test-linuxcnc-source-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this syntax probe checks the native RS274 manifest' \
|
||||
test-linuxcnc-source-syntax.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: the wasm syntax probe compiles the' \
|
||||
test-linuxcnc-wasm-source-syntax.sh >/dev/null
|
||||
grep -F "printf 'CONFIGURE_RULE_VERSION=1\n'" \
|
||||
test-linuxcnc-wasm-cmake-safe-probe.sh >/dev/null
|
||||
grep -F 'cmake --build "$build_dir" --target linuxcnc_rs274_wasm_safe_probe cnc_sim_wasm_runtime_probe --parallel "$build_jobs"' \
|
||||
test-linuxcnc-wasm-cmake-safe-probe.sh >/dev/null
|
||||
|
||||
if grep -F 'printf '\''BUILD_JOBS=%s\n'\'' "$build_jobs"' build-wasm.sh >/dev/null; then
|
||||
echo "build-wasm configure signature must not depend on CNC_SIM_BUILD_JOBS" >&2
|
||||
exit 1
|
||||
fi
|
||||
for hot_signature_script in \
|
||||
build-linuxcnc-wasm-link-probe.sh \
|
||||
build-linuxcnc-wasm-probe-objects.sh \
|
||||
build-linuxcnc-wasm-standalone-probe.sh \
|
||||
build-linuxcnc-native-bridge-objects.sh \
|
||||
test-linuxcnc-api-native.sh \
|
||||
test-linuxcnc-bridge-native.sh \
|
||||
test-linuxcnc-rs274-native.sh \
|
||||
test-linuxcnc-source-link.sh \
|
||||
test-linuxcnc-source-objects.sh \
|
||||
test-linuxcnc-source-syntax.sh \
|
||||
test-native.sh; do
|
||||
if grep -F "sha256sum $hot_signature_script" "$hot_signature_script" >/dev/null; then
|
||||
echo "$hot_signature_script hot object signature must use BUILD_RULE_VERSION instead of the whole script hash" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
source_map = Path("docs/linuxcnc-build-source-map.md").read_text(encoding="utf-8")
|
||||
wasm_manifest = Path("linuxcnc-rs274-wasm-source-files.txt")
|
||||
core_count = len(subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-manifest-sources.sh", str(wasm_manifest), "core"],
|
||||
text=True,
|
||||
).splitlines())
|
||||
blocked_count = len(subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-manifest-sources.sh", str(wasm_manifest), "blocked"],
|
||||
text=True,
|
||||
).splitlines())
|
||||
if core_count != 26 or blocked_count != 9:
|
||||
raise SystemExit(f"unexpected default WASM manifest partition: core={core_count} blocked={blocked_count}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"test-linuxcnc-source-syntax.sh",
|
||||
"test-linuxcnc-wasm-cmake-safe-probe.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-build-source-map.md missing build entry: {entry}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC",
|
||||
"must not expand the temporary smoke parser",
|
||||
"CNC_SIM_BUILD_JOBS",
|
||||
"BUILD_RULE_VERSION",
|
||||
"CONFIGURE_RULE_VERSION",
|
||||
"CNC_SIM_ENABLE_SMOKE_BACKEND=OFF",
|
||||
"Node smoke before browser smoke",
|
||||
"does not interpret",
|
||||
"G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-build-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
build_wasm = Path("build-wasm.sh").read_text(encoding="utf-8").splitlines()
|
||||
positions = {}
|
||||
for index, line in enumerate(build_wasm, start=1):
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe"' in line:
|
||||
positions["parallel_start"] = index
|
||||
if "wait_parallel_wasm_probes" in line and "parallel_start" in positions and "wait" not in positions:
|
||||
positions["wait"] = index
|
||||
if "LinuxCNC wasm rs274ngc_pre link blocker scan" in line:
|
||||
positions["pre_link"] = index
|
||||
if "for required_tool in cmake emcmake emcc node; do" in line:
|
||||
positions["tools"] = index
|
||||
if "emcmake cmake -S core -B build/wasm" in line:
|
||||
positions["configure"] = index
|
||||
if "cmake --build build/wasm --target cnc_sim_wasm_runtime_probe cnc_sim_wasm" in line:
|
||||
positions["build"] = index
|
||||
if "cp build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["cp_js"] = index
|
||||
if "cp build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["cp_wasm"] = index
|
||||
if "cmp -s build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["cmp_js"] = index
|
||||
if "cmp -s build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["cmp_wasm"] = index
|
||||
if "./test-web-wasm-node-smoke.sh" in line:
|
||||
positions["node"] = index
|
||||
if "./test-web-wasm-browser-smoke.sh" in line:
|
||||
positions["browser"] = index
|
||||
|
||||
required = [
|
||||
"parallel_start", "wait", "pre_link", "tools", "configure", "build",
|
||||
"cp_js", "cp_wasm", "cmp_js", "cmp_wasm", "node", "browser",
|
||||
]
|
||||
missing = [name for name in required if name not in positions]
|
||||
if missing:
|
||||
raise SystemExit(f"build-wasm.sh missing ordered build anchors: {', '.join(missing)}")
|
||||
if not (positions["parallel_start"] < positions["wait"] < positions["pre_link"]):
|
||||
raise SystemExit("build-wasm.sh must wait for parallel probes before rs274ngc_pre link checks")
|
||||
if not (positions["tools"] < positions["configure"] < positions["build"]):
|
||||
raise SystemExit("build-wasm.sh must check tools, then configure, then build")
|
||||
if not (positions["cp_js"] < positions["cmp_js"] < positions["node"] < positions["browser"]):
|
||||
raise SystemExit("build-wasm.js artifact JS copy/compare or smoke ordering changed")
|
||||
if not (positions["cp_wasm"] < positions["cmp_wasm"] < positions["node"] < positions["browser"]):
|
||||
raise SystemExit("build-wasm.wasm artifact copy/compare or smoke ordering changed")
|
||||
PY
|
||||
136
check-linuxcnc-inputs-cached.sh
Executable file
136
check-linuxcnc-inputs-cached.sh
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: the cached input checker keys check-linuxcnc-inputs.sh
|
||||
# results by manifest contents and LinuxCNC source mtimes so source-backed
|
||||
# rs274/kinematics coverage is not silently reused after upstream changes.
|
||||
cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-}
|
||||
check_args=("$@")
|
||||
if [[ "${1:-}" == "--cache-dir" ]]; then
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
echo "missing --cache-dir value" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=$2
|
||||
shift 2
|
||||
check_args=("$@")
|
||||
fi
|
||||
|
||||
manifest=${1:-}
|
||||
require_complete=${2:-}
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_PREFLIGHT_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_PREFLIGHT_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
exec 8>"$cache_dir/check-linuxcnc-inputs.lock"
|
||||
flock 8
|
||||
|
||||
if [[ ! -d "$linuxcnc_root" ]]; then
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
manifest_key=ROOT_ONLY
|
||||
manifest_path=
|
||||
if [[ -n "$manifest" && "$manifest" != "--root-only" ]]; then
|
||||
if [[ ! -f "$manifest" ]]; then
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
manifest_path=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
manifest_key=$(printf '%s' "$manifest_path" | sha256sum | awk '{ print $1 }')
|
||||
fi
|
||||
|
||||
safe_require=${require_complete:-none}
|
||||
safe_require=${safe_require//[^A-Za-z0-9_.-]/_}
|
||||
args_key=$(
|
||||
{
|
||||
printf 'ARGS='
|
||||
printf ' %q' "${check_args[@]}"
|
||||
printf '\n'
|
||||
} | sha256sum | awk '{ print $1 }'
|
||||
)
|
||||
cache_file="$cache_dir/check-linuxcnc-inputs.${manifest_key}.${safe_require}.${args_key}.signature"
|
||||
next_signature=$(mktemp "$cache_file.next.XXXXXX")
|
||||
|
||||
write_source_stat_signature() {
|
||||
local source_path
|
||||
[[ -z "$manifest_path" ]] && return 0
|
||||
while IFS=: read -r group path note extra; do
|
||||
case "$group" in
|
||||
""|\#*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
[[ -z "${path:-}" ]] && continue
|
||||
source_path="$linuxcnc_root/$path"
|
||||
if [[ ! -f "$source_path" ]]; then
|
||||
return 1
|
||||
fi
|
||||
stat -c 'SOURCE=%n:%s:%y' "$source_path"
|
||||
done < "$manifest_path"
|
||||
}
|
||||
|
||||
write_complete_mode_signature() {
|
||||
case "$require_complete" in
|
||||
--require-rs274-complete)
|
||||
find "$linuxcnc_root/src/emc/rs274ngc" -maxdepth 1 -type f \
|
||||
-printf 'RS274=%P:%s:%T@\n' | sort
|
||||
;;
|
||||
--require-kinematics-complete)
|
||||
for source_dir in \
|
||||
"$linuxcnc_root/src/emc/kinematics" \
|
||||
"$linuxcnc_root/src/libnml/posemath" \
|
||||
"$linuxcnc_root/configs/sim"; do
|
||||
[[ -d "$source_dir" ]] || return 1
|
||||
find "$source_dir" -type f -printf "KIN=$source_dir/%P:%s:%T@\n" | sort
|
||||
done
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if ! {
|
||||
printf 'CACHED_SCRIPT='
|
||||
sha256sum check-linuxcnc-inputs-cached.sh
|
||||
printf 'CHECK_SCRIPT='
|
||||
sha256sum check-linuxcnc-inputs.sh
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'ARGS='
|
||||
printf ' %q' "${check_args[@]}"
|
||||
printf '\n'
|
||||
if [[ -n "$manifest_path" ]]; then
|
||||
printf 'MANIFEST_PATH=%s\n' "$manifest_path"
|
||||
printf 'MANIFEST='
|
||||
sha256sum "$manifest_path"
|
||||
write_source_stat_signature
|
||||
fi
|
||||
write_complete_mode_signature
|
||||
} > "$next_signature"; then
|
||||
rm -f "$next_signature"
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f "$cache_file" ]] && cmp -s "$cache_file" "$next_signature"; then
|
||||
rm -f "$next_signature"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs.sh "${check_args[@]}"
|
||||
mv "$next_signature" "$cache_file"
|
||||
1443
check-linuxcnc-inputs.sh
Executable file
1443
check-linuxcnc-inputs.sh
Executable file
File diff suppressed because it is too large
Load Diff
97
check-linuxcnc-kinematics-source-map.sh
Executable file
97
check-linuxcnc-kinematics-source-map.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard keeps the kinematics source map aligned
|
||||
# with linuxcnc-kinematics-source-files.txt, which enumerates LinuxCNC
|
||||
# kinematics, posemath, switchkins INI/HAL/remap/tooldata/assets, and adjacent
|
||||
# build metadata. It validates source coverage documentation only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F 'extern int kinematicsSwitch(int switchkins_type);' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F 'motion.switchkins-type' \
|
||||
"$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini" >/dev/null
|
||||
grep -F '#<kinstype>' \
|
||||
"$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc" >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
manifest = Path("linuxcnc-kinematics-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
source_map = Path("docs/linuxcnc-kinematics-source-map.md").read_text(encoding="utf-8")
|
||||
|
||||
expected_groups = [
|
||||
"core",
|
||||
"config",
|
||||
"remap",
|
||||
"component",
|
||||
"generated",
|
||||
"header",
|
||||
"metadata",
|
||||
"asset",
|
||||
"tooldata",
|
||||
]
|
||||
counts = {group: 0 for group in expected_groups}
|
||||
for line in manifest:
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
group = line.split(":", 1)[0]
|
||||
if group not in counts:
|
||||
raise SystemExit(f"unexpected kinematics manifest group in source map guard: {group}")
|
||||
counts[group] += 1
|
||||
|
||||
for group, count in counts.items():
|
||||
pattern = rf"\| `{re.escape(group)}` \| {count} \|"
|
||||
if not re.search(pattern, source_map):
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md {group} count no longer matches linuxcnc-kinematics-source-files.txt"
|
||||
)
|
||||
|
||||
for group in expected_groups:
|
||||
if f"`{group}`" not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md is missing kinematics manifest group {group}"
|
||||
)
|
||||
|
||||
required_phrases = [
|
||||
"LinuxCNC Source Anchors",
|
||||
"must not add CNC behavior",
|
||||
"must not",
|
||||
"expand the temporary smoke parser",
|
||||
"`src/emc/kinematics/Submakefile`",
|
||||
"`src/emc/kinematics/kinematics.h`",
|
||||
"motion.switchkins-type",
|
||||
"`#<kinstype>` remap assignment",
|
||||
"not browser API surface",
|
||||
"OPFS-only",
|
||||
"derive M428/M429/M430 cases from",
|
||||
"RTCP and five-axis coverage",
|
||||
"./check-linuxcnc-kinematics-source-map.sh",
|
||||
"./check-linuxcnc-inputs.sh linuxcnc-kinematics-source-files.txt --require-kinematics-complete",
|
||||
"./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-kinematics-source-map.md is missing source-coverage boundary phrase: {phrase}"
|
||||
)
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-kinematics-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-kinematics-source-map.sh")
|
||||
PY
|
||||
182
check-linuxcnc-opfs-source-map.sh
Executable file
182
check-linuxcnc-opfs-source-map.sh
Executable file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties browser OPFS parameter persistence to
|
||||
# interp_internal.hh defaults and rs274ngc_pre.cc restore_parameters() /
|
||||
# save_parameters() file semantics. It validates bridge policy only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::open(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '_setup.file_pointer = fopen(filename, "r");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
|
||||
grep -F 'RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX` as `.bak`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::restore_parameters()` for parameter-file reads' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::open()` by opening' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`fopen(filename, "r")`, then `Interp::_read()`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`read_text()`' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '`Interp::save_parameters()` for `filename + ".new"`' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'unlinks `filename + ".bak"`, links the' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'must not add independent filesystem behavior or expand the temporary smoke parser' \
|
||||
docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'parseFileWithParameterFile()' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F 'OPFS Coverage' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/wasm-core.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/wasm-core.d.ts` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/src/app.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-basic-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-parameter-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-workspace-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-mirror-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-directory-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-opfs-policy-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
grep -F '| `web/test-browser-wasm-smoke-app-sections.js` |' docs/linuxcnc-opfs-source-map.md >/dev/null
|
||||
|
||||
grep -F 'const LINUXCNC_DEFAULT_PARAMETER_FILE = "rs274ngc.var";' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async parseFile(path, dialect = "linuxcnc", options = {})' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS workspace is not available for program file parsing' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'const program = new TextDecoder().decode(await opfs.readFile(path));' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async parseFileWithParameterFile(path, parameterPath, dialect = "linuxcnc", options = {})' \
|
||||
web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS workspace is not available for program and parameter file parsing' web/src/wasm-core.js >/dev/null
|
||||
grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.new`' web/src/wasm-core.js >/dev/null
|
||||
grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.bak`' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters() reads the' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'before replacing the main file and managing filename + ".bak".' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'OPFS cannot be disabled in browser contexts with OPFS support' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS path must stay inside the CNC workspace' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'OPFS mount point must stay inside the Emscripten filesystem' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async persistDirectory(path)' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'async readDirectory(path)' web/src/wasm-core.js >/dev/null
|
||||
grep -F 'export type WasmOpfsWorkspace = {' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'readDirectory(path: string): Promise<string[]>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'persistDirectory(path: string): Promise<string[]>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'loadParameterFile(path: string): Promise<Uint8Array | null>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'persistParameterFile(path: string): Promise<Uint8Array>;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'opfs?: false | {' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'mountPoint?: string;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'workspacePath?: string;' web/src/wasm-core.d.ts >/dev/null
|
||||
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
|
||||
web/src/app.js >/dev/null
|
||||
grep -F 'OPFS workspace is required for browser program parsing' web/src/app.js >/dev/null
|
||||
grep -F 'runBrowserOpfsBasicSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsParameterSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsMirrorSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsDirectorySections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsPolicySections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs metadata queries avoid wasm mirror pollution"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs copy and move mirror files"' \
|
||||
web/test-browser-wasm-smoke-opfs-mirror-sections.js >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' \
|
||||
web/test-browser-wasm-smoke-opfs-policy-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs parameter restore in new instance"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs invalid parameter restore failures"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs stale parameter state cleanup"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs program parse and restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' \
|
||||
web/test-browser-wasm-smoke-*.js \
|
||||
web/test-browser-wasm-smoke.html \
|
||||
test-web-wasm-browser-smoke.sh; then
|
||||
echo "browser OPFS smoke harness must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-opfs-source-map.md").read_text(encoding="utf-8")
|
||||
coverage_entries = [
|
||||
"web/src/wasm-core.js",
|
||||
"web/src/wasm-core.d.ts",
|
||||
"web/src/app.js",
|
||||
"web/test-browser-wasm-smoke-opfs-basic-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-parameter-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-workspace-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-mirror-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-directory-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-policy-sections.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]
|
||||
for entry in coverage_entries:
|
||||
if f"| `{entry}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-opfs-source-map.md missing OPFS coverage entry: {entry}")
|
||||
|
||||
required_phrases = [
|
||||
"programs/current.ngc",
|
||||
"parameters/rs274ngc.var",
|
||||
'fopen(filename, "r")',
|
||||
"LinuxCNC `read_text()`",
|
||||
"program reads and parameter restore/save bridge files under the OPFS workspace",
|
||||
"`.new`, `.bak`, failure, and stale-state semantics",
|
||||
'unlinks `filename + ".bak"`',
|
||||
"OPFS/WASM mirror persistence",
|
||||
"OPFS directory persistence and WASM mirror refresh",
|
||||
"OPFS workspace and mount policy",
|
||||
"Browser OPFS smoke harness files must also stay free of Local Storage",
|
||||
"they may only verify OPFS-backed browser persistence",
|
||||
"OPFS-backed workspace, directory, parameter-file, and mount/workspace option types",
|
||||
"app-level OPFS program, parameter, backup, and reload behavior",
|
||||
"./check-linuxcnc-opfs-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-opfs-source-map.md missing OPFS coverage phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-opfs-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-opfs-source-map.sh")
|
||||
PY
|
||||
102
check-linuxcnc-rs274-source-map.sh
Executable file
102
check-linuxcnc-rs274-source-map.sh
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard keeps the local source map aligned with the
|
||||
# LinuxCNC-root relative rs274 manifests that drive native and WASM source-link
|
||||
# probes. It validates documentation/manifest drift only; it does not add CNC
|
||||
# behavior, expand smoke parsing, or interpret G-code.
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
source_map = Path("docs/linuxcnc-rs274-source-map.md").read_text(encoding="utf-8")
|
||||
native_manifest = Path("linuxcnc-rs274-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
wasm_manifest = Path("linuxcnc-rs274-wasm-source-files.txt").read_text(encoding="utf-8").splitlines()
|
||||
|
||||
expected = {
|
||||
"### Interpreter core": [
|
||||
Path(line.split(":", 2)[1]).name
|
||||
for line in native_manifest
|
||||
if line.startswith("core:")
|
||||
],
|
||||
"### Python binding modules": [
|
||||
Path(line.split(":", 2)[1]).name
|
||||
for line in native_manifest
|
||||
if line.startswith("binding:")
|
||||
],
|
||||
"### WASM-safe source core": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("core:")
|
||||
],
|
||||
"### WASM-blocked sources": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("blocked:")
|
||||
],
|
||||
"### WASM-tracked headers": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("header:")
|
||||
],
|
||||
"### WASM-blocked headers": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("blocked-header:")
|
||||
],
|
||||
"### WASM metadata sources": [
|
||||
line.split(":", 2)[1]
|
||||
for line in wasm_manifest
|
||||
if line.startswith("metadata:")
|
||||
],
|
||||
}
|
||||
|
||||
actual = {section: [] for section in expected}
|
||||
active_section = None
|
||||
for line in source_map.splitlines():
|
||||
if line in expected:
|
||||
active_section = line
|
||||
continue
|
||||
if active_section and line.startswith("### "):
|
||||
active_section = None
|
||||
if active_section and line.startswith("- `"):
|
||||
actual[active_section].append(line.split("`", 2)[1])
|
||||
|
||||
labels = {
|
||||
"### Interpreter core": "interpreter core",
|
||||
"### Python binding modules": "Python binding module",
|
||||
"### WASM-safe source core": "WASM-safe source core",
|
||||
"### WASM-blocked sources": "WASM-blocked source",
|
||||
"### WASM-tracked headers": "WASM-tracked header",
|
||||
"### WASM-blocked headers": "WASM-blocked header",
|
||||
"### WASM metadata sources": "WASM metadata source",
|
||||
}
|
||||
for section, expected_entries in expected.items():
|
||||
if actual[section] != expected_entries:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-rs274-source-map.md {labels[section]} list no longer matches source manifest"
|
||||
)
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"source coverage only",
|
||||
"must not become browser API fields",
|
||||
"temporary smoke parser fallback behavior",
|
||||
"Browser-hostile dependencies must remain tracked blockers",
|
||||
"./check-linuxcnc-rs274-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-rs274-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-rs274-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-rs274-source-map.sh")
|
||||
PY
|
||||
107
check-linuxcnc-switchkins-remap-source-map.sh
Executable file
107
check-linuxcnc-switchkins-remap-source-map.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties generated switchkins/remap aliases and
|
||||
# config cases to LinuxCNC configs/sim INI REMAP entries, remap_subs
|
||||
# #<kinstype> assignments, and halcmd loadusr parsing sources. It validates
|
||||
# generator/table policy only; it does not add CNC behavior, expand smoke
|
||||
# parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: generated switchkins/remap tables are extracted from' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'src/hal/utils/halcmd_commands.cc do_loadusr_cmd()' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'getopt("+wWin:")' generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'src/hal/utils/halcmd_completion.c lists the common -W/-Wn/-w/-iw forms' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'LinuxCNC TOOL_TABLE source is not listed as tooldata' \
|
||||
generate-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: switchkins/remap table validation derives M428/M429/M430' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'validate_tool_table_source_coverage_only' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
grep -F 'exposes TOOL_TABLE through switchkins API/web bridge' \
|
||||
check-linuxcnc-switchkins-remap-table.sh >/dev/null
|
||||
|
||||
grep -F 'int do_loadusr_cmd(const char *args[])' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F 'getopt(argc,' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F '"+wWin:"' "$linuxcnc_root/src/hal/utils/halcmd_commands.cc" >/dev/null
|
||||
grep -F -- '-Wn' "$linuxcnc_root/src/hal/utils/halcmd_completion.c" >/dev/null
|
||||
|
||||
python3 - "$linuxcnc_root" <<'PY'
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
linuxcnc_root = Path(sys.argv[1])
|
||||
source_map = Path("docs/linuxcnc-switchkins-remap-source-map.md").read_text(encoding="utf-8")
|
||||
table = Path("core/src/linuxcnc_switchkins_remap_table.inc").read_text(encoding="utf-8")
|
||||
cpp_cases = Path("core/tests/linuxcnc_switchkins_remap_config_cases.inc").read_text(encoding="utf-8")
|
||||
json_cases = json.loads(Path("web/public/linuxcnc_switchkins_remap_config_cases.json").read_text(encoding="utf-8"))
|
||||
|
||||
counts = {
|
||||
"core/src/linuxcnc_switchkins_remap_table.inc": len(re.findall(r'^\s*\{"', table, re.M)),
|
||||
"core/tests/linuxcnc_switchkins_remap_config_cases.inc": len(re.findall(r'^\s*\{"', cpp_cases, re.M)),
|
||||
"web/public/linuxcnc_switchkins_remap_config_cases.json": len(json_cases),
|
||||
}
|
||||
for path, count in counts.items():
|
||||
if f"| `{path}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-switchkins-remap-source-map.md count mismatch for {path}")
|
||||
|
||||
remap_sources = [
|
||||
path
|
||||
for path in (linuxcnc_root / "configs/sim").rglob("*remap.ngc")
|
||||
if path.name in {"428remap.ngc", "429remap.ngc", "430remap.ngc"}
|
||||
]
|
||||
remap_ini_re = re.compile(r"REMAP\s*=\s*M(428|429|430)(?:\D|$)", re.I)
|
||||
remap_inis = [
|
||||
path
|
||||
for path in (linuxcnc_root / "configs/sim").rglob("*.ini")
|
||||
if remap_ini_re.search(path.read_text(encoding="utf-8", errors="ignore"))
|
||||
]
|
||||
if f"| LinuxCNC M428/M429/M430 remap sources | {len(remap_sources)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-switchkins-remap-source-map.md remap source count mismatch")
|
||||
if f"| LinuxCNC switchkins REMAP INI sources | {len(remap_inis)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-switchkins-remap-source-map.md REMAP INI source count mismatch")
|
||||
|
||||
required_phrases = [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"`#<kinstype>` assignments",
|
||||
"[EMCIO] TOOL_TABLE` entries are source coverage only",
|
||||
"must not become generated switchkins aliases",
|
||||
"./check-linuxcnc-switchkins-remap-source-map.sh",
|
||||
"./check-linuxcnc-switchkins-remap-table.sh linuxcnc-kinematics-source-files.txt",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(
|
||||
f"docs/linuxcnc-switchkins-remap-source-map.md is missing boundary phrase: {phrase}"
|
||||
)
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-switchkins-remap-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-switchkins-remap-source-map.sh")
|
||||
|
||||
case_fields = {case["field"] for case in json_cases}
|
||||
source_only_field_re = re.compile(r"asset|metadata|tool|tooldata|tool_table|TOOL_TABLE", re.I)
|
||||
bad_fields = [field for field in case_fields if source_only_field_re.search(field)]
|
||||
if bad_fields:
|
||||
raise SystemExit(f"generated switchkins config cases expose source-only fields: {bad_fields}")
|
||||
api_surface_re = re.compile(r'\b(?:asset|metadata|toolData|tooldata|toolTable|tooltable|tool_table|TOOL_TABLE)\b')
|
||||
for api_path in ["web/src/wasm-core.js", "web/src/index.ts", "core/include/cnc_sim_api.h"]:
|
||||
if api_surface_re.search(Path(api_path).read_text(encoding="utf-8")):
|
||||
raise SystemExit(f"{api_path} exposes source-only switchkins inputs through API surface")
|
||||
PY
|
||||
123
check-linuxcnc-switchkins-remap-table-cached.sh
Executable file
123
check-linuxcnc-switchkins-remap-table-cached.sh
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: cached switchkins/remap validation hashes the LinuxCNC
|
||||
# kinematics manifest, referenced configs/remaps, generator script, and bridge
|
||||
# outputs before reusing table-check results.
|
||||
cache_dir=${CNC_SIM_PREFLIGHT_CACHE_DIR:-}
|
||||
check_args=("$@")
|
||||
if [[ "${1:-}" == "--cache-dir" ]]; then
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
echo "missing --cache-dir value" >&2
|
||||
exit 1
|
||||
fi
|
||||
cache_dir=$2
|
||||
shift 2
|
||||
check_args=("$@")
|
||||
fi
|
||||
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-kinematics-source-files.txt}
|
||||
|
||||
if [[ -z "$cache_dir" ]]; then
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$cache_dir" =~ [[:space:]] ]]; then
|
||||
echo "CNC_SIM_PREFLIGHT_CACHE_DIR must not contain whitespace: $cache_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$cache_dir"
|
||||
cache_dir=$(cd "$cache_dir" && pwd)
|
||||
if [[ "$cache_dir" == "/" ]]; then
|
||||
echo "CNC_SIM_PREFLIGHT_CACHE_DIR must not be the filesystem root" >&2
|
||||
exit 1
|
||||
fi
|
||||
exec 8>"$cache_dir/check-linuxcnc-switchkins-remap-table.lock"
|
||||
flock 8
|
||||
|
||||
if [[ ! -d "$linuxcnc_root" || ! -f "$manifest" ]]; then
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
manifest_path=$(cd "$(dirname "$manifest")" && pwd)/$(basename "$manifest")
|
||||
manifest_key=$(printf '%s' "$manifest_path" | sha256sum | awk '{ print $1 }')
|
||||
args_key=$(
|
||||
{
|
||||
printf 'ARGS='
|
||||
printf ' %q' "${check_args[@]}"
|
||||
printf '\n'
|
||||
} | sha256sum | awk '{ print $1 }'
|
||||
)
|
||||
cache_file="$cache_dir/check-linuxcnc-switchkins-remap-table.${manifest_key}.${args_key}.signature"
|
||||
next_signature=$(mktemp "$cache_file.next.XXXXXX")
|
||||
|
||||
write_manifest_source_stats() {
|
||||
local source_path
|
||||
while IFS=: read -r group path note extra; do
|
||||
case "$group" in
|
||||
""|\#*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
[[ -z "${path:-}" ]] && continue
|
||||
source_path="$linuxcnc_root/$path"
|
||||
if [[ ! -f "$source_path" ]]; then
|
||||
return 1
|
||||
fi
|
||||
stat -c 'SOURCE=%n:%s:%y' "$source_path"
|
||||
done < "$manifest_path"
|
||||
}
|
||||
|
||||
write_project_output_hashes() {
|
||||
local project_output
|
||||
for project_output in \
|
||||
core/src/cnc_sim_api.cpp \
|
||||
core/src/linuxcnc_switchkins_remap_table.inc \
|
||||
core/tests/linuxcnc_switchkins_remap_config_cases.inc \
|
||||
web/public/linuxcnc_switchkins_remap_config_cases.json \
|
||||
web/src/index.ts \
|
||||
web/src/wasm-core.js; do
|
||||
[[ -f "$project_output" ]] || return 1
|
||||
sha256sum "$project_output"
|
||||
done
|
||||
}
|
||||
|
||||
if ! {
|
||||
printf 'CACHED_SCRIPT='
|
||||
sha256sum check-linuxcnc-switchkins-remap-table-cached.sh
|
||||
printf 'CHECK_SCRIPT='
|
||||
sha256sum check-linuxcnc-switchkins-remap-table.sh
|
||||
printf 'INPUT_CACHED_SCRIPT='
|
||||
sha256sum check-linuxcnc-inputs-cached.sh
|
||||
printf 'INPUT_CHECK_SCRIPT='
|
||||
sha256sum check-linuxcnc-inputs.sh
|
||||
printf 'GENERATOR_SCRIPT='
|
||||
sha256sum generate-linuxcnc-switchkins-remap-table.sh
|
||||
printf 'LINUXCNC_ROOT=%s\n' "$linuxcnc_root"
|
||||
printf 'ARGS='
|
||||
printf ' %q' "${check_args[@]}"
|
||||
printf '\n'
|
||||
printf 'MANIFEST_PATH=%s\n' "$manifest_path"
|
||||
printf 'MANIFEST='
|
||||
sha256sum "$manifest_path"
|
||||
write_manifest_source_stats
|
||||
printf 'PROJECT_OUTPUTS:\n'
|
||||
write_project_output_hashes
|
||||
} > "$next_signature"; then
|
||||
rm -f "$next_signature"
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table.sh "${check_args[@]}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f "$cache_file" ]] && cmp -s "$cache_file" "$next_signature"; then
|
||||
rm -f "$next_signature"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-switchkins-remap-table.sh "${check_args[@]}"
|
||||
mv "$next_signature" "$cache_file"
|
||||
3080
check-linuxcnc-switchkins-remap-table.sh
Executable file
3080
check-linuxcnc-switchkins-remap-table.sh
Executable file
File diff suppressed because it is too large
Load Diff
333
check-linuxcnc-tooldata-source-map.sh
Executable file
333
check-linuxcnc-tooldata-source-map.sh
Executable file
@@ -0,0 +1,333 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties LinuxCNC tooldata/Submakefile,
|
||||
# src/emc/tooldata sources, native/WASM manifests, and wasm-safe tooldata shims
|
||||
# to the tooldata source map. It validates source coverage only; it does not
|
||||
# add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_nml.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_mmap.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_db.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'TOOL_MMAP_READ_SRCS = emc/tooldata/tool_mmap_read.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'TOOL_WATCH_SRCS = emc/tooldata/tool_watch.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'int main (int argc,char**argv)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'if (tool_mmap_user())' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'idx_last = tooldata_last_index_get();' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'if (tooldata_get(&tdata,idx) != IDX_OK)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_mmap_read.cc" >/dev/null
|
||||
grep -F 'RCS_STAT_CHANNEL *stat = 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'stat = new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "xemc", nmlfile);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'EMC_STAT *emcStatus = static_cast<EMC_STAT*>(stat->get_address());' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F 'emcStatus->io.tool.pocketPrepped' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tool_watch.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'bool tool_mmap_is_random_toolchanger(void)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'ans = hptr->is_random_toolchanger;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_creator(EMC_TOOL_STAT const * ptr,int random_toolchanger)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'static int inited=0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (inited) {' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'inited = 1;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'hptr->is_random_toolchanger = random_toolchanger;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'hptr->last_index = 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_user()' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'fprintf(stderr,"tool_mmap_user(): tool mmap not available\n");' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'return(-1);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'void tool_mmap_close()' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (!tool_mmap_base) { return; }' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tooldata_last_index_get(void)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'tool_mmap_mutex_give(); return -1;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tooldata_find_index_for_tool(int toolno)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (toolno == -1) {tool_mmap_mutex_give(); return -1;}' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'if (!hptr->is_random_toolchanger && toolno == 0)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_nml_register(CANON_TOOL_TABLE *tblptr)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_nml.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_init(char progname_plus_args[]' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F '#define MAX_DB_PROGRAM_ARGS 10' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'char* token = strtok_r(progname_plus_args, " ", &saveptr);' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (child_argc >= MAX_DB_PROGRAM_ARGS)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (access(child_argv[0],X_OK))' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_getall() {' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) {return -1;}' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_notify(tool_notify_t ntype,' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) return 0;' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'int tooldata_read_entry(const char *input_line)' \
|
||||
"$linuxcnc_root/src/emc/tooldata/tooldata_common.cc" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC tooldata source map' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC behavior' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/Submakefile` selects `tooldata_mmap.cc`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F 'Tool table files referenced by switchkins INI files are source coverage only' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/tool_mmap_read.cc` is the mmap tool table reader utility' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`tool_mmap_user()`, `tooldata_last_index_get()`, and `tooldata_get()`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F "single-creator process boundary from" docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F "including after" docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`src/emc/tooldata/tool_watch.cc` is the NML/mmap tool table watcher utility' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
grep -F '`EMC_STAT::io.tool` fields through `RCS_STAT_CHANNEL`' \
|
||||
docs/linuxcnc-tooldata-source-map.md >/dev/null
|
||||
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_common.cc:shared tool table parser/format logic' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_mmap.cc:native mmap implementation; replace for wasm' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_db.cc:external database integration; exclude from wasm core' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'tooldata:src/emc/tooldata/tooldata_nml.cc:NML tool table backend selected by LinuxCNC TOOL_NML_FLAG' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'header:src/emc/tooldata/tooldata.hh:LinuxCNC tooldata declarations used by RS274 and wasm-safe tooldata shims' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/Submakefile:LinuxCNC tooldata build metadata defining mmap and NML backend source selection' \
|
||||
linuxcnc-rs274-source-files.txt >/dev/null
|
||||
grep -F 'core:src/emc/tooldata/tooldata_common.cc:shared tool table parser/format logic linked with wasm-safe mmap backend' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'blocked:src/emc/tooldata/tooldata_mmap.cc:native mmap implementation' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/tooldata_db.cc:source basis for wasm-safe tooldata runtime export shim' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
grep -F 'metadata:src/emc/tooldata/tooldata_nml.cc:source basis for wasm-safe tooldata runtime NML export shim' \
|
||||
linuxcnc-rs274-wasm-source-files.txt >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_mmap.cc provides these' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_created = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_random_toolchanger = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool mmap_creator_called = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tool_mmap_creator(EMC_TOOL_STAT const *ptr, int random_toolchanger)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'Error: tool_mmap_creator already called BYE' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_created = true;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_random_toolchanger = random_toolchanger;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'last_index = 0;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tool_mmap_user(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'tool_mmap_user(): tool mmap not available' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'void tool_mmap_close(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'mmap_created = false;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'bool tool_mmap_is_random_toolchanger(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'return mmap_random_toolchanger;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'int tooldata_last_index_get(void)' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'return -1;' \
|
||||
core/wasm_shims/tooldata/tooldata_mmap_backend.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_nml.cc and tooldata_db.cc' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'constexpr int MAX_DB_PROGRAM_ARGS = 10;' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'strtok_r(progname_plus_args, " ", &saveptr)' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'argc exceeds MAX_DB_PROGRAM_ARGS=%d' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'access(program, X_OK) != 0' \
|
||||
core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'returns 0 when' core/wasm_shims/tooldata/tooldata_runtime_stubs.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_common.cc provides' \
|
||||
core/wasm_shims/tooldata/tooldata_common_probe_main.cc >/dev/null
|
||||
grep -F 'LinuxCNC source basis: src/emc/tooldata/tooldata_mmap.cc, tooldata_nml.cc,' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_notify() returns 0 without side effects while db_live is' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(missing_db_program_with_arg.data(), 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'missing_db_program_with_arg[separator] != 0' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(too_many_db_args, 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tooldata_db_init(non_db_program, 1) != -1' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'tool_mmap_creator(nullptr, 1);' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'WEXITSTATUS(recreate_status) == 0' \
|
||||
core/wasm_shims/tooldata/tooldata_probe_main.cc >/dev/null
|
||||
grep -F 'core/wasm_shims/tooldata/tooldata_mmap_backend.cc' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
grep -F 'core/wasm_shims/tooldata/tooldata_runtime_stubs.cc' docs/linuxcnc-wasm-shims-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: this link probe runs the wasm-safe tooldata shim' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this link probe runs tooldata_common through the' \
|
||||
test-linuxcnc-wasm-tooldata-common-link.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this symbol probe compares the wasm mmap backend shim' \
|
||||
test-linuxcnc-wasm-tooldata-mmap-symbols.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this probe compares wasm-safe tooldata runtime stubs' \
|
||||
test-linuxcnc-wasm-tooldata-runtime-symbols.sh >/dev/null
|
||||
grep -F '!!!!db_init: argc exceeds MAX_DB_PROGRAM_ARGS=10' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'not executable' test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'Error: tool_mmap_creator already called BYE' \
|
||||
test-linuxcnc-wasm-tooldata-link.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe" ./test-linuxcnc-wasm-tooldata-link.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_common link probe" ./test-linuxcnc-wasm-tooldata-common-link.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_mmap symbol probe" ./test-linuxcnc-wasm-tooldata-mmap-symbols.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
grep -F 'run_parallel_wasm_probe "LinuxCNC wasm tooldata runtime symbol probe" ./test-linuxcnc-wasm-tooldata-runtime-symbols.sh' \
|
||||
build-wasm.sh >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
doc = Path("docs/linuxcnc-tooldata-source-map.md").read_text(encoding="utf-8")
|
||||
build_wasm_lines = Path("build-wasm.sh").read_text(encoding="utf-8").splitlines()
|
||||
native_tooldata = subprocess.check_output(
|
||||
["./list-linuxcnc-source-manifest-sources.sh", "linuxcnc-rs274-source-files.txt", "tooldata"],
|
||||
text=True,
|
||||
).splitlines()
|
||||
expected_native = [
|
||||
"src/emc/tooldata/tooldata_common.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
"src/emc/tooldata/tooldata_db.cc",
|
||||
"src/emc/tooldata/tooldata_nml.cc",
|
||||
"src/emc/tooldata/tool_mmap_read.cc",
|
||||
"src/emc/tooldata/tool_watch.cc",
|
||||
]
|
||||
for source in expected_native:
|
||||
if source not in native_tooldata:
|
||||
raise SystemExit(f"native RS274 manifest missing LinuxCNC tooldata source: {source}")
|
||||
|
||||
kin_tooldata = subprocess.check_output(
|
||||
["./list-linuxcnc-kinematics-manifest-sources.sh", "linuxcnc-kinematics-source-files.txt", "tooldata"],
|
||||
text=True,
|
||||
).splitlines()
|
||||
if len([source for source in kin_tooldata if source.endswith(".tbl")]) != 10:
|
||||
raise SystemExit("kinematics manifest must track exactly 10 LinuxCNC TOOL_TABLE sources")
|
||||
|
||||
positions = {}
|
||||
for index, line in enumerate(build_wasm_lines, start=1):
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata shim link probe"' in line:
|
||||
positions["tooldata_link"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_common link probe"' in line:
|
||||
positions["tooldata_common"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata_mmap symbol probe"' in line:
|
||||
positions["tooldata_mmap"] = index
|
||||
if 'run_parallel_wasm_probe "LinuxCNC wasm tooldata runtime symbol probe"' in line:
|
||||
positions["tooldata_runtime"] = index
|
||||
if "cp build/wasm/cnc_sim.js web/public/cnc_sim.js" in line:
|
||||
positions["copy_js"] = index
|
||||
if "cp build/wasm/cnc_sim.wasm web/public/cnc_sim.wasm" in line:
|
||||
positions["copy_wasm"] = index
|
||||
|
||||
missing = [
|
||||
name for name in (
|
||||
"tooldata_link",
|
||||
"tooldata_common",
|
||||
"tooldata_mmap",
|
||||
"tooldata_runtime",
|
||||
"copy_js",
|
||||
"copy_wasm",
|
||||
)
|
||||
if name not in positions
|
||||
]
|
||||
if missing:
|
||||
raise SystemExit(f"build-wasm.sh missing tooldata/copy ordering anchor: {', '.join(missing)}")
|
||||
for probe in ("tooldata_link", "tooldata_common", "tooldata_mmap", "tooldata_runtime"):
|
||||
if not (positions[probe] < positions["copy_js"] and positions[probe] < positions["copy_wasm"]):
|
||||
raise SystemExit("build-wasm.sh must run all tooldata link/symbol probes before copying browser artifacts")
|
||||
|
||||
for path in [
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
"core/wasm_shims/tooldata/tooldata_runtime_stubs.cc",
|
||||
"test-linuxcnc-wasm-tooldata-link.sh",
|
||||
"test-linuxcnc-wasm-tooldata-common-link.sh",
|
||||
"test-linuxcnc-wasm-tooldata-mmap-symbols.sh",
|
||||
"test-linuxcnc-wasm-tooldata-runtime-symbols.sh",
|
||||
]:
|
||||
if path not in doc:
|
||||
raise SystemExit(f"docs/linuxcnc-tooldata-source-map.md missing coverage path: {path}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"source coverage only",
|
||||
"must not become browser API fields",
|
||||
"WASM-safe tooldata shims must preserve the LinuxCNC export surface",
|
||||
"must keep external DB services unavailable",
|
||||
"must not fork, exec, poll",
|
||||
"MAX_DB_PROGRAM_ARGS=10",
|
||||
"`strtok_r()` argument splitting",
|
||||
"access(..., X_OK)",
|
||||
"mmap tool table reader utility",
|
||||
"NML/mmap tool table watcher utility",
|
||||
"mmap creator/user/close lifecycle",
|
||||
"random-toolchanger flag",
|
||||
"last-index unavailable return",
|
||||
"in-memory replacement for native mmap",
|
||||
"inactive-DB return values",
|
||||
"./check-linuxcnc-tooldata-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in doc:
|
||||
raise SystemExit(f"docs/linuxcnc-tooldata-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-tooldata-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-tooldata-source-map.sh")
|
||||
PY
|
||||
194
check-linuxcnc-wasm-blockers-source-map.sh
Executable file
194
check-linuxcnc-wasm-blockers-source-map.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the documented WASM blocker map to
|
||||
# LinuxCNC RS274/Python/remap/tooldata sources, the rs274 WASM manifest, and
|
||||
# wasm-safe shim replacement sources. It validates source coverage only; it
|
||||
# does not add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest"
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: this blocker scan is constrained to the RS274/WASM' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'blocked replacement is not in wasm shim build set' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'shim_source_output=$(./list-linuxcnc-wasm-safe-shims.sh)' \
|
||||
analyze-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guardrail locks the blocker categories reported' \
|
||||
test-linuxcnc-wasm-blockers.sh >/dev/null
|
||||
grep -F 'Cache wasm blocker analyzer output' docs/linuxcnc-source-policy.md >/dev/null
|
||||
|
||||
grep -F '#include <Python.h>' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyInit_gcode' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '#include <boost/python/module.hpp>' "$linuxcnc_root/src/emc/rs274ngc/interpmodule.cc" >/dev/null
|
||||
grep -F '#include "pythonplugin/python_plugin.hh"' "$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'dlopen' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'opendir(direct)' "$linuxcnc_root/src/emc/rs274ngc/interp_o_word.cc" >/dev/null
|
||||
grep -F 'readdir(aDir)' "$linuxcnc_root/src/emc/rs274ngc/interp_o_word.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_mmap_creator(' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
|
||||
python3 - "$linuxcnc_root" "$manifest" <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
linuxcnc_root = Path(sys.argv[1])
|
||||
manifest = Path(sys.argv[2])
|
||||
source_map = Path("docs/linuxcnc-wasm-blockers-source-map.md").read_text(encoding="utf-8")
|
||||
manifest_lines = [
|
||||
line for line in manifest.read_text(encoding="utf-8").splitlines()
|
||||
if line and not line.startswith("#")
|
||||
]
|
||||
manifest_counts = {"core": 0, "blocked": 0, "header": 0, "blocked-header": 0, "metadata": 0}
|
||||
for line in manifest_lines:
|
||||
group = line.split(":", 1)[0]
|
||||
if group not in manifest_counts:
|
||||
raise SystemExit(f"unexpected WASM manifest group in blocker source map guard: {group}")
|
||||
manifest_counts[group] += 1
|
||||
for group, count in manifest_counts.items():
|
||||
if f"| `{group}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md count mismatch for {group}")
|
||||
|
||||
output = subprocess.check_output(
|
||||
["./analyze-linuxcnc-wasm-blockers.sh", str(manifest)],
|
||||
text=True,
|
||||
env={"LINUXCNC_ROOT": str(linuxcnc_root)},
|
||||
)
|
||||
sections = {}
|
||||
current = None
|
||||
for line in output.splitlines():
|
||||
if line.startswith("[") and line.endswith("]"):
|
||||
current = line[1:-1]
|
||||
sections[current] = []
|
||||
elif current and line:
|
||||
sections[current].append(line)
|
||||
|
||||
expected_counts = {
|
||||
"manifest-core": "core=26",
|
||||
"manifest-blocked": "blocked=9",
|
||||
"python": 8,
|
||||
"python-compile-covered": 8,
|
||||
"tooldata": 1,
|
||||
"native-backend": 1,
|
||||
"native-fs": 1,
|
||||
"blocked-replacements": 9,
|
||||
"core-python-shimmed": 6,
|
||||
"core-dlopen-shimmed": 1,
|
||||
"core-tooldata-shimmed": 1,
|
||||
"core-tooldata-users-shimmed": 2,
|
||||
"core-native-fs-shimmed": 16,
|
||||
}
|
||||
manifest_section = sections.get("manifest", [])
|
||||
if expected_counts["manifest-core"] not in manifest_section:
|
||||
raise SystemExit("WASM blocker analyzer core count changed")
|
||||
if expected_counts["manifest-blocked"] not in manifest_section:
|
||||
raise SystemExit("WASM blocker analyzer blocked count changed")
|
||||
for section, count in expected_counts.items():
|
||||
if section.startswith("manifest-"):
|
||||
continue
|
||||
entries = [entry for entry in sections.get(section, []) if entry != "(none)"]
|
||||
if len(entries) != count:
|
||||
raise SystemExit(f"WASM blocker analyzer section {section} count changed: {len(entries)}")
|
||||
if f"| `{section}` | {count} |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md analyzer count mismatch for {section}")
|
||||
if sections.get("dlopen") != ["(none)"]:
|
||||
raise SystemExit("blocked dlopen section is no longer empty")
|
||||
if sections.get("tooldata-users") != ["(none)"]:
|
||||
raise SystemExit("blocked tooldata-users section is no longer empty")
|
||||
if sections.get("python") != sections.get("python-compile-covered"):
|
||||
raise SystemExit("blocked Python sources are no longer fully compile-covered by the inert Python C API probe")
|
||||
|
||||
shim_paths = set(Path(line).as_posix() for line in subprocess.check_output(
|
||||
["./list-linuxcnc-wasm-safe-shims.sh"],
|
||||
text=True,
|
||||
).splitlines() if line)
|
||||
required_tracked_entries = [
|
||||
"src/emc/rs274ngc/interp_base.cc -> core/wasm_shims/dlfcn.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/rs274ngc/interpmodule.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
"src/emc/rs274ngc/interp_base.cc",
|
||||
"src/emc/rs274ngc/interp_o_word.cc",
|
||||
"src/emc/rs274ngc/rs274ngc_pre.cc",
|
||||
]
|
||||
required_replacements = [
|
||||
"src/emc/rs274ngc/canonmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/interpmodule.cc -> core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"src/emc/rs274ngc/pyarrays.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyblock.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyemctypes.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyinterp1.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/rs274ngc/pyparamclass.cc -> core/wasm_shims/python_c_api_shim.cc",
|
||||
"src/emc/tooldata/tooldata_mmap.cc -> core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
]
|
||||
for entry in required_tracked_entries:
|
||||
if " -> " in entry:
|
||||
source, shim = entry.split(" -> ", 1)
|
||||
if source not in sections.get("core-dlopen-shimmed", []):
|
||||
raise SystemExit(f"WASM blocker analyzer output missing core dlopen shimmed source: {source}")
|
||||
if shim not in shim_paths:
|
||||
raise SystemExit(f"WASM blocker analyzer core dlopen shim is absent from wasm-safe shim set: {shim}")
|
||||
elif entry not in output:
|
||||
raise SystemExit(f"WASM blocker analyzer output missing required entry: {entry}")
|
||||
if entry not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing required entry: {entry}")
|
||||
replacement_entries = [entry for entry in sections.get("blocked-replacements", []) if entry != "(none)"]
|
||||
if replacement_entries != required_replacements:
|
||||
raise SystemExit(f"WASM blocker replacement set changed: {replacement_entries}")
|
||||
if "Required replacement set:" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-wasm-blockers-source-map.md must document the complete replacement set")
|
||||
for entry in required_replacements:
|
||||
if entry not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing required replacement: {entry}")
|
||||
|
||||
for replacement in re.findall(r"-> (core/wasm_shims/[^\s]+)", output):
|
||||
if replacement not in shim_paths:
|
||||
raise SystemExit(f"blocked replacement is absent from wasm-safe shim set: {replacement}")
|
||||
for phrase in [
|
||||
"does not add CNC behavior",
|
||||
"must not become smoke parser behavior",
|
||||
"blocked `dlopen` and blocked tooldata-users remain empty",
|
||||
'parameter-file replacement through `filename + ".new"`',
|
||||
"O-word lookup and parameter-file replacement",
|
||||
"Python/Boost.Python remap paths remain tracked blockers",
|
||||
"Python/Boost.Python blockers are compile-covered by the inert Python C API probe",
|
||||
"./check-linuxcnc-wasm-blockers-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-blockers-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-blockers-source-map.sh")
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "CNC_SIM_WASM_BLOCKERS_SELF_CHECKS=1" not in text:
|
||||
raise SystemExit(f"{entry} must run wasm blocker analyzer self-checks")
|
||||
PY
|
||||
499
check-linuxcnc-wasm-shims-source-map.sh
Executable file
499
check-linuxcnc-wasm-shims-source-map.sh
Executable file
@@ -0,0 +1,499 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the documented wasm-safe shim map to
|
||||
# the linuxcnc_wasm_safe_probe_shims CMake set, the RS274/WASM source manifest,
|
||||
# and the LinuxCNC sources each shim cites. It validates source coverage only;
|
||||
# it does not add CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
manifest=${1:-linuxcnc-rs274-wasm-source-files.txt}
|
||||
|
||||
LINUXCNC_ROOT="$linuxcnc_root" ./check-linuxcnc-inputs-cached.sh "$manifest"
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'LinuxCNC source basis: wasm-safe shim probe sources are limited to the' \
|
||||
list-linuxcnc-wasm-safe-shims.sh >/dev/null
|
||||
grep -F 'set(linuxcnc_wasm_safe_probe_shims' core/CMakeLists.txt >/dev/null
|
||||
grep -F 'LinuxCNC source basis: this guard ties the documented WASM blocker map' \
|
||||
check-linuxcnc-wasm-blockers-source-map.sh >/dev/null
|
||||
|
||||
grep -F 'dlopen(NULL, RTLD_GLOBAL);' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'interp_lib = dlopen(interp_path, RTLD_NOW);' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'Constructor constructor = (Constructor)dlsym(interp_lib, "makeInterp");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F 'dlerror()' "$linuxcnc_root/src/emc/rs274ngc/interp_base.cc" >/dev/null
|
||||
grep -F '#include "libintl.h"' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F '#define _(s) gettext(s)' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'CHKS((!_readers[(int)' "$linuxcnc_root/src/emc/rs274ngc/interp_internal.cc" >/dev/null
|
||||
grep -F 'Cannot use polar coordinate on a machine lacking X or Y axes' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.cc" >/dev/null
|
||||
grep -F 'int _task = 0;' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'int _task = 1;' "$linuxcnc_root/src/emc/task/emctaskmain.cc" >/dev/null
|
||||
grep -F '{ "interpreter", PyInit_interpreter },' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '{ "emccanon", PyInit_emccanon },' "$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'struct _inittab builtin_modules[]' "$linuxcnc_root/src/emc/task/taskclass.cc" >/dev/null
|
||||
grep -F 'int Interp::fetch_hal_param(' "$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_pin_value_by_name(hal_name, &type, &ptr, &conn)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_signal_value_by_name(hal_name, &type, &ptr, &conn)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'hal_get_param_value_by_name(hal_name, &type, &ptr)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_namedparams.cc" >/dev/null
|
||||
grep -F 'HAL_TYPE_UNINITIALIZED = 0,' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_pin_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_signal_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'extern int hal_get_param_value_by_name(' "$linuxcnc_root/include/hal.h" >/dev/null
|
||||
grep -F 'int hal_get_pin_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'int hal_get_signal_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'int hal_get_param_value_by_name(' "$linuxcnc_root/src/hal/hal_lib.c" >/dev/null
|
||||
grep -F 'wordexp(basename, &exp_result, 0);' "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordexp(settings->program_prefix, &exp_result, 0);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordexp(settings->subroutines[dct], &exp_result, 0);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'wordfree(&exp_result);' "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F '#include "nml_intf/emc_nml.hh"' "$linuxcnc_root/src/emc/sai/dummyemcstat.cc" >/dev/null
|
||||
grep -F 'EMC_STAT *emcStatus = new EMC_STAT;' "$linuxcnc_root/src/emc/sai/dummyemcstat.cc" >/dev/null
|
||||
grep -F 'int NMLmsg::automatically_clear = 1;' \
|
||||
"$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'NMLmsg::NMLmsg' "$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'void NMLmsg::clear()' "$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'memset((void *) this, 0, size);' \
|
||||
"$linuxcnc_root/src/libnml/nml/nmlmsg.cc" >/dev/null
|
||||
grep -F 'RCS_STAT_MSG::RCS_STAT_MSG' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'command_type = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'echo_serial_number = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'status = RCS_STATUS::UNINITIALIZED;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F '_state = -1;' "$linuxcnc_root/src/libnml/nml/stat_msg.cc" >/dev/null
|
||||
grep -F 'extern int set_print_rcs_error_info(const char *file, int line);' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F 'extern int print_rcs_error_new(const char *_fmt, ...)' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F '#define rcs_print_error set_print_rcs_error_info( __FILE__, __LINE__); print_rcs_error_new' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.hh" >/dev/null
|
||||
grep -F 'int set_print_rcs_error_info(const char *file, int line)' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'print_rcs_error_new' "$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'retval = rcs_vprint(_fmt, args, 1);' \
|
||||
"$linuxcnc_root/src/libnml/rcs/rcs_print.cc" >/dev/null
|
||||
grep -F 'extern int rtapi_snprintf(char *buf, unsigned long int size,' \
|
||||
"$linuxcnc_root/src/rtapi/rtapi.h" >/dev/null
|
||||
grep -F 'extern int rtapi_vsnprintf(char *buf, unsigned long size,' \
|
||||
"$linuxcnc_root/src/rtapi/rtapi.h" >/dev/null
|
||||
grep -F 'int rtapi_snprintf(char *buffer, unsigned long int size, const char *msg, ...) {' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'result = vsnprintf(buffer, size, msg, args);' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'int rtapi_vsnprintf(char *buffer, unsigned long int size, const char *fmt,' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'return vsnprintf(buffer, size, fmt, args);' \
|
||||
"$linuxcnc_root/src/rtapi/uspace_common.h" >/dev/null
|
||||
grep -F 'class PythonPlugin' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_PYTHON_NOT_INITIALIZED = -12,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_BAD_PATH = -5,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_INITTAB_FAILED = -7 ,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION_DURING_PATH_PREPEND = -9,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION_DURING_PATH_APPEND = -10,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_NO_CALLABLE = 1,' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PLUGIN_EXCEPTION = 2' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.hh" >/dev/null
|
||||
grep -F 'PythonPlugin::instantiate' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'for (int i = 0; inittab[i].name != NULL; i++) {' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (module == NULL) {' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_INITTAB_FAILED;' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (status < PLUGIN_OK)' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (auto inistring = inifile.findString("TOPLEVEL", section)) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'if (realpath(toplevel, real_path) == NULL) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_BAD_PATH;' "$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'while (auto inistring = inifile.findString(n, "PATH_PREPEND", "PYTHON")) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'while (auto inistring = inifile.findString(n, "PATH_APPEND", "PYTHON")) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_EXCEPTION_DURING_PATH_PREPEND;' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'status = PLUGIN_EXCEPTION_DURING_PATH_APPEND;' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'int IniFile::tildeExpand(const std::string &path, std::string &result)' \
|
||||
"$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F "if(!home)" "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'IniFile::trim(sect);' "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'Section header has trailing content, ignored' "$linuxcnc_root/src/emc/ini/inifile.cc" >/dev/null
|
||||
grep -F 'retval = bp::exec_file(cmd, main_namespace, main_namespace);' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'retval = bp::exec(cmd, main_namespace, main_namespace);' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'PyObject *rv = PyObject_Call(function.ptr(), tupleargs.ptr(), kwargs.ptr());' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F 'PyErr_Fetch(&exc,&val,&tb);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'PyErr_NormalizeException(&exc,&val,&tb);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_python.cc" >/dev/null
|
||||
grep -F 'if (Py_IsInitialized()) {' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/python_plugin.cc" >/dev/null
|
||||
grep -F '#define callmethod(o, m, f, ...) PyObject_CallMethod((o), (char*)(m), (char*)(f), ## __VA_ARGS__)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject *result = PyObject_GetAttrString(callback, "parameter_file");' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyErr_Format(PyExc_TypeError,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'return Py_BuildValue("[ddd][ddd][ddd][ddd]",' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject *m = PyModule_Create(&gcode_moduledef);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyType_Ready(&LineCodeType);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyModule_AddObject(m, "linecode", (PyObject*)&LineCodeType);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F 'PyObject_SetAttrString(m, "MAX_ERROR", PyLong_FromLong(maxerror));' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/gcodemodule.cc" >/dev/null
|
||||
grep -F '#define TOOL_MMAP_FILENAME ".tool.mmap"' "$linuxcnc_root/src/emc/tooldata/tooldata_mmap.cc" >/dev/null
|
||||
grep -F 'int tool_nml_register(CANON_TOOL_TABLE *tblptr)' "$linuxcnc_root/src/emc/tooldata/tooldata_nml.cc" >/dev/null
|
||||
grep -F 'int tooldata_db_init(char progname_plus_args[]' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) {return -1;}' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
grep -F 'if (!db_live) return 0;' "$linuxcnc_root/src/emc/tooldata/tooldata_db.cc" >/dev/null
|
||||
|
||||
python3 - "$manifest" <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
manifest = Path(sys.argv[1])
|
||||
source_map = Path("docs/linuxcnc-wasm-shims-source-map.md").read_text(encoding="utf-8")
|
||||
manifest_text = manifest.read_text(encoding="utf-8")
|
||||
shim_paths = [
|
||||
line for line in subprocess.check_output(["./list-linuxcnc-wasm-safe-shims.sh"], text=True).splitlines()
|
||||
if line
|
||||
]
|
||||
if len(shim_paths) != 11:
|
||||
raise SystemExit(f"expected 11 wasm-safe CMake shim sources, found {len(shim_paths)}")
|
||||
if f"| CMake `linuxcnc_wasm_safe_probe_shims` sources | {len(shim_paths)} |" not in source_map:
|
||||
raise SystemExit("docs/linuxcnc-wasm-shims-source-map.md shim count mismatch")
|
||||
|
||||
expected_shims = {
|
||||
"core/wasm_shims/dlfcn.cc": ["src/emc/rs274ngc/interp_base.cc"],
|
||||
"core/wasm_shims/emc_status_shim.cc": ["src/emc/sai/dummyemcstat.cc"],
|
||||
"core/wasm_shims/gettext_shim.cc": ["src/emc/rs274ngc/interp_internal.hh"],
|
||||
"core/wasm_shims/linuxcnc_runtime_shim.cc": [
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/task/emctaskmain.cc",
|
||||
"src/emc/task/taskclass.cc",
|
||||
"src/emc/rs274ngc/interp_namedparams.cc",
|
||||
"include/hal.h",
|
||||
"src/hal/hal_lib.c",
|
||||
"src/emc/rs274ngc/rs274ngc_pre.cc",
|
||||
],
|
||||
"core/wasm_shims/nml_status_shim.cc": [
|
||||
"src/libnml/nml/nmlmsg.cc",
|
||||
"src/libnml/nml/stat_msg.cc",
|
||||
],
|
||||
"core/wasm_shims/python_c_api_shim.cc": [
|
||||
"src/emc/rs274ngc/interp_python.cc",
|
||||
"src/emc/rs274ngc/interp_namedparams.cc",
|
||||
"src/emc/rs274ngc/gcodemodule.cc",
|
||||
"src/emc/pythonplugin/python_plugin.cc",
|
||||
],
|
||||
"core/wasm_shims/rcs_print_shim.cc": [
|
||||
"src/libnml/rcs/rcs_print.cc",
|
||||
"src/libnml/rcs/rcs_print.hh",
|
||||
],
|
||||
"core/wasm_shims/rtapi_compat.cc": [
|
||||
"src/rtapi/uspace_common.h",
|
||||
"src/rtapi/rtapi.h",
|
||||
],
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc": [
|
||||
"src/emc/tooldata/tooldata_mmap.cc",
|
||||
],
|
||||
"core/wasm_shims/tooldata/tooldata_runtime_stubs.cc": [
|
||||
"src/emc/tooldata/tooldata_nml.cc",
|
||||
"src/emc/tooldata/tooldata_db.cc",
|
||||
],
|
||||
"core/wasm_shims/pythonplugin/python_plugin.cc": [
|
||||
"src/emc/pythonplugin/python_plugin.cc",
|
||||
"src/emc/pythonplugin/python_plugin.hh",
|
||||
"src/emc/ini/inifile.cc",
|
||||
],
|
||||
}
|
||||
if shim_paths != list(expected_shims):
|
||||
raise SystemExit("wasm-safe shim CMake order no longer matches docs/linuxcnc-wasm-shims-source-map.md")
|
||||
|
||||
for shim_path, linuxcnc_sources in expected_shims.items():
|
||||
shim_text = Path(shim_path).read_text(encoding="utf-8")
|
||||
if "LinuxCNC source basis:" not in shim_text:
|
||||
raise SystemExit(f"{shim_path} is missing a LinuxCNC source basis comment")
|
||||
if f"| `{shim_path}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing shim row: {shim_path}")
|
||||
for source in linuxcnc_sources:
|
||||
if source not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing source {source} for {shim_path}")
|
||||
if source not in manifest_text:
|
||||
raise SystemExit(f"{source} is not tracked in {manifest}")
|
||||
|
||||
runtime_shim = Path("core/wasm_shims/linuxcnc_runtime_shim.cc").read_text(encoding="utf-8")
|
||||
runtime_probe = Path("core/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc").read_text(encoding="utf-8")
|
||||
dlfcn_shim = Path("core/wasm_shims/dlfcn.cc").read_text(encoding="utf-8")
|
||||
dlfcn_header = Path("core/wasm_shims/dlfcn.h").read_text(encoding="utf-8")
|
||||
emc_status_shim = Path("core/wasm_shims/emc_status_shim.cc").read_text(encoding="utf-8")
|
||||
gettext_shim = Path("core/wasm_shims/gettext_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"#define RTLD_GLOBAL 0x00100",
|
||||
"#define RTLD_NOW 0x00002",
|
||||
"void *dlopen(const char *filename, int flags);",
|
||||
"void *dlsym(void *handle, const char *symbol);",
|
||||
"char *dlerror(void);",
|
||||
"int dlclose(void *handle);",
|
||||
]:
|
||||
if needle not in dlfcn_header:
|
||||
raise SystemExit(f"dlfcn shim header missing LinuxCNC loader boundary: {needle}")
|
||||
for needle in [
|
||||
"dynamic loading is unavailable in wasm-safe probe",
|
||||
"void *dlopen(const char *, int)",
|
||||
"return nullptr;",
|
||||
"void *dlsym(void *, const char *)",
|
||||
"char *dlerror(void)",
|
||||
"return last_error;",
|
||||
"int dlclose(void *)",
|
||||
"return 0;",
|
||||
]:
|
||||
if needle not in dlfcn_shim:
|
||||
raise SystemExit(f"dlfcn shim missing unavailable-loader boundary: {needle}")
|
||||
for needle in [
|
||||
'#include "nml_intf/emc_nml.hh"',
|
||||
"EMC_STAT *emcStatus = new EMC_STAT;",
|
||||
]:
|
||||
if needle not in emc_status_shim:
|
||||
raise SystemExit(f"EMC status shim missing detached LinuxCNC status singleton: {needle}")
|
||||
for needle in [
|
||||
"extern \"C\" char *gettext(const char *msgid)",
|
||||
"return const_cast<char *>(msgid ? msgid : \"\");",
|
||||
]:
|
||||
if needle not in gettext_shim:
|
||||
raise SystemExit(f"gettext shim missing diagnostic passthrough boundary: {needle}")
|
||||
nml_status_shim = Path("core/wasm_shims/nml_status_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"int NMLmsg::automatically_clear = 1;",
|
||||
"void NMLmsg::clear()",
|
||||
"std::memset(static_cast<void *>(this), 0, static_cast<size_t>(size));",
|
||||
"command_type = -1;",
|
||||
"echo_serial_number = -1;",
|
||||
"status = RCS_STATUS::UNINITIALIZED;",
|
||||
"_state = -1;",
|
||||
]:
|
||||
if needle not in nml_status_shim:
|
||||
raise SystemExit(f"NML status shim missing LinuxCNC constructor boundary: {needle}")
|
||||
for needle in [
|
||||
"int _task = 0;",
|
||||
'extern "C" PyObject *PyInit_interpreter(void)',
|
||||
'extern "C" PyObject *PyInit_emccanon(void)',
|
||||
'extern "C" PyObject *PyInit_gcode(void)',
|
||||
"return nullptr;",
|
||||
'struct _inittab builtin_modules[] = {',
|
||||
'{"interpreter", PyInit_interpreter}',
|
||||
'{"emccanon", PyInit_emccanon}',
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing preview/builtin module boundary: {needle}")
|
||||
for needle in [
|
||||
"std::string expand_home_directory(const char *words)",
|
||||
"std::string expand_environment_variables(const std::string &words)",
|
||||
"extern \"C\" int wordexp(const char *words, wordexp_t *pwordexp, int)",
|
||||
"return WRDE_BADVAL;",
|
||||
"return WRDE_NOSPACE;",
|
||||
"pwordexp->we_wordc = 1;",
|
||||
"pwordexp->we_offs = 0;",
|
||||
"extern \"C\" void wordfree(wordexp_t *pwordexp)",
|
||||
"pwordexp->we_wordc = 0;",
|
||||
"pwordexp->we_wordv = nullptr;",
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing limited wordexp boundary: {needle}")
|
||||
for needle in [
|
||||
'extern "C" int hal_get_pin_value_by_name',
|
||||
'extern "C" int hal_get_signal_value_by_name',
|
||||
'extern "C" int hal_get_param_value_by_name',
|
||||
"*type = HAL_TYPE_UNINITIALIZED;",
|
||||
"*data = nullptr;",
|
||||
"return -1;",
|
||||
]:
|
||||
if needle not in runtime_shim:
|
||||
raise SystemExit(f"linuxcnc runtime shim missing HAL unavailable boundary: {needle}")
|
||||
for needle in [
|
||||
"bool hal_lookup_is_unavailable()",
|
||||
'hal_get_pin_value_by_name("cnc-sim.missing-pin", &type, &data, &connected) != -1',
|
||||
'hal_get_signal_value_by_name("cnc-sim.missing-signal", &type, &data, &has_writers) != -1',
|
||||
'hal_get_param_value_by_name("cnc-sim.missing-param", &type, &data) != -1',
|
||||
"type != HAL_TYPE_UNINITIALIZED",
|
||||
"data != nullptr",
|
||||
]:
|
||||
if needle not in runtime_probe:
|
||||
raise SystemExit(f"runtime probe missing HAL unavailable assertion: {needle}")
|
||||
|
||||
python_plugin_shim = Path("core/wasm_shims/pythonplugin/python_plugin.cc").read_text(encoding="utf-8")
|
||||
python_plugin_probe = Path("core/wasm_shims/pythonplugin/python_plugin_probe_main.cc").read_text(encoding="utf-8")
|
||||
python_plugin_inittab_probe = Path("core/wasm_shims/pythonplugin/python_plugin_inittab_probe_main.cc").read_text(encoding="utf-8")
|
||||
python_c_api_shim = Path("core/wasm_shims/python_c_api_shim.cc").read_text(encoding="utf-8")
|
||||
for forbidden in [
|
||||
"bp::exec(",
|
||||
"bp::exec_file(",
|
||||
"PyObject_Call(",
|
||||
]:
|
||||
if forbidden in python_plugin_shim:
|
||||
raise SystemExit(f"PythonPlugin wasm shim must not execute Python: {forbidden}")
|
||||
for needle in [
|
||||
"python disabled in wasm-safe probe",
|
||||
'find_ini_value(iniFilename, section, "TOPLEVEL", toplevel)',
|
||||
"realpath(toplevel.c_str(), resolved_path) == nullptr",
|
||||
"status = PLUGIN_BAD_PATH;",
|
||||
"status = PLUGIN_INITTAB_FAILED;",
|
||||
"failed to initialize built-in module",
|
||||
"read_ini_section(text, section_name)",
|
||||
"section_name = trim_ini_value(text.substr(1, close - 1));",
|
||||
'check_python_path_entries(iniFilename,',
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_PREPEND",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_APPEND",
|
||||
"tilde_expand_path(entry, expanded)",
|
||||
"status = PLUGIN_PYTHON_NOT_INITIALIZED;",
|
||||
"return PLUGIN_NO_CALLABLE;",
|
||||
"status = PLUGIN_EXCEPTION;",
|
||||
"if (status < PLUGIN_OK)",
|
||||
]:
|
||||
if needle not in python_plugin_shim:
|
||||
raise SystemExit(f"PythonPlugin wasm shim missing disabled-python boundary: {needle}")
|
||||
for needle in [
|
||||
"PythonPlugin::PythonPlugin(struct _inittab*) reports PLUGIN_INITTAB_FAILED",
|
||||
"PythonPlugin *plugin = PythonPlugin::instantiate(bad_modules);",
|
||||
"plugin != nullptr",
|
||||
"python_plugin->plugin_status() != PLUGIN_INITTAB_FAILED",
|
||||
"python_plugin->usable()",
|
||||
'python_plugin->last_errmsg() != "failed to initialize built-in module"',
|
||||
]:
|
||||
if needle not in python_plugin_inittab_probe:
|
||||
raise SystemExit(f"PythonPlugin inittab probe missing first-caller status assertion: {needle}")
|
||||
for needle in [
|
||||
"[ PYTHON ] ; section comment",
|
||||
"PLUGIN_NO_SECTION",
|
||||
"PLUGIN_BAD_INIFILE",
|
||||
"PLUGIN_BAD_PATH",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_PREPEND",
|
||||
"PLUGIN_EXCEPTION_DURING_PATH_APPEND",
|
||||
"PLUGIN_PYTHON_NOT_INITIALIZED",
|
||||
"PLUGIN_NO_CALLABLE",
|
||||
"PLUGIN_EXCEPTION",
|
||||
"handle_pyerror().empty()",
|
||||
]:
|
||||
if needle not in python_plugin_probe:
|
||||
raise SystemExit(f"PythonPlugin probe missing disabled-python status assertion: {needle}")
|
||||
for needle in [
|
||||
"static PyTypeObject none_type = {\"NoneType\"};",
|
||||
"static PyObject none_object = {&none_type};",
|
||||
"PyObject *_Py_NoneStructPtr = &none_object;",
|
||||
"int Py_IsInitialized(void)",
|
||||
"return 1;",
|
||||
"PyObject *PyErr_Occurred(void)",
|
||||
"return nullptr;",
|
||||
"void PyErr_Fetch(PyObject **exc, PyObject **val, PyObject **tb)",
|
||||
"*exc = nullptr;",
|
||||
"*val = nullptr;",
|
||||
"*tb = nullptr;",
|
||||
"int PyCallable_Check(PyObject *)",
|
||||
"return 0;",
|
||||
"PyObject *PyObject_CallMethod(PyObject *, char *, char *, ...)",
|
||||
"PyObject *PyObject_GetAttrString(PyObject *, const char *)",
|
||||
"return &none_object;",
|
||||
"PyObject *Py_BuildValue(const char *, ...)",
|
||||
"PyObject *PyModule_Create(PyModuleDef *)",
|
||||
"int PyModule_AddObject(PyObject *, const char *, PyObject *)",
|
||||
"int PyType_Ready(PyTypeObject *)",
|
||||
"void *PyObject_NewShim(std::size_t size, PyTypeObject *type)",
|
||||
"std::calloc(1, size)",
|
||||
]:
|
||||
if needle not in python_c_api_shim:
|
||||
raise SystemExit(f"Python C API shim missing symbol boundary: {needle}")
|
||||
|
||||
rcs_print_shim = Path("core/wasm_shims/rcs_print_shim.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"set_print_rcs_error_info",
|
||||
"print_rcs_error_new",
|
||||
"std::vfprintf(stderr, format, args)",
|
||||
]:
|
||||
if needle not in rcs_print_shim:
|
||||
raise SystemExit(f"RCS print shim missing split print-error boundary: {needle}")
|
||||
|
||||
rtapi_compat_shim = Path("core/wasm_shims/rtapi_compat.cc").read_text(encoding="utf-8")
|
||||
for needle in [
|
||||
"rtapi_snprintf",
|
||||
"std::vsnprintf(buf, static_cast<std::size_t>(size), fmt, ap)",
|
||||
]:
|
||||
if needle not in rtapi_compat_shim:
|
||||
raise SystemExit(f"RTAPI compatibility shim missing userspace snprintf boundary: {needle}")
|
||||
|
||||
for phrase in [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"CMake `linuxcnc_wasm_safe_probe_shims` set",
|
||||
"RS274/WASM manifest",
|
||||
"browser-safe LinuxCNC adaptations",
|
||||
"LinuxCNC `interp_base.cc` dynamic loader calls",
|
||||
"unavailable-loader returns",
|
||||
"detached LinuxCNC `EMC_STAT` singleton",
|
||||
"LinuxCNC `_()` diagnostic call sites",
|
||||
"browser gettext catalogs unavailable",
|
||||
"LinuxCNC NML status constructors",
|
||||
"`RCS_STAT_MSG` default status fields",
|
||||
"dynamic loading unavailable",
|
||||
"unavailable HAL lookup",
|
||||
"must leave HAL values unavailable",
|
||||
"preview `_task=0`",
|
||||
"builtin module stubs",
|
||||
"must not switch browser-safe probes into task mode",
|
||||
"single-word `wordexp()` path expansion",
|
||||
"`wordfree()` cleanup",
|
||||
"must not become a shell expansion feature",
|
||||
"must not become Python execution",
|
||||
"Python C API shim must return inert objects",
|
||||
"must not call into CPython runtime",
|
||||
"keeping Python execution disabled",
|
||||
"must not execute `bp::exec`, `bp::exec_file`, or",
|
||||
"inactive-DB return values",
|
||||
"negative-status short-circuit behavior",
|
||||
"first-caller `_inittab` `PLUGIN_INITTAB_FAILED` edge",
|
||||
"preserve the `TOPLEVEL` missing-path `PLUGIN_BAD_PATH` edge",
|
||||
"preserve `PATH_PREPEND` and `PATH_APPEND` tilde-expansion failure statuses",
|
||||
"preserve LinuxCNC INI section-name trimming and trailing section-comment handling",
|
||||
"LinuxCNC `rcs_print_error` split entry points",
|
||||
"without native print routing",
|
||||
"LinuxCNC userspace `rtapi_snprintf()` formatting",
|
||||
"`uspace_common.h` `vsnprintf()` implementation path",
|
||||
"./check-linuxcnc-wasm-shims-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-shims-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-shims-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-shims-source-map.sh")
|
||||
|
||||
cmake_text = Path("core/CMakeLists.txt").read_text(encoding="utf-8")
|
||||
for shim_path in shim_paths:
|
||||
cmake_suffix = shim_path.removeprefix("core/")
|
||||
if cmake_suffix not in cmake_text:
|
||||
raise SystemExit(f"{shim_path} is not listed in linuxcnc_wasm_safe_probe_shims")
|
||||
|
||||
blocker_map = Path("docs/linuxcnc-wasm-blockers-source-map.md").read_text(encoding="utf-8")
|
||||
for shim_path in [
|
||||
"core/wasm_shims/linuxcnc_runtime_shim.cc",
|
||||
"core/wasm_shims/python_c_api_shim.cc",
|
||||
"core/wasm_shims/tooldata/tooldata_mmap_backend.cc",
|
||||
]:
|
||||
if shim_path not in blocker_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-blockers-source-map.md no longer references {shim_path}")
|
||||
PY
|
||||
204
check-linuxcnc-wasm-smoke-source-map.sh
Executable file
204
check-linuxcnc-wasm-smoke-source-map.sh
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties Node/browser WASM smoke coverage to
|
||||
# LinuxCNC RS274 parameter/INI handling, M-code canon side effects, generated
|
||||
# switchkins/remap config cases, kinematics sources, and OPFS-only browser
|
||||
# persistence. It validates smoke-test source coverage only; it does not add
|
||||
# CNC behavior, expand smoke parsing, or interpret G-code.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F 'int Interp::ini_load(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::restore_parameters(const char *filename)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'std::string tempfile = std::string(filename) + ".new";' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'unlink(bakfile.c_str());' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'int read_text(const char *command, FILE * inport, char *raw_line,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_interp.hh" >/dev/null
|
||||
|
||||
grep -F 'int Interp::convert_m(block_pointer block' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'int ret = WAIT(round_to_int(block->p_number), DIGITAL_INPUT, type, timeout);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'SET_AUX_OUTPUT_VALUE(round_to_int(block->e_number), block->q_number);' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_convert.cc" >/dev/null
|
||||
grep -F 'extern int WAIT(int index' "$linuxcnc_root/src/emc/nml_intf/canon.hh" >/dev/null
|
||||
grep -F 'extern void SET_AUX_OUTPUT_VALUE(int index, double value);' \
|
||||
"$linuxcnc_root/src/emc/nml_intf/canon.hh" >/dev/null
|
||||
|
||||
grep -F 'kp->kinsname = "5axiskins";' "$linuxcnc_root/src/emc/kinematics/5axiskins.c" >/dev/null
|
||||
grep -F 'int xyzbcKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/trtfuncs.c" >/dev/null
|
||||
grep -F 'int xyzacKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/trtfuncs.c" >/dev/null
|
||||
grep -F '*kinv1 = xyzacKinematicsInverse;' \
|
||||
"$linuxcnc_root/src/emc/kinematics/xyzac-trt-kins.c" >/dev/null
|
||||
grep -F '*kinv1 = xyzbcKinematicsInverse;' \
|
||||
"$linuxcnc_root/src/emc/kinematics/xyzbc-trt-kins.c" >/dev/null
|
||||
grep -F 'int userkKinematicsInverse(const EmcPose * pos' \
|
||||
"$linuxcnc_root/src/emc/kinematics/userkfuncs.c" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC WASM smoke source map' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'OPFS-only' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F '`src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'unlinking `filename + ".bak"`' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F '`src/emc/kinematics/5axiskins.c`, `src/emc/kinematics/trtfuncs.c`' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
grep -F 'Generated switchkins config smoke cases must continue to come from' \
|
||||
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: Node smoke only verifies the wasm/API bridge around' \
|
||||
test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'minimum_steps=${WASM_NODE_SMOKE_MIN_STEPS:-50}' test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'WASM Node smoke covered $passed_steps steps, expected at least $minimum_steps' \
|
||||
test-web-wasm-node-smoke.sh >/dev/null
|
||||
grep -F 'expected Node wasm-core wrapper to leave OPFS disabled' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected Node wasm-core parseFile to require OPFS' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'linuxcnc_switchkins_remap_config_cases.json' test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM M68 E3 Q${kinstype} remap side effect' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM M66 E0 L0 remap side effect' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM 5axiskins RTCP pivot from LinuxCNC 5axiskins inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM configured xyzbc-trt RTCP pivot from LinuxCNC trtfuncs inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
grep -F 'expected LinuxCNC WASM configured xyzac-trt RTCP pivot from LinuxCNC xyzab_tdr inverse' \
|
||||
test-web-wasm-node-smoke.cjs >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC source basis: browser smoke verifies OPFS-backed wasm/API/app flows' \
|
||||
test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'minimum_sections=${BROWSER_SMOKE_MIN_SECTIONS:-50}' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'BROWSER_SMOKE_MIN_SECTIONS must be a positive integer' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'browser WASM smoke covered $passed_sections sections, expected at least $minimum_sections' \
|
||||
test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'required_browser_sections = {' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("linuxcnc generated switchkins cases load"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs parameter restore in new instance"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runSection("browser app opfs restore"' test-web-wasm-browser-smoke.sh >/dev/null
|
||||
grep -F 'runLinuxCncBrowserSections(context, simulator)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsWorkspaceSections(context, simulator)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsPolicySections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserAppOpfsSections(context)' web/test-browser-wasm-smoke-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsBasicSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsParameterSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsMirrorSections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'runBrowserOpfsDirectorySections(context, simulator)' \
|
||||
web/test-browser-wasm-smoke-opfs-workspace-sections.js >/dev/null
|
||||
grep -F 'linuxcnc_switchkins_remap_config_cases.json' \
|
||||
web/test-browser-wasm-smoke-linuxcnc-sections.js >/dev/null
|
||||
grep -F 'missing LinuxCNC switchkins config cases after INI_FILE_NAME remap-load filtering' \
|
||||
web/test-browser-wasm-smoke-linuxcnc-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters()' \
|
||||
web/test-browser-wasm-smoke-opfs-parameter-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc save_parameters()' \
|
||||
web/test-browser-wasm-smoke-opfs-parameter-sections.js >/dev/null
|
||||
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc read_text() reads' \
|
||||
web/test-browser-wasm-smoke-opfs-basic-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs directory persist and load"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("opfs metadata queries avoid wasm mirror pollution"' \
|
||||
web/test-browser-wasm-smoke-opfs-directory-sections.js >/dev/null
|
||||
grep -F 'runSection("browser opfs policy"' \
|
||||
web/test-browser-wasm-smoke-opfs-policy-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist current program into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
|
||||
web/test-browser-wasm-smoke-app-sections.js >/dev/null
|
||||
|
||||
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
|
||||
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' \
|
||||
web/test-browser-wasm-smoke-*.js \
|
||||
web/test-browser-wasm-smoke.html \
|
||||
test-web-wasm-browser-smoke.sh; then
|
||||
echo "browser WASM smoke harness must not add filesystem persistence outside OPFS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
|
||||
source_map = Path("docs/linuxcnc-wasm-smoke-source-map.md").read_text(encoding="utf-8")
|
||||
json_cases = json.loads(Path("web/public/linuxcnc_switchkins_remap_config_cases.json").read_text(encoding="utf-8"))
|
||||
if not isinstance(json_cases, list) or len(json_cases) == 0:
|
||||
raise SystemExit("generated LinuxCNC switchkins browser config cases are missing")
|
||||
|
||||
node_wrapper = Path("test-web-wasm-node-smoke.sh").read_text(encoding="utf-8")
|
||||
browser_wrapper = Path("test-web-wasm-browser-smoke.sh").read_text(encoding="utf-8")
|
||||
node_min = re.search(r"minimum_steps=\$\{WASM_NODE_SMOKE_MIN_STEPS:-(\d+)\}", node_wrapper)
|
||||
browser_min = re.search(r"minimum_sections=\$\{BROWSER_SMOKE_MIN_SECTIONS:-(\d+)\}", browser_wrapper)
|
||||
if not node_min or int(node_min.group(1)) < 50:
|
||||
raise SystemExit("Node WASM smoke minimum step threshold is missing or below 50")
|
||||
if not browser_min or int(browser_min.group(1)) < 50:
|
||||
raise SystemExit("browser WASM smoke minimum section threshold is missing or below 50")
|
||||
|
||||
for path in [
|
||||
"test-web-wasm-node-smoke.sh",
|
||||
"test-web-wasm-node-smoke.cjs",
|
||||
"test-web-wasm-browser-smoke.sh",
|
||||
"web/test-browser-wasm-smoke-linuxcnc-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-workspace-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-basic-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-parameter-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-mirror-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-directory-sections.js",
|
||||
"web/test-browser-wasm-smoke-opfs-policy-sections.js",
|
||||
"web/test-browser-wasm-smoke-app-sections.js",
|
||||
]:
|
||||
if f"| `{path}` |" not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-smoke-source-map.md missing smoke entry: {path}")
|
||||
|
||||
required_phrases = [
|
||||
"must not add CNC behavior",
|
||||
"must not expand the temporary smoke parser",
|
||||
"persistence OPFS-only",
|
||||
"Node smoke must leave OPFS disabled",
|
||||
"Browser smoke harness files must not use Local Storage",
|
||||
"Generated switchkins config smoke cases",
|
||||
"browser smoke shell guard also pins required section names",
|
||||
"OPFS workspace/policy/directory handling",
|
||||
'unlinking `filename + ".bak"`',
|
||||
"./check-linuxcnc-wasm-smoke-source-map.sh",
|
||||
"does not interpret G-code",
|
||||
]
|
||||
for phrase in required_phrases:
|
||||
if phrase not in source_map:
|
||||
raise SystemExit(f"docs/linuxcnc-wasm-smoke-source-map.md missing boundary phrase: {phrase}")
|
||||
|
||||
for entry in [
|
||||
"test-native.sh",
|
||||
"test-linuxcnc-source-link.sh",
|
||||
"build-wasm.sh",
|
||||
]:
|
||||
text = Path(entry).read_text(encoding="utf-8")
|
||||
if "./check-linuxcnc-wasm-smoke-source-map.sh" not in text:
|
||||
raise SystemExit(f"{entry} must run ./check-linuxcnc-wasm-smoke-source-map.sh")
|
||||
PY
|
||||
132
check-linuxcnc-workstreams-source-map.sh
Executable file
132
check-linuxcnc-workstreams-source-map.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# LinuxCNC source basis: this guard ties the six active workstream contexts to
|
||||
# their source-map guards and to LinuxCNC source/config anchors. It validates
|
||||
# coordination policy only; it does not add CNC behavior or expand smoke
|
||||
# parsing.
|
||||
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
|
||||
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
|
||||
|
||||
grep -F '1. `switchkins/remap` generator and tables' docs/architecture.md >/dev/null
|
||||
grep -F '2. `linuxcnc-kinematics` source manifest' docs/architecture.md >/dev/null
|
||||
grep -F '3. WASM filesystem and OPFS persistence' docs/architecture.md >/dev/null
|
||||
grep -F '4. browser app integration' docs/architecture.md >/dev/null
|
||||
grep -F '5. Node and browser smoke coverage' docs/architecture.md >/dev/null
|
||||
grep -F '6. source-link, build, and documentation constraints' docs/architecture.md >/dev/null
|
||||
grep -F 'The synchronized source-map guard for these contexts is' docs/architecture.md >/dev/null
|
||||
grep -F '`docs/linuxcnc-workstreams-source-map.md`.' docs/architecture.md >/dev/null
|
||||
|
||||
grep -F 'REMAP = M428' "$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/5axis.ini" >/dev/null
|
||||
grep -F '#<kinstype>' "$linuxcnc_root/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc" >/dev/null
|
||||
grep -F 'GENSERKINSSRCS := emc/kinematics/ugenserkins.c' \
|
||||
"$linuxcnc_root/src/emc/kinematics/Submakefile" >/dev/null
|
||||
grep -F 'extern int kinematicsInverse(const struct EmcPose * world,' \
|
||||
"$linuxcnc_root/src/emc/kinematics/kinematics.h" >/dev/null
|
||||
grep -F '#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var"' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/interp_internal.hh" >/dev/null
|
||||
grep -F 'int Interp::save_parameters(const char *filename,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
|
||||
grep -F 'LIBRS274SRCS := $(addprefix emc/rs274ngc/,' \
|
||||
"$linuxcnc_root/src/emc/rs274ngc/Submakefile" >/dev/null
|
||||
grep -F 'LIBTOOLDATA_SRCS += emc/tooldata/tooldata_common.cc' \
|
||||
"$linuxcnc_root/src/emc/tooldata/Submakefile" >/dev/null
|
||||
grep -F 'LIBLCNCINISRCS := emc/ini/inifile.cc' \
|
||||
"$linuxcnc_root/src/emc/ini/Submakefile" >/dev/null
|
||||
grep -F 'LIBPPSRCS := $(addprefix emc/pythonplugin/,' \
|
||||
"$linuxcnc_root/src/emc/pythonplugin/Submakefile" >/dev/null
|
||||
|
||||
grep -F 'LinuxCNC workstreams source map' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'must not add CNC' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'temporary smoke parser' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Every active workstream must have at least one source-map document and guard' \
|
||||
docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'docs/linuxcnc-source-policy.md` must keep the same one-context workflow' \
|
||||
docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Browser filesystem persistence remains OPFS-only.' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Smoke coverage remains verification only' docs/linuxcnc-workstreams-source-map.md >/dev/null
|
||||
grep -F 'Keep the change inside one active workstream context unless a dependency is' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Each pass should advance one reasonable, reviewable context.' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Keep the six active workstream contexts synchronized with' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F '`docs/linuxcnc-workstreams-source-map.md` so source-map guards' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Smoke tests are verification guardrails. They must not be expanded with new' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Do not mix generator/table work, manifests, OPFS/browser work, and build' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
grep -F 'Browser-side wasm filesystem behavior must use OPFS-backed storage.' \
|
||||
docs/linuxcnc-source-policy.md >/dev/null
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
|
||||
doc = Path("docs/linuxcnc-workstreams-source-map.md").read_text(encoding="utf-8")
|
||||
policy = Path("docs/linuxcnc-source-policy.md").read_text(encoding="utf-8")
|
||||
expected = {
|
||||
"switchkins/remap": [
|
||||
"docs/linuxcnc-switchkins-remap-source-map.md",
|
||||
"check-linuxcnc-switchkins-remap-source-map.sh",
|
||||
],
|
||||
"linuxcnc-kinematics": [
|
||||
"docs/linuxcnc-kinematics-source-map.md",
|
||||
"check-linuxcnc-kinematics-source-map.sh",
|
||||
],
|
||||
"WASM filesystem and OPFS persistence": [
|
||||
"docs/linuxcnc-opfs-source-map.md",
|
||||
"docs/linuxcnc-wasm-shims-source-map.md",
|
||||
"docs/linuxcnc-wasm-blockers-source-map.md",
|
||||
"docs/linuxcnc-tooldata-source-map.md",
|
||||
"check-linuxcnc-opfs-source-map.sh",
|
||||
"check-linuxcnc-wasm-shims-source-map.sh",
|
||||
"check-linuxcnc-wasm-blockers-source-map.sh",
|
||||
"check-linuxcnc-tooldata-source-map.sh",
|
||||
],
|
||||
"browser app integration": [
|
||||
"docs/linuxcnc-browser-app-source-map.md",
|
||||
"check-linuxcnc-browser-app-source-map.sh",
|
||||
],
|
||||
"Node and browser smoke coverage": [
|
||||
"docs/linuxcnc-wasm-smoke-source-map.md",
|
||||
"check-linuxcnc-wasm-smoke-source-map.sh",
|
||||
],
|
||||
"source-link, build, and documentation constraints": [
|
||||
"docs/linuxcnc-rs274-source-map.md",
|
||||
"docs/linuxcnc-build-source-map.md",
|
||||
"docs/linuxcnc-tooldata-source-map.md",
|
||||
"check-linuxcnc-rs274-source-map.sh",
|
||||
"check-linuxcnc-build-source-map.sh",
|
||||
"check-linuxcnc-tooldata-source-map.sh",
|
||||
],
|
||||
}
|
||||
for workstream, paths in expected.items():
|
||||
if workstream not in doc:
|
||||
raise SystemExit(f"missing workstream row in docs/linuxcnc-workstreams-source-map.md: {workstream}")
|
||||
policy_terms = {
|
||||
"switchkins/remap": ["switchkins/remap", "M428/M429/M430"],
|
||||
"linuxcnc-kinematics": ["kinematics manifest", "RTCP coverage"],
|
||||
"WASM filesystem and OPFS persistence": ["OPFS", "filesystem"],
|
||||
"browser app integration": ["Browser app", "wasm bridge"],
|
||||
"Node and browser smoke coverage": ["Smoke tests are verification guardrails", "temporary smoke parser"],
|
||||
"source-link, build, and documentation constraints": ["source-link", "build-policy"],
|
||||
}[workstream]
|
||||
if not any(term in policy for term in policy_terms):
|
||||
raise SystemExit(f"docs/linuxcnc-source-policy.md no longer references workstream boundary: {workstream}")
|
||||
for path in paths:
|
||||
if path not in doc:
|
||||
raise SystemExit(f"missing source-map path in workstream index: {path}")
|
||||
if not Path(path).exists():
|
||||
raise SystemExit(f"source-map path listed in workstream index does not exist: {path}")
|
||||
if path.startswith("check-") and not Path(path).stat().st_mode & 0o111:
|
||||
raise SystemExit(f"source-map guard is not executable: {path}")
|
||||
|
||||
for test_entry in ["test-native.sh", "test-linuxcnc-source-link.sh", "build-wasm.sh"]:
|
||||
text = Path(test_entry).read_text(encoding="utf-8")
|
||||
for guard in sorted({path for paths in expected.values() for path in paths if path.startswith("check-")}):
|
||||
if f"./{guard}" not in text:
|
||||
raise SystemExit(f"{test_entry} does not run workstream source-map guard: {guard}")
|
||||
PY
|
||||
@@ -1,9 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(cnc_sim_wasm_core LANGUAGES CXX)
|
||||
project(cnc_sim_wasm_core LANGUAGES C CXX)
|
||||
|
||||
option(CNC_SIM_ENABLE_LINUXCNC_BRIDGE "Build the experimental LinuxCNC canon bridge" OFF)
|
||||
option(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND "Build the native LinuxCNC librs274 backend" OFF)
|
||||
option(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE "Compile the browser-safe subset of LinuxCNC rs274 sources" OFF)
|
||||
option(CNC_SIM_ENABLE_SMOKE_BACKEND "Build the legacy explicit smoke G-code backend test harness" OFF)
|
||||
if(CNC_SIM_ENABLE_SMOKE_BACKEND AND CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
message(FATAL_ERROR "CNC_SIM_ENABLE_SMOKE_BACKEND cannot be combined with CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE")
|
||||
endif()
|
||||
set(CNC_SIM_LINUXCNC_ROOT "" CACHE PATH "LinuxCNC source root for the experimental bridge")
|
||||
set(CNC_SIM_LINUXCNC_WASM_SOURCE_MANIFEST
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc-rs274-wasm-source-files.txt"
|
||||
@@ -15,23 +19,71 @@ set(cnc_sim_core_sources
|
||||
src/canon_event_sink.cpp
|
||||
src/cnc_sim_api.cpp
|
||||
src/gcode_backend.cpp
|
||||
src/linuxcnc_5axiskins_adapter.c
|
||||
src/linuxcnc_5axiskins_adapter.cpp
|
||||
src/linuxcnc_corexykins_adapter.c
|
||||
src/linuxcnc_corexykins_adapter.cpp
|
||||
src/linuxcnc_cubic_adapter.c
|
||||
src/linuxcnc_cubic_adapter.cpp
|
||||
src/linuxcnc_genserfuncs_adapter.c
|
||||
src/linuxcnc_genserfuncs_adapter.cpp
|
||||
src/linuxcnc_genhexkins_adapter.c
|
||||
src/linuxcnc_genhexkins_adapter.cpp
|
||||
src/linuxcnc_kins_util_adapter.c
|
||||
src/linuxcnc_kins_util_adapter.cpp
|
||||
src/linuxcnc_lineardeltakins_adapter.c
|
||||
src/linuxcnc_lineardeltakins_adapter.cpp
|
||||
src/linuxcnc_maxkins_adapter.c
|
||||
src/linuxcnc_maxkins_adapter.cpp
|
||||
src/linuxcnc_pentakins_adapter.c
|
||||
src/linuxcnc_pentakins_adapter.cpp
|
||||
src/linuxcnc_pumakins_adapter.c
|
||||
src/linuxcnc_pumakins_adapter.cpp
|
||||
src/linuxcnc_rotatekins_adapter.c
|
||||
src/linuxcnc_rotatekins_adapter.cpp
|
||||
src/linuxcnc_rosekins_adapter.c
|
||||
src/linuxcnc_rosekins_adapter.cpp
|
||||
src/linuxcnc_rotarydeltakins_adapter.c
|
||||
src/linuxcnc_rotarydeltakins_adapter.cpp
|
||||
src/linuxcnc_scarakins_adapter.c
|
||||
src/linuxcnc_scarakins_adapter.cpp
|
||||
src/linuxcnc_scorbot_kins_adapter.c
|
||||
src/linuxcnc_scorbot_kins_adapter.cpp
|
||||
src/linuxcnc_tripodkins_adapter.c
|
||||
src/linuxcnc_tripodkins_adapter.cpp
|
||||
src/linuxcnc_trtfuncs_adapter.c
|
||||
src/linuxcnc_trtfuncs_adapter.cpp
|
||||
src/linuxcnc_userkfuncs_adapter.c
|
||||
src/linuxcnc_userkfuncs_adapter.cpp
|
||||
src/linuxcnc_xyzab_tdr_kins_adapter.c
|
||||
src/linuxcnc_xyzab_tdr_kins_adapter.cpp
|
||||
src/rtcp_kinematics.cpp
|
||||
src/simulator_gcode_controls.cpp
|
||||
)
|
||||
|
||||
set(cnc_sim_smoke_backend_sources
|
||||
src/smoke_gcode_parser.cpp
|
||||
)
|
||||
|
||||
set(cnc_sim_linuxcnc_rs274_backend_sources
|
||||
src/linuxcnc_canon_bridge.cpp
|
||||
src/linuxcnc_rs274_backend.cpp
|
||||
src/linuxcnc_tooldata_fixture.cpp
|
||||
)
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
|
||||
message(FATAL_ERROR "CNC_SIM_ENABLE_SMOKE_BACKEND cannot be combined with CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND")
|
||||
endif()
|
||||
if(EMSCRIPTEN)
|
||||
message(FATAL_ERROR "CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND is native-only; it links LinuxCNC librs274")
|
||||
endif()
|
||||
if(NOT CNC_SIM_LINUXCNC_ROOT)
|
||||
message(FATAL_ERROR "Set CNC_SIM_LINUXCNC_ROOT to the LinuxCNC source root")
|
||||
endif()
|
||||
list(APPEND cnc_sim_core_sources
|
||||
src/linuxcnc_canon_bridge.cpp
|
||||
src/linuxcnc_rs274_backend.cpp
|
||||
src/linuxcnc_tooldata_fixture.cpp
|
||||
)
|
||||
list(APPEND cnc_sim_core_sources ${cnc_sim_linuxcnc_rs274_backend_sources})
|
||||
elseif(CNC_SIM_ENABLE_SMOKE_BACKEND)
|
||||
list(APPEND cnc_sim_core_sources ${cnc_sim_smoke_backend_sources})
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
@@ -67,7 +119,11 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
|
||||
set(manifest_group "${CMAKE_MATCH_1}")
|
||||
set(manifest_path "${CMAKE_MATCH_2}")
|
||||
if(NOT manifest_group STREQUAL "core" AND NOT manifest_group STREQUAL "blocked")
|
||||
if(NOT manifest_group STREQUAL "core"
|
||||
AND NOT manifest_group STREQUAL "blocked"
|
||||
AND NOT manifest_group STREQUAL "header"
|
||||
AND NOT manifest_group STREQUAL "metadata"
|
||||
AND NOT manifest_group STREQUAL "blocked-header")
|
||||
message(FATAL_ERROR "Unknown LinuxCNC wasm source manifest group: ${manifest_group}")
|
||||
endif()
|
||||
|
||||
@@ -81,7 +137,7 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
|
||||
if(manifest_group STREQUAL "core")
|
||||
list(APPEND linuxcnc_wasm_safe_probe_sources "${manifest_source}")
|
||||
else()
|
||||
elseif(manifest_group STREQUAL "blocked")
|
||||
list(APPEND linuxcnc_wasm_blocked_sources "${manifest_source}")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -97,12 +153,27 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
message(STATUS "LinuxCNC wasm-safe core sources: ${linuxcnc_wasm_safe_probe_source_count}")
|
||||
message(STATUS "LinuxCNC wasm blocked sources: ${linuxcnc_wasm_blocked_source_count}")
|
||||
|
||||
set(cnc_sim_wasm_safe_preinclude_options "SHELL:-include wctype.h")
|
||||
set(cnc_sim_wasm_safe_section_options -ffunction-sections -fdata-sections)
|
||||
set(cnc_sim_wasm_safe_link_options "-Wl,--gc-sections")
|
||||
if(EMSCRIPTEN)
|
||||
list(APPEND cnc_sim_wasm_safe_preinclude_options "SHELL:-include libgen.h")
|
||||
find_path(CNC_SIM_FMT_INCLUDE_DIR fmt/format.h
|
||||
PATHS /usr/include /usr/local/include
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
REQUIRED
|
||||
)
|
||||
list(APPEND cnc_sim_wasm_safe_preinclude_options "SHELL:-idirafter ${CNC_SIM_FMT_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
set(linuxcnc_wasm_safe_probe_shims
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/dlfcn.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/emc_status_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/gettext_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/linuxcnc_runtime_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/nml_status_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/python_c_api_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rcs_print_shim.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rtapi_compat.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_mmap_backend.cc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/tooldata/tooldata_runtime_stubs.cc
|
||||
@@ -115,7 +186,10 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
)
|
||||
target_compile_features(linuxcnc_rs274_wasm_safe_probe_objects PUBLIC cxx_std_20)
|
||||
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE ULAPI)
|
||||
target_compile_options(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE -include wctype.h)
|
||||
target_compile_options(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE
|
||||
${cnc_sim_wasm_safe_preinclude_options}
|
||||
${cnc_sim_wasm_safe_section_options}
|
||||
)
|
||||
target_include_directories(linuxcnc_rs274_wasm_safe_probe_objects
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
@@ -128,36 +202,14 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
)
|
||||
if(EMSCRIPTEN)
|
||||
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe_objects PRIVATE FMT_HEADER_ONLY=1)
|
||||
endif()
|
||||
|
||||
set(linuxcnc_rs274_wasm_safe_probe_project_sources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/canon_event_sink.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_canon_bridge.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/linuxcnc_tooldata_fixture.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcp_kinematics.cpp
|
||||
set(cnc_sim_wasm_runtime_probe_main
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/cnc_sim_wasm_runtime_probe_main.cc
|
||||
)
|
||||
|
||||
add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL
|
||||
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
|
||||
${linuxcnc_rs274_wasm_safe_probe_project_sources}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rs274ngc_pre_probe_main.cc
|
||||
)
|
||||
target_compile_features(linuxcnc_rs274_wasm_safe_probe PRIVATE cxx_std_20)
|
||||
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe PRIVATE ULAPI)
|
||||
target_compile_options(linuxcnc_rs274_wasm_safe_probe PRIVATE -include wctype.h)
|
||||
target_include_directories(linuxcnc_rs274_wasm_safe_probe
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
)
|
||||
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
|
||||
|
||||
if(linuxcnc_wasm_blocked_sources)
|
||||
add_custom_target(linuxcnc_rs274_wasm_blocked_sources
|
||||
SOURCES ${linuxcnc_wasm_blocked_sources}
|
||||
@@ -165,6 +217,10 @@ if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
list(APPEND cnc_sim_core_sources ${cnc_sim_linuxcnc_rs274_backend_sources})
|
||||
endif()
|
||||
|
||||
add_library(cnc_sim_objects OBJECT
|
||||
${cnc_sim_core_sources}
|
||||
)
|
||||
@@ -174,9 +230,36 @@ target_include_directories(cnc_sim_objects
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../linuxcnc/include
|
||||
)
|
||||
|
||||
target_compile_features(cnc_sim_objects PUBLIC cxx_std_17)
|
||||
set(cnc_sim_linuxcnc_kinematics_c_sources
|
||||
src/linuxcnc_5axiskins_adapter.c
|
||||
src/linuxcnc_corexykins_adapter.c
|
||||
src/linuxcnc_cubic_adapter.c
|
||||
src/linuxcnc_genserfuncs_adapter.c
|
||||
src/linuxcnc_genhexkins_adapter.c
|
||||
src/linuxcnc_kins_util_adapter.c
|
||||
src/linuxcnc_lineardeltakins_adapter.c
|
||||
src/linuxcnc_maxkins_adapter.c
|
||||
src/linuxcnc_pentakins_adapter.c
|
||||
src/linuxcnc_pumakins_adapter.c
|
||||
src/linuxcnc_rotatekins_adapter.c
|
||||
src/linuxcnc_rosekins_adapter.c
|
||||
src/linuxcnc_rotarydeltakins_adapter.c
|
||||
src/linuxcnc_scarakins_adapter.c
|
||||
src/linuxcnc_scorbot_kins_adapter.c
|
||||
src/linuxcnc_tripodkins_adapter.c
|
||||
src/linuxcnc_trtfuncs_adapter.c
|
||||
src/linuxcnc_userkfuncs_adapter.c
|
||||
src/linuxcnc_xyzab_tdr_kins_adapter.c
|
||||
)
|
||||
set_source_files_properties(
|
||||
${cnc_sim_linuxcnc_kinematics_c_sources}
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>"
|
||||
)
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
find_package(Python3 REQUIRED COMPONENTS Development)
|
||||
@@ -196,6 +279,97 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
target_compile_definitions(cnc_sim_objects
|
||||
PRIVATE
|
||||
CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
|
||||
CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
ULAPI
|
||||
)
|
||||
target_compile_options(cnc_sim_objects PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
|
||||
target_include_directories(cnc_sim_objects
|
||||
PRIVATE
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
|
||||
)
|
||||
if(EMSCRIPTEN)
|
||||
target_compile_definitions(cnc_sim_objects PRIVATE FMT_HEADER_ONLY=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
add_executable(linuxcnc_rs274_wasm_safe_probe EXCLUDE_FROM_ALL
|
||||
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
|
||||
$<TARGET_OBJECTS:cnc_sim_objects>
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims/rs274ngc_pre_probe_main.cc
|
||||
)
|
||||
target_compile_features(linuxcnc_rs274_wasm_safe_probe PRIVATE cxx_std_20)
|
||||
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe
|
||||
PRIVATE
|
||||
CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
|
||||
CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
ULAPI
|
||||
)
|
||||
target_compile_options(linuxcnc_rs274_wasm_safe_probe PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
|
||||
target_link_options(linuxcnc_rs274_wasm_safe_probe PRIVATE ${cnc_sim_wasm_safe_link_options})
|
||||
target_include_directories(linuxcnc_rs274_wasm_safe_probe
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
)
|
||||
if(EMSCRIPTEN)
|
||||
target_compile_definitions(linuxcnc_rs274_wasm_safe_probe PRIVATE FMT_HEADER_ONLY=1)
|
||||
else()
|
||||
target_link_libraries(linuxcnc_rs274_wasm_safe_probe PRIVATE fmt)
|
||||
endif()
|
||||
|
||||
add_executable(cnc_sim_wasm_runtime_probe EXCLUDE_FROM_ALL
|
||||
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
|
||||
$<TARGET_OBJECTS:cnc_sim_objects>
|
||||
${cnc_sim_wasm_runtime_probe_main}
|
||||
)
|
||||
target_compile_features(cnc_sim_wasm_runtime_probe PRIVATE cxx_std_20)
|
||||
target_compile_definitions(cnc_sim_wasm_runtime_probe PRIVATE ULAPI)
|
||||
target_compile_options(cnc_sim_wasm_runtime_probe PRIVATE ${cnc_sim_wasm_safe_preinclude_options})
|
||||
target_link_options(cnc_sim_wasm_runtime_probe PRIVATE ${cnc_sim_wasm_safe_link_options})
|
||||
target_include_directories(cnc_sim_wasm_runtime_probe
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
)
|
||||
if(EMSCRIPTEN)
|
||||
target_compile_definitions(cnc_sim_wasm_runtime_probe PRIVATE FMT_HEADER_ONLY=1)
|
||||
else()
|
||||
target_link_libraries(cnc_sim_wasm_runtime_probe PRIVATE fmt)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
|
||||
target_compile_definitions(cnc_sim_objects
|
||||
PRIVATE
|
||||
CNC_SIM_ENABLE_SMOKE_BACKEND
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(cnc_sim_core STATIC
|
||||
$<TARGET_OBJECTS:cnc_sim_objects>
|
||||
)
|
||||
@@ -225,11 +399,13 @@ if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
endif()
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
|
||||
add_executable(cnc_sim_api_smoke
|
||||
tests/cnc_sim_api_smoke.cpp
|
||||
)
|
||||
target_link_libraries(cnc_sim_api_smoke PRIVATE cnc_sim_core)
|
||||
target_include_directories(cnc_sim_api_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
endif()
|
||||
|
||||
add_executable(canon_event_sink_smoke
|
||||
tests/canon_event_sink_smoke.cpp
|
||||
@@ -254,11 +430,13 @@ if(NOT EMSCRIPTEN)
|
||||
target_link_libraries(simulator_gcode_controls_smoke PRIVATE cnc_sim_core)
|
||||
target_include_directories(simulator_gcode_controls_smoke PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
|
||||
if(CNC_SIM_ENABLE_SMOKE_BACKEND)
|
||||
add_executable(cnc_sim_dump
|
||||
tools/cnc_sim_dump.cpp
|
||||
)
|
||||
target_link_libraries(cnc_sim_dump PRIVATE cnc_sim_core)
|
||||
target_include_directories(cnc_sim_dump PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
endif()
|
||||
|
||||
if(CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND)
|
||||
add_executable(cnc_sim_api_linuxcnc_rs274_smoke
|
||||
@@ -298,7 +476,11 @@ if(CNC_SIM_ENABLE_LINUXCNC_BRIDGE)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
if(NOT CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE)
|
||||
message(FATAL_ERROR "WASM builds must enable CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE so LinuxCNC rs274 sources are linked")
|
||||
endif()
|
||||
add_executable(cnc_sim_wasm
|
||||
$<TARGET_OBJECTS:linuxcnc_rs274_wasm_safe_probe_objects>
|
||||
$<TARGET_OBJECTS:cnc_sim_objects>
|
||||
)
|
||||
|
||||
@@ -306,7 +488,15 @@ if(EMSCRIPTEN)
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wasm_shims
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/nml_intf
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/rs274ngc
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/src/emc/motion
|
||||
${CNC_SIM_LINUXCNC_ROOT_ABS}/include
|
||||
)
|
||||
target_compile_definitions(cnc_sim_wasm PRIVATE FMT_HEADER_ONLY=1)
|
||||
|
||||
set_target_properties(cnc_sim_wasm PROPERTIES
|
||||
OUTPUT_NAME "cnc_sim"
|
||||
@@ -314,12 +504,14 @@ if(EMSCRIPTEN)
|
||||
)
|
||||
|
||||
target_link_options(cnc_sim_wasm PRIVATE
|
||||
${cnc_sim_wasm_safe_link_options}
|
||||
"--no-entry"
|
||||
"-sMODULARIZE=1"
|
||||
"-sEXPORT_NAME=createCncSimModule"
|
||||
"-sALLOW_MEMORY_GROWTH=1"
|
||||
"-sALLOW_TABLE_GROWTH=1"
|
||||
"-sFORCE_FILESYSTEM=1"
|
||||
"-sEXPORTED_FUNCTIONS=['_malloc','_free','_cnc_sim_create','_cnc_sim_destroy','_cnc_sim_reset','_cnc_sim_set_dialect','_cnc_sim_set_event_callback','_cnc_sim_load_config_json','_cnc_sim_parse_program','_cnc_sim_last_error']"
|
||||
"-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8','addFunction','removeFunction']"
|
||||
"-sEXPORTED_RUNTIME_METHODS=['FS','ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8','addFunction','removeFunction']"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kCssSpindleModeEvent = 960;
|
||||
constexpr int kConstantRpmSpindleModeEvent = 970;
|
||||
|
||||
void rotate_xy(double *x, double *y, double degrees) {
|
||||
const double radians = degrees * std::acos(-1.0) / 180.0;
|
||||
const double c = std::cos(radians);
|
||||
@@ -32,7 +33,9 @@ void CanonEventSink::reset() {
|
||||
tool_length_offset_ = {};
|
||||
xy_rotation_degrees_ = 0.0;
|
||||
callback_status_ = 0;
|
||||
kinematics_type_ = 1;
|
||||
// LinuxCNC xyzbc-trt-kins with sparm=identityfirst starts at switchkins-type 0.
|
||||
// Source: linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini.
|
||||
kinematics_type_ = 0;
|
||||
feed_override_ = false;
|
||||
speed_override_ = false;
|
||||
adaptive_feed_ = false;
|
||||
@@ -67,6 +70,31 @@ void CanonEventSink::configure_rtcp(bool enabled, double tool_length) {
|
||||
rtcp_tool_length_ = tool_length;
|
||||
}
|
||||
|
||||
void CanonEventSink::configure_xyzbc_trt(const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
xyzbc_trt_parameters_ = parameters;
|
||||
xyzbc_trt_parameters_configured_ = true;
|
||||
use_xyzac_trt_ = false;
|
||||
}
|
||||
|
||||
void CanonEventSink::configure_xyzac_trt(const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
xyzbc_trt_parameters_ = parameters;
|
||||
xyzbc_trt_parameters_configured_ = true;
|
||||
use_xyzac_trt_ = true;
|
||||
}
|
||||
|
||||
void CanonEventSink::configure_fiveaxis(double pivot_length, int kinematics_type) {
|
||||
fiveaxis_configured_ = true;
|
||||
fiveaxis_pivot_length_ = pivot_length;
|
||||
fiveaxis_kinematics_type_ = kinematics_type;
|
||||
}
|
||||
|
||||
void CanonEventSink::configure_switchkins_remap(int m428_type, int m429_type, int m430_type) {
|
||||
switchkins_remap_configured_ = true;
|
||||
switchkins_m428_type_ = m428_type;
|
||||
switchkins_m429_type_ = m429_type;
|
||||
switchkins_m430_type_ = m430_type;
|
||||
}
|
||||
|
||||
void CanonEventSink::set_tool_length(int h_code, double tool_length) {
|
||||
if (h_code <= 0) {
|
||||
default_rtcp_tool_length_ = tool_length;
|
||||
@@ -119,15 +147,72 @@ void CanonEventSink::set_rtcp_state(bool enabled, int h_code, int line) {
|
||||
emit(event);
|
||||
}
|
||||
|
||||
void CanonEventSink::switch_kinematics(int kinematics_type, bool rtcp_enabled, int line) {
|
||||
void CanonEventSink::switch_kinematics(int kinematics_type, int line) {
|
||||
kinematics_type_ = kinematics_type;
|
||||
rtcp_enabled_ = rtcp_enabled;
|
||||
// Source: linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/{428,429,430}remap.ngc.
|
||||
// M68 E3 Q#<kinstype>, then M66 E0 L0 to force synchronization.
|
||||
set_analog_output(3, static_cast<double>(kinematics_type_), false, line);
|
||||
wait_input(0, 0, 0, 0.0, line);
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_KINEMATICS_SWITCH, line);
|
||||
event.reserved = kinematics_type_;
|
||||
event.feed = rtcp_enabled_ ? 1.0 : 0.0;
|
||||
emit(event);
|
||||
}
|
||||
|
||||
bool CanonEventSink::can_switch_m_code_kinematics(int m_code) const {
|
||||
if (!switchkins_remap_configured_) {
|
||||
return true;
|
||||
}
|
||||
if (m_code == 428) {
|
||||
return switchkins_m428_type_ >= 0;
|
||||
}
|
||||
if (m_code == 429) {
|
||||
return switchkins_m429_type_ >= 0;
|
||||
}
|
||||
if (m_code == 430) {
|
||||
return switchkins_m430_type_ >= 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanonEventSink::switch_m_code_kinematics(int m_code, int default_kinematics_type, int line) {
|
||||
if (switchkins_remap_configured_) {
|
||||
int kinematics_type = -1;
|
||||
if (m_code == 428) {
|
||||
kinematics_type = switchkins_m428_type_;
|
||||
} else if (m_code == 429) {
|
||||
kinematics_type = switchkins_m429_type_;
|
||||
} else if (m_code == 430) {
|
||||
kinematics_type = switchkins_m430_type_;
|
||||
}
|
||||
if (kinematics_type >= 0) {
|
||||
switch_kinematics(kinematics_type, line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (fiveaxis_configured_) {
|
||||
// Sources:
|
||||
// - linuxcnc/configs/sim/axis/vismach/5axis/bridgemill/remap_subs/{428,429,430}remap.ngc
|
||||
// - linuxcnc/configs/sim/axis/vismach/scara/remap_subs/{428,429,430}remap.ngc
|
||||
// - linuxcnc/configs/sim/axis/vismach/melfa-sim/remap_subs/{428,429,430}remap.ngc
|
||||
// These remaps select kinstype 0, 1, and 2 respectively.
|
||||
if (m_code == 428) {
|
||||
switch_kinematics(0, line);
|
||||
return true;
|
||||
}
|
||||
if (m_code == 429) {
|
||||
switch_kinematics(1, line);
|
||||
return true;
|
||||
}
|
||||
if (m_code == 430) {
|
||||
switch_kinematics(2, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
switch_kinematics(default_kinematics_type, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CanonEventSink::set_g5x_offset(int index, const CncSimPose &offset, int line) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_G5X_OFFSET, line);
|
||||
event.tool = index;
|
||||
@@ -149,6 +234,41 @@ void CanonEventSink::set_xy_rotation(double angle_degrees, int line) {
|
||||
}
|
||||
|
||||
void CanonEventSink::use_length_units(double scale, int line) {
|
||||
use_length_units(scale, line, false);
|
||||
}
|
||||
|
||||
void CanonEventSink::use_length_units(double scale, int line, bool rescale_linear_state) {
|
||||
if (rescale_linear_state && unit_scale_ != 0.0 && scale != unit_scale_) {
|
||||
const double factor = unit_scale_ / scale;
|
||||
// LinuxCNC src/emc/rs274ngc/interp_convert.cc convert_length_units()
|
||||
// rescales linear current axes on G20/G21; A/B/C remain angular.
|
||||
position_.x *= factor;
|
||||
position_.y *= factor;
|
||||
position_.z *= factor;
|
||||
position_.u *= factor;
|
||||
position_.v *= factor;
|
||||
position_.w *= factor;
|
||||
tool_length_offset_.x *= factor;
|
||||
tool_length_offset_.y *= factor;
|
||||
tool_length_offset_.z *= factor;
|
||||
tool_length_offset_.u *= factor;
|
||||
tool_length_offset_.v *= factor;
|
||||
tool_length_offset_.w *= factor;
|
||||
probe_position_.x *= factor;
|
||||
probe_position_.y *= factor;
|
||||
probe_position_.z *= factor;
|
||||
probe_position_.u *= factor;
|
||||
probe_position_.v *= factor;
|
||||
probe_position_.w *= factor;
|
||||
if (has_pending_motion_start_) {
|
||||
pending_motion_start_.x *= factor;
|
||||
pending_motion_start_.y *= factor;
|
||||
pending_motion_start_.z *= factor;
|
||||
pending_motion_start_.u *= factor;
|
||||
pending_motion_start_.v *= factor;
|
||||
pending_motion_start_.w *= factor;
|
||||
}
|
||||
}
|
||||
unit_scale_ = scale;
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_SET_UNITS, line);
|
||||
event.feed = scale;
|
||||
@@ -198,7 +318,7 @@ void CanonEventSink::set_spindle_mode(int spindle, double mode, int line) {
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_COMMENT, line);
|
||||
event.tool = spindle;
|
||||
event.feed = mode;
|
||||
event.reserved = mode == 0.0 ? 970 : 960;
|
||||
event.reserved = mode == 0.0 ? kConstantRpmSpindleModeEvent : kCssSpindleModeEvent;
|
||||
emit(event);
|
||||
}
|
||||
|
||||
@@ -479,16 +599,67 @@ void CanonEventSink::emit(CncSimEvent event) {
|
||||
}
|
||||
|
||||
void CanonEventSink::emit_rtcp_pivot(int line, const CncSimPose &start, const CncSimPose &end) {
|
||||
if (!rtcp_enabled_ || rtcp_tool_length_ == 0.0 || callback_status_ != 0) {
|
||||
if (!rtcp_enabled_ || callback_status_ != 0) {
|
||||
return;
|
||||
}
|
||||
CncSimEvent event = base_event(CNC_SIM_EVENT_RTCP_PIVOT, line);
|
||||
event.start = rtcp_pivot_from_tool_tip(start, rtcp_tool_length_);
|
||||
event.end = rtcp_pivot_from_tool_tip(end, rtcp_tool_length_);
|
||||
const RtcpVector tool = rtcp_tool_vector_from_pose(end, rtcp_tool_length_);
|
||||
event.center.x = tool.x;
|
||||
event.center.y = tool.y;
|
||||
event.center.z = tool.z;
|
||||
if (fiveaxis_configured_ && kinematics_type_ == fiveaxis_kinematics_type_) {
|
||||
const LinuxCncFiveAxisJoints start_joints =
|
||||
linuxcnc_5axis_inverse(start, fiveaxis_pivot_length_);
|
||||
const LinuxCncFiveAxisJoints end_joints =
|
||||
linuxcnc_5axis_inverse(end, fiveaxis_pivot_length_);
|
||||
event.start.x = start_joints.x;
|
||||
event.start.y = start_joints.y;
|
||||
event.start.z = start_joints.z;
|
||||
event.start.b = start_joints.b;
|
||||
event.start.c = start_joints.c;
|
||||
event.start.w = start_joints.w;
|
||||
event.end.x = end_joints.x;
|
||||
event.end.y = end_joints.y;
|
||||
event.end.z = end_joints.z;
|
||||
event.end.b = end_joints.b;
|
||||
event.end.c = end_joints.c;
|
||||
event.end.w = end_joints.w;
|
||||
event.reserved = kinematics_type_;
|
||||
event.dwell_seconds = fiveaxis_pivot_length_;
|
||||
} else if (kinematics_type_ == 1 || kinematics_type_ == 2) {
|
||||
LinuxCncFiveAxisJoints start_joints{};
|
||||
LinuxCncFiveAxisJoints end_joints{};
|
||||
if (kinematics_type_ == 1) {
|
||||
LinuxCncXyzbcTrtParameters parameters = xyzbc_trt_parameters_configured_
|
||||
? xyzbc_trt_parameters_
|
||||
: linuxcnc_xyzbc_trt_default_parameters(rtcp_tool_length_);
|
||||
parameters.tool_offset = rtcp_tool_length_;
|
||||
if (use_xyzac_trt_) {
|
||||
start_joints = linuxcnc_xyzac_trt_inverse(start, parameters);
|
||||
end_joints = linuxcnc_xyzac_trt_inverse(end, parameters);
|
||||
} else {
|
||||
start_joints = linuxcnc_xyzbc_trt_inverse(start, parameters);
|
||||
end_joints = linuxcnc_xyzbc_trt_inverse(end, parameters);
|
||||
}
|
||||
} else {
|
||||
start_joints = linuxcnc_xyzbc_userk_inverse(start);
|
||||
end_joints = linuxcnc_xyzbc_userk_inverse(end);
|
||||
}
|
||||
event.start.x = start_joints.x;
|
||||
event.start.y = start_joints.y;
|
||||
event.start.z = start_joints.z;
|
||||
event.start.a = start_joints.a;
|
||||
event.start.b = start_joints.b;
|
||||
event.start.c = start_joints.c;
|
||||
event.start.w = start_joints.w;
|
||||
event.end.x = end_joints.x;
|
||||
event.end.y = end_joints.y;
|
||||
event.end.z = end_joints.z;
|
||||
event.end.a = end_joints.a;
|
||||
event.end.b = end_joints.b;
|
||||
event.end.c = end_joints.c;
|
||||
event.end.w = end_joints.w;
|
||||
event.reserved = kinematics_type_;
|
||||
event.dwell_seconds = rtcp_tool_length_;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
emit(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "cnc_sim_api.h"
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -12,16 +13,23 @@ public:
|
||||
bool callback_aborted() const;
|
||||
void set_block_delete(bool enabled);
|
||||
void configure_rtcp(bool enabled, double tool_length);
|
||||
void configure_xyzbc_trt(const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
void configure_xyzac_trt(const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
void configure_fiveaxis(double pivot_length, int kinematics_type);
|
||||
void configure_switchkins_remap(int m428_type, int m429_type, int m430_type);
|
||||
void set_tool_length(int h_code, double tool_length);
|
||||
void set_tool_length_offset(const CncSimPose &offset);
|
||||
void apply_tool_length_offset(const CncSimPose &offset);
|
||||
void set_rtcp_state(bool enabled, int h_code, int line);
|
||||
void switch_kinematics(int kinematics_type, bool rtcp_enabled, int line);
|
||||
void switch_kinematics(int kinematics_type, int line);
|
||||
bool can_switch_m_code_kinematics(int m_code) const;
|
||||
bool switch_m_code_kinematics(int m_code, int default_kinematics_type, int line);
|
||||
void set_g5x_offset(int index, const CncSimPose &offset, int line);
|
||||
void set_g92_offset(const CncSimPose &offset, int line);
|
||||
void set_xy_rotation(double angle_degrees, int line);
|
||||
|
||||
void use_length_units(double scale, int line);
|
||||
void use_length_units(double scale, int line, bool rescale_linear_state);
|
||||
void select_plane(int plane, int line);
|
||||
void set_traverse_rate(double rate);
|
||||
void set_feed_rate(double feed, int line);
|
||||
@@ -97,9 +105,19 @@ private:
|
||||
double default_rtcp_tool_length_ = 0.0;
|
||||
double rtcp_tool_length_ = 0.0;
|
||||
int rtcp_h_code_ = 0;
|
||||
LinuxCncXyzbcTrtParameters xyzbc_trt_parameters_{};
|
||||
bool xyzbc_trt_parameters_configured_ = false;
|
||||
bool use_xyzac_trt_ = false;
|
||||
bool fiveaxis_configured_ = false;
|
||||
double fiveaxis_pivot_length_ = 250.0;
|
||||
int fiveaxis_kinematics_type_ = 0;
|
||||
bool switchkins_remap_configured_ = false;
|
||||
int switchkins_m428_type_ = 1;
|
||||
int switchkins_m429_type_ = 0;
|
||||
int switchkins_m430_type_ = 2;
|
||||
CncSimPose tool_length_offset_{};
|
||||
double xy_rotation_degrees_ = 0.0;
|
||||
int kinematics_type_ = 1;
|
||||
int kinematics_type_ = 0;
|
||||
bool feed_override_ = false;
|
||||
bool speed_override_ = false;
|
||||
bool adaptive_feed_ = false;
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
struct CncSimHandle {
|
||||
CncSimDialect dialect = CNC_SIM_DIALECT_LINUXCNC;
|
||||
GcodeBackendKind backend = GcodeBackendKind::Smoke;
|
||||
GcodeBackendKind backend = GcodeBackendKind::LinuxCncRs274;
|
||||
GcodeBackendOptions backend_options;
|
||||
std::string last_error;
|
||||
CanonEventSink sink;
|
||||
};
|
||||
@@ -73,6 +75,116 @@ bool contains_bool_value(const std::string &compact, const char *key, bool *valu
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains_string_value(const std::string &compact, const char *key, const char *value) {
|
||||
const std::string quoted_needle = std::string("\"") + key + "\":\"" + value + "\"";
|
||||
if (compact.find(quoted_needle) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
const std::string prefix_needle = std::string("\"") + key + "\":\"";
|
||||
size_t pos = 0;
|
||||
while ((pos = compact.find(prefix_needle, pos)) != std::string::npos) {
|
||||
pos += prefix_needle.size();
|
||||
const size_t end = compact.find('"', pos);
|
||||
if (end == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
const std::string field_value = compact.substr(pos, end - pos);
|
||||
if (field_value.find(value) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
pos = end + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool find_json_string_value(const std::string &json, const char *key, std::string *value) {
|
||||
const std::string needle = std::string("\"") + key + "\"";
|
||||
size_t pos = 0;
|
||||
while ((pos = json.find(needle, pos)) != std::string::npos) {
|
||||
pos += needle.size();
|
||||
while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
if (pos >= json.size() || json[pos] != ':') {
|
||||
continue;
|
||||
}
|
||||
++pos;
|
||||
while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
if (pos >= json.size() || json[pos] != '"') {
|
||||
continue;
|
||||
}
|
||||
++pos;
|
||||
std::string parsed;
|
||||
bool escaped = false;
|
||||
for (; pos < json.size(); ++pos) {
|
||||
const char ch = json[pos];
|
||||
if (escaped) {
|
||||
switch (ch) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
parsed.push_back(ch);
|
||||
break;
|
||||
case 'n':
|
||||
parsed.push_back('\n');
|
||||
break;
|
||||
case 'r':
|
||||
parsed.push_back('\r');
|
||||
break;
|
||||
case 't':
|
||||
parsed.push_back('\t');
|
||||
break;
|
||||
default:
|
||||
parsed.push_back(ch);
|
||||
break;
|
||||
}
|
||||
escaped = false;
|
||||
} else if (ch == '\\') {
|
||||
escaped = true;
|
||||
} else if (ch == '"') {
|
||||
*value = parsed;
|
||||
return true;
|
||||
} else {
|
||||
parsed.push_back(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool find_json_string_any(const std::string &json, std::string *value, const char *first) {
|
||||
return find_json_string_value(json, first, value);
|
||||
}
|
||||
|
||||
template <typename... Keys>
|
||||
bool find_json_string_any(const std::string &json, std::string *value, const char *first, Keys... rest) {
|
||||
return find_json_string_value(json, first, value) || find_json_string_any(json, value, rest...);
|
||||
}
|
||||
|
||||
bool contains_switchkins_config_alias(const std::string &compact, const char *alias) {
|
||||
return contains_string_value(compact, "switchkins", alias) ||
|
||||
contains_string_value(compact, "remap", alias) ||
|
||||
contains_string_value(compact, "machine", alias) ||
|
||||
contains_string_value(compact, "kinematics", alias) ||
|
||||
contains_string_value(compact, "halfile", alias) ||
|
||||
contains_string_value(compact, "hal_file", alias) ||
|
||||
contains_string_value(compact, "postguihalfile", alias) ||
|
||||
contains_string_value(compact, "postgui_halfile", alias) ||
|
||||
contains_string_value(compact, "postgui_hal_file", alias) ||
|
||||
contains_string_value(compact, "subroutinepath", alias) ||
|
||||
contains_string_value(compact, "subroutine_path", alias) ||
|
||||
contains_string_value(compact, "config", alias) ||
|
||||
contains_string_value(compact, "configpath", alias) ||
|
||||
contains_string_value(compact, "config_path", alias) ||
|
||||
contains_string_value(compact, "ini", alias) ||
|
||||
contains_string_value(compact, "inifile", alias) ||
|
||||
contains_string_value(compact, "inifilename", alias) ||
|
||||
contains_string_value(compact, "ini_file", alias) ||
|
||||
contains_string_value(compact, "ini_file_name", alias);
|
||||
}
|
||||
|
||||
bool find_number_value(const std::string &compact, const char *key, double *value) {
|
||||
const std::string needle = std::string("\"") + key + "\":";
|
||||
const size_t pos = compact.find(needle);
|
||||
@@ -128,6 +240,118 @@ void apply_tool_length_table(CanonEventSink &sink, const std::string &compact) {
|
||||
}
|
||||
}
|
||||
|
||||
bool find_number_any(const std::string &compact, double *value, const char *first) {
|
||||
return find_number_value(compact, first, value);
|
||||
}
|
||||
|
||||
template <typename... Keys>
|
||||
bool find_number_any(const std::string &compact, double *value, const char *first, Keys... rest) {
|
||||
return find_number_value(compact, first, value) || find_number_any(compact, value, rest...);
|
||||
}
|
||||
|
||||
bool contains_bool_any(const std::string &compact, bool *value, const char *first) {
|
||||
return contains_bool_value(compact, first, value);
|
||||
}
|
||||
|
||||
template <typename... Keys>
|
||||
bool contains_bool_any(const std::string &compact, bool *value, const char *first, Keys... rest) {
|
||||
return contains_bool_value(compact, first, value) || contains_bool_any(compact, value, rest...);
|
||||
}
|
||||
|
||||
void apply_xyzbc_trt_config(CanonEventSink &sink, const std::string &compact) {
|
||||
LinuxCncXyzbcTrtParameters parameters = linuxcnc_xyzbc_trt_default_parameters(0.0);
|
||||
bool configured = false;
|
||||
const bool xyzac = compact.find("\"trt\":\"xyzac\"") != std::string::npos ||
|
||||
compact.find("\"kinematics\":\"xyzac-trt\"") != std::string::npos ||
|
||||
compact.find("\"switchkins\":\"xyzac-trt\"") != std::string::npos;
|
||||
const bool xyzbc = compact.find("\"trt\":\"xyzbc\"") != std::string::npos ||
|
||||
compact.find("\"kinematics\":\"xyzbc-trt\"") != std::string::npos ||
|
||||
compact.find("\"switchkins\":\"xyzbc-trt\"") != std::string::npos;
|
||||
|
||||
configured = find_number_any(compact, ¶meters.x_rot_point, "xrotpoint", "x_rot_point", "x-rot-point") ||
|
||||
configured;
|
||||
configured = find_number_any(compact, ¶meters.y_rot_point, "yrotpoint", "y_rot_point", "y-rot-point") ||
|
||||
configured;
|
||||
configured = find_number_any(compact, ¶meters.z_rot_point, "zrotpoint", "z_rot_point", "z-rot-point") ||
|
||||
configured;
|
||||
configured = find_number_any(compact, ¶meters.x_offset, "xoffset", "x_offset", "x-offset") ||
|
||||
configured;
|
||||
configured = find_number_any(compact, ¶meters.y_offset, "yoffset", "y_offset", "y-offset") ||
|
||||
configured;
|
||||
configured = find_number_any(compact, ¶meters.z_offset, "zoffset", "z_offset", "z-offset") ||
|
||||
configured;
|
||||
configured = contains_bool_any(compact,
|
||||
¶meters.conventional_directions,
|
||||
"conventionaldirections",
|
||||
"conventional_directions",
|
||||
"conventional-directions") ||
|
||||
configured;
|
||||
|
||||
if (configured || xyzac || xyzbc) {
|
||||
configured = true;
|
||||
}
|
||||
if (configured && xyzac) {
|
||||
sink.configure_xyzac_trt(parameters);
|
||||
} else if (configured) {
|
||||
sink.configure_xyzbc_trt(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
void apply_fiveaxis_config(CanonEventSink &sink, const std::string &compact) {
|
||||
const bool fiveaxis = compact.find("\"kinematics\":\"5axiskins\"") != std::string::npos ||
|
||||
compact.find("\"switchkins\":\"5axiskins\"") != std::string::npos ||
|
||||
compact.find("\"kinematics\":\"5axis\"") != std::string::npos;
|
||||
double pivot_length = 250.0;
|
||||
const bool has_pivot_length = find_number_any(compact,
|
||||
&pivot_length,
|
||||
"pivotlength",
|
||||
"pivot_length",
|
||||
"pivot-length");
|
||||
double kinematics_type = 0.0;
|
||||
const bool has_kinematics_type = find_number_any(compact,
|
||||
&kinematics_type,
|
||||
"fiveaxiskinematicstype",
|
||||
"fiveaxis_kinematics_type",
|
||||
"fiveaxis-kinematics-type",
|
||||
"kinematicstype",
|
||||
"kinematics_type");
|
||||
if (fiveaxis || has_pivot_length || has_kinematics_type) {
|
||||
sink.configure_fiveaxis(pivot_length, static_cast<int>(kinematics_type));
|
||||
}
|
||||
}
|
||||
|
||||
void apply_switchkins_remap_config(CanonEventSink &sink, const std::string &compact) {
|
||||
struct RemapSource {
|
||||
const char *alias;
|
||||
int m428_type;
|
||||
int m429_type;
|
||||
int m430_type;
|
||||
};
|
||||
|
||||
// Generated from LinuxCNC INI REMAP/SUBROUTINE_PATH entries and the
|
||||
// adjacent remap_subs #<kinstype> assignments.
|
||||
static constexpr RemapSource kSources[] = {
|
||||
#include "linuxcnc_switchkins_remap_table.inc"
|
||||
};
|
||||
|
||||
const RemapSource *matched_source = nullptr;
|
||||
size_t matched_alias_length = 0;
|
||||
for (const RemapSource &source : kSources) {
|
||||
if (contains_switchkins_config_alias(compact, source.alias)) {
|
||||
const size_t alias_length = std::strlen(source.alias);
|
||||
if (alias_length > matched_alias_length) {
|
||||
matched_source = &source;
|
||||
matched_alias_length = alias_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matched_source) {
|
||||
sink.configure_switchkins_remap(matched_source->m428_type,
|
||||
matched_source->m429_type,
|
||||
matched_source->m430_type);
|
||||
}
|
||||
}
|
||||
|
||||
int apply_config(CncSimHandle *handle, const std::string &json) {
|
||||
if (json.empty()) {
|
||||
return 0;
|
||||
@@ -143,6 +367,20 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string ini_file_name;
|
||||
if (find_json_string_any(json,
|
||||
&ini_file_name,
|
||||
"ini",
|
||||
"iniFile",
|
||||
"inifile",
|
||||
"iniFileName",
|
||||
"inifilename",
|
||||
"ini_file",
|
||||
"ini_file_name",
|
||||
"INI_FILE_NAME")) {
|
||||
handle->backend_options.ini_file_name = ini_file_name;
|
||||
}
|
||||
|
||||
bool rtcp_enabled = false;
|
||||
double tool_length = 0.0;
|
||||
const bool has_rtcp_enabled = contains_bool_value(compact, "rtcp", &rtcp_enabled) ||
|
||||
@@ -158,6 +396,9 @@ int apply_config(CncSimHandle *handle, const std::string &json) {
|
||||
handle->sink.set_block_delete(block_delete);
|
||||
}
|
||||
apply_tool_length_table(handle->sink, compact);
|
||||
apply_switchkins_remap_config(handle->sink, compact);
|
||||
apply_xyzbc_trt_config(handle->sink, compact);
|
||||
apply_fiveaxis_config(handle->sink, compact);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -223,7 +464,12 @@ int cnc_sim_parse_program(CncSimHandle *handle, const char *program, size_t prog
|
||||
}
|
||||
|
||||
handle->last_error.clear();
|
||||
const int rc = parse_gcode_with_backend(handle->backend, handle->sink, program, program_len, &handle->last_error);
|
||||
const int rc = parse_gcode_with_backend(handle->backend,
|
||||
handle->sink,
|
||||
program,
|
||||
program_len,
|
||||
handle->backend_options,
|
||||
&handle->last_error);
|
||||
if (rc != 0 && handle->last_error.empty()) {
|
||||
handle->last_error = "program parse failed";
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
|
||||
#include "linuxcnc_rs274_backend.h"
|
||||
#endif
|
||||
#ifdef CNC_SIM_ENABLE_SMOKE_BACKEND
|
||||
#include "smoke_gcode_parser.h"
|
||||
#endif
|
||||
|
||||
const char *gcode_backend_name(GcodeBackendKind backend) {
|
||||
switch (backend) {
|
||||
@@ -20,15 +22,23 @@ int parse_gcode_with_backend(GcodeBackendKind backend,
|
||||
CanonEventSink &sink,
|
||||
const char *program,
|
||||
size_t program_len,
|
||||
const GcodeBackendOptions &options,
|
||||
std::string *error) {
|
||||
switch (backend) {
|
||||
case GcodeBackendKind::Smoke: {
|
||||
#ifdef CNC_SIM_ENABLE_SMOKE_BACKEND
|
||||
SmokeGcodeParser parser(sink);
|
||||
return parser.parse(program, program_len, error);
|
||||
#else
|
||||
if (error) {
|
||||
*error = "smoke backend is not compiled into this build";
|
||||
}
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
case GcodeBackendKind::LinuxCncRs274:
|
||||
#ifdef CNC_SIM_ENABLE_LINUXCNC_RS274_BACKEND
|
||||
return parse_linuxcnc_rs274_backend(sink, program, program_len, error);
|
||||
return parse_linuxcnc_rs274_backend(sink, program, program_len, options, error);
|
||||
#else
|
||||
if (error) {
|
||||
*error = "linuxcnc-rs274 backend is not compiled into this build";
|
||||
|
||||
@@ -10,11 +10,15 @@ enum class GcodeBackendKind {
|
||||
LinuxCncRs274,
|
||||
};
|
||||
|
||||
struct GcodeBackendOptions {
|
||||
std::string ini_file_name;
|
||||
};
|
||||
|
||||
const char *gcode_backend_name(GcodeBackendKind backend);
|
||||
|
||||
int parse_gcode_with_backend(GcodeBackendKind backend,
|
||||
CanonEventSink &sink,
|
||||
const char *program,
|
||||
size_t program_len,
|
||||
const GcodeBackendOptions &options,
|
||||
std::string *error);
|
||||
|
||||
|
||||
266
core/src/linuxcnc_5axiskins_adapter.c
Normal file
266
core/src/linuxcnc_5axiskins_adapter.c
Normal file
@@ -0,0 +1,266 @@
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_RTAPI_CTYPE_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define SWITCHKINS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
#define TO_RAD (PM_PI / 180.0)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define EMCMOT_MAX_AXIS 9
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
typedef int (*KF)(const double *joint,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
typedef int (*KI)(const struct EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static int cnc_sim_axis_idx_for_jno[EMCMOT_MAX_JOINTS];
|
||||
static int cnc_sim_max_joints;
|
||||
|
||||
void cnc_sim_5axis_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_5axis_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_5axis_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_map_coordinates_to_jnumbers(const char *coordinates,
|
||||
const int max_joints,
|
||||
const int allow_duplicates,
|
||||
int axis_idx_for_jno[]) {
|
||||
(void)allow_duplicates;
|
||||
const char *letters = "XYZABCUVW";
|
||||
int jno = 0;
|
||||
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
|
||||
axis_idx_for_jno[i] = -1;
|
||||
cnc_sim_axis_idx_for_jno[i] = -1;
|
||||
}
|
||||
while (*coordinates) {
|
||||
const char *found = strchr(letters, toupper((unsigned char)*coordinates));
|
||||
if (!found || jno >= max_joints) {
|
||||
return -1;
|
||||
}
|
||||
axis_idx_for_jno[jno++] = (int)(found - letters);
|
||||
++coordinates;
|
||||
}
|
||||
cnc_sim_max_joints = jno;
|
||||
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
|
||||
cnc_sim_axis_idx_for_jno[i] = axis_idx_for_jno[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_position_to_mapped_joints(const int max_joints, const EmcPose *pos, double *joints) {
|
||||
for (int jno = 0; jno < max_joints; ++jno) {
|
||||
switch (cnc_sim_axis_idx_for_jno[jno]) {
|
||||
case 0: joints[jno] = pos->tran.x; break;
|
||||
case 1: joints[jno] = pos->tran.y; break;
|
||||
case 2: joints[jno] = pos->tran.z; break;
|
||||
case 3: joints[jno] = pos->a; break;
|
||||
case 4: joints[jno] = pos->b; break;
|
||||
case 5: joints[jno] = pos->c; break;
|
||||
case 6: joints[jno] = pos->u; break;
|
||||
case 7: joints[jno] = pos->v; break;
|
||||
case 8: joints[jno] = pos->w; break;
|
||||
default: joints[jno] = 0.0; break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_identityKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_identityKinematicsInverse(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_userkKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_5axis_userkKinematicsInverse(const EmcPose *pos,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)pos;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_5axis_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_5axis_rtapi_print_msg
|
||||
#define hal_pin_float_newf cnc_sim_5axis_hal_pin_float_newf
|
||||
#define map_coordinates_to_jnumbers cnc_sim_5axis_map_coordinates_to_jnumbers
|
||||
#define position_to_mapped_joints cnc_sim_5axis_position_to_mapped_joints
|
||||
#define identityKinematicsSetup cnc_sim_5axis_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_5axis_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_5axis_identityKinematicsInverse
|
||||
#define userkKinematicsSetup cnc_sim_5axis_userkKinematicsSetup
|
||||
#define userkKinematicsForward cnc_sim_5axis_userkKinematicsForward
|
||||
#define userkKinematicsInverse cnc_sim_5axis_userkKinematicsInverse
|
||||
#define switchkinsSetup cnc_sim_5axis_switchkinsSetup
|
||||
#define haldata cnc_sim_5axis_haldata
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_5axis_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/5axiskins.c"
|
||||
#undef hal_malloc
|
||||
#undef haldata
|
||||
#undef switchkinsSetup
|
||||
#undef userkKinematicsInverse
|
||||
#undef userkKinematicsForward
|
||||
#undef userkKinematicsSetup
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef position_to_mapped_joints
|
||||
#undef map_coordinates_to_jnumbers
|
||||
#undef hal_pin_float_newf
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_5axiskins_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "5axiskins";
|
||||
static char halprefix[] = "5axiskins";
|
||||
static char required_coordinates[] = "XYZBCW";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.required_coordinates = required_coordinates;
|
||||
kp.max_joints = EMCMOT_MAX_JOINTS;
|
||||
kp.allow_duplicates = 1;
|
||||
return fiveaxis_KinematicsSetup(0, "XYZBCW", &kp);
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_5axiskins_set_pivot_length(double pivot_length) {
|
||||
*cnc_sim_5axis_haldata->pivot_length = pivot_length;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_5axiskins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return fiveaxis_KinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_5axiskins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return fiveaxis_KinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
122
core/src/linuxcnc_5axiskins_adapter.cpp
Normal file
122
core/src/linuxcnc_5axiskins_adapter.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "linuxcnc_5axiskins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_5axiskins_setup(void);
|
||||
void cnc_sim_linuxcnc_5axiskins_set_pivot_length(double pivot_length);
|
||||
int cnc_sim_linuxcnc_5axiskins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_5axiskins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_5axiskins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.b;
|
||||
out[4] = joints.c;
|
||||
out[5] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncFiveAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncFiveAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.b = joints[3];
|
||||
out.c = joints[4];
|
||||
out.w = joints[5];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_5axiskins_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
double pivot_length,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_5axiskins_set_pivot_length(pivot_length);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_5axiskins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_5axiskins_inverse(const CncSimPose &pose,
|
||||
double pivot_length,
|
||||
LinuxCncFiveAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_5axiskins_set_pivot_length(pivot_length);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_5axiskins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
10
core/src/linuxcnc_5axiskins_adapter.h
Normal file
10
core/src/linuxcnc_5axiskins_adapter.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_5axiskins_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
double pivot_length,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_5axiskins_inverse(const CncSimPose &pose,
|
||||
double pivot_length,
|
||||
LinuxCncFiveAxisJoints *joints);
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kToolLengthOffsetEvent = 430;
|
||||
|
||||
CanonEventSink *active_sink = nullptr;
|
||||
int active_line = 0;
|
||||
bool flood_on = false;
|
||||
@@ -26,6 +28,19 @@ double motion_control_tolerance = 0.0;
|
||||
double naivecam_tolerance = 0.0;
|
||||
std::string parameter_file_name = "rs274ngc.var";
|
||||
|
||||
void load_nonrandom_tool_to_spindle(int pocket) {
|
||||
// LinuxCNC Task::load_tool() uses pocket 0 as the non-random
|
||||
// toolchanger unload handshake. Do not eagerly mirror nonzero
|
||||
// loads here; the source-linked interpreter observes its own
|
||||
// post-canonical state before external task-side load completion.
|
||||
if (pocket == 0) {
|
||||
CANON_TOOL_TABLE unloaded = tooldata_entry_init();
|
||||
unloaded.toolno = 0;
|
||||
unloaded.pocketno = 0;
|
||||
tooldata_put(unloaded, 0);
|
||||
}
|
||||
}
|
||||
|
||||
CncSimPose make_pose(double x, double y, double z,
|
||||
double a, double b, double c,
|
||||
double u, double v, double w) {
|
||||
@@ -178,7 +193,7 @@ void INIT_CANON() {
|
||||
void USE_LENGTH_UNITS(CANON_UNITS units) {
|
||||
trace_call("USE_LENGTH_UNITS");
|
||||
if (active_sink) {
|
||||
active_sink->use_length_units(units_to_scale(units), event_line());
|
||||
active_sink->use_length_units(units_to_scale(units), event_line(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +211,10 @@ void SET_FEED_RATE(double rate) {
|
||||
}
|
||||
}
|
||||
|
||||
void SET_SPINDLE_SPEED(int, double speed) {
|
||||
void SET_SPINDLE_SPEED(int spindle, double speed) {
|
||||
trace_call("SET_SPINDLE_SPEED");
|
||||
if (active_sink) {
|
||||
active_sink->set_spindle_speed(speed, event_line());
|
||||
active_sink->set_spindle_speed(spindle, speed, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +228,10 @@ void SELECT_TOOL(int tool) {
|
||||
void CHANGE_TOOL() {
|
||||
trace_call("CHANGE_TOOL");
|
||||
if (active_sink) {
|
||||
const int selected_tool = active_sink->selected_tool();
|
||||
if (selected_tool == 0) {
|
||||
load_nonrandom_tool_to_spindle(0);
|
||||
}
|
||||
active_sink->change_tool(event_line());
|
||||
}
|
||||
}
|
||||
@@ -383,6 +402,15 @@ void SET_MOTION_CONTROL_MODE(CANON_MOTION_MODE mode, double tolerance) {
|
||||
|
||||
void SET_NAIVECAM_TOLERANCE(double tolerance) {
|
||||
naivecam_tolerance = tolerance;
|
||||
if (active_sink) {
|
||||
CncSimEvent event{};
|
||||
event.version = 1;
|
||||
event.type = CNC_SIM_EVENT_COMMENT;
|
||||
event.line = event_line();
|
||||
event.feed = tolerance;
|
||||
event.reserved = 641;
|
||||
active_sink->emit_raw(event);
|
||||
}
|
||||
}
|
||||
|
||||
void SET_CUTTER_RADIUS_COMPENSATION(double) {
|
||||
@@ -458,21 +486,21 @@ void SET_SPINDLE_MODE(int spindle, double mode) {
|
||||
void SPINDLE_RETRACT_TRAVERSE() {
|
||||
}
|
||||
|
||||
void START_SPINDLE_CLOCKWISE(int, int) {
|
||||
void START_SPINDLE_CLOCKWISE(int spindle, int) {
|
||||
if (active_sink) {
|
||||
active_sink->start_spindle(1, event_line());
|
||||
active_sink->start_spindle(spindle, 1, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
void START_SPINDLE_COUNTERCLOCKWISE(int, int) {
|
||||
void START_SPINDLE_COUNTERCLOCKWISE(int spindle, int) {
|
||||
if (active_sink) {
|
||||
active_sink->start_spindle(-1, event_line());
|
||||
active_sink->start_spindle(spindle, -1, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
void STOP_SPINDLE_TURNING(int) {
|
||||
void STOP_SPINDLE_TURNING(int spindle) {
|
||||
if (active_sink) {
|
||||
active_sink->stop_spindle(event_line());
|
||||
active_sink->stop_spindle(spindle, event_line());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,13 +543,14 @@ void USE_TOOL_LENGTH_OFFSET(const EmcPose &offset) {
|
||||
event.version = 1;
|
||||
event.type = CNC_SIM_EVENT_COMMENT;
|
||||
event.line = event_line();
|
||||
event.reserved = 430;
|
||||
event.reserved = kToolLengthOffsetEvent;
|
||||
event.start = tool_offset;
|
||||
active_sink->emit_raw(event);
|
||||
}
|
||||
|
||||
void CHANGE_TOOL_NUMBER(int number) {
|
||||
if (active_sink) {
|
||||
load_nonrandom_tool_to_spindle(number);
|
||||
active_sink->select_tool(number);
|
||||
active_sink->change_tool(event_line());
|
||||
}
|
||||
@@ -753,11 +782,16 @@ int GET_EXTERNAL_FLOOD() {
|
||||
}
|
||||
|
||||
CANON_UNITS GET_EXTERNAL_LENGTH_UNIT_TYPE() {
|
||||
return active_sink && active_sink->unit_scale() == 25.4 ? CANON_UNITS_INCHES : CANON_UNITS_MM;
|
||||
// LinuxCNC src/emc/task/emccanon.cc derives this from INI machine/user
|
||||
// units, not from the active G20/G21 program units.
|
||||
return CANON_UNITS_MM;
|
||||
}
|
||||
|
||||
double GET_EXTERNAL_LENGTH_UNITS() {
|
||||
return active_sink ? active_sink->unit_scale() : 1.0;
|
||||
// LinuxCNC src/emc/task/emccanon.cc returns traj.linearUnits here:
|
||||
// external/user units per internal millimeter. The simulator has no INI
|
||||
// machine-units bridge yet, so the source-linked default is metric.
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double GET_EXTERNAL_ANGLE_UNITS() {
|
||||
|
||||
127
core/src/linuxcnc_corexykins_adapter.c
Normal file
127
core/src/linuxcnc_corexykins_adapter.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
typedef int hal_s32_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_corexykins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_corexykins_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_corexykins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_corexykins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_corexykins_hal_init
|
||||
#define hal_malloc(size) ((struct data *)cnc_sim_corexykins_hal_malloc(size))
|
||||
#define hal_ready cnc_sim_corexykins_hal_ready
|
||||
#define hal_exit cnc_sim_corexykins_hal_exit
|
||||
#define kinematicsType cnc_sim_corexykins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_corexykins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_corexykins_kinematicsInverse
|
||||
#define kinematicsHome cnc_sim_corexykins_kinematicsHome
|
||||
#define kinematicsSwitchable cnc_sim_corexykins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_corexykins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_corexykins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_corexykins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_corexykins_comp_id
|
||||
#define data cnc_sim_corexykins_data
|
||||
#include "../../../linuxcnc/src/emc/kinematics/corexykins.c"
|
||||
#undef data
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsHome
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_corexykins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_corexykins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_corexykins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_corexykins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
104
core/src/linuxcnc_corexykins_adapter.cpp
Normal file
104
core/src/linuxcnc_corexykins_adapter.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "linuxcnc_corexykins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_corexykins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_corexykins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_corexykins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_corexykins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_corexykins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_corexykins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_corexykins_adapter.h
Normal file
6
core/src/linuxcnc_corexykins_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_corexykins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_corexykins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
|
||||
117
core/src/linuxcnc_cubic_adapter.c
Normal file
117
core/src/linuxcnc_cubic_adapter.c
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
|
||||
typedef struct {
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double d;
|
||||
} CUBIC_COEFF;
|
||||
|
||||
typedef struct {
|
||||
int configured;
|
||||
double segmentTime;
|
||||
int interpolationRate;
|
||||
double interpolationTime;
|
||||
double interpolationIncrement;
|
||||
double x0, x1, x2, x3;
|
||||
double wp0, wp1;
|
||||
double velp0, velp1;
|
||||
int filled;
|
||||
int needNextPoint;
|
||||
CUBIC_COEFF coeff;
|
||||
} CUBIC_STRUCT;
|
||||
|
||||
#define CUBIC_H
|
||||
#define cubicInit cnc_sim_cubic_cubicInit
|
||||
#define cubicSetSegmentTime cnc_sim_cubic_cubicSetSegmentTime
|
||||
#define cubicGetSegmentTime cnc_sim_cubic_cubicGetSegmentTime
|
||||
#define cubicSetInterpolationRate cnc_sim_cubic_cubicSetInterpolationRate
|
||||
#define cubicGetInterpolationRate cnc_sim_cubic_cubicGetInterpolationRate
|
||||
#define cubicAddPoint cnc_sim_cubic_cubicAddPoint
|
||||
#define cubicOffset cnc_sim_cubic_cubicOffset
|
||||
#define cubicGetInterpolationIncrement cnc_sim_cubic_cubicGetInterpolationIncrement
|
||||
#define cubicGetCubicCoeff cnc_sim_cubic_cubicGetCubicCoeff
|
||||
#define cubicFilled cnc_sim_cubic_cubicFilled
|
||||
#define cubicInterpolate cnc_sim_cubic_cubicInterpolate
|
||||
#define cubicNeedNextPoint cnc_sim_cubic_cubicNeedNextPoint
|
||||
#define cubicDrain cnc_sim_cubic_cubicDrain
|
||||
int cubicInit(CUBIC_STRUCT *ci);
|
||||
int cubicSetSegmentTime(CUBIC_STRUCT *ci, double time);
|
||||
double cubicGetSegmentTime(CUBIC_STRUCT *ci);
|
||||
int cubicSetInterpolationRate(CUBIC_STRUCT *ci, int rate);
|
||||
int cubicGetInterpolationRate(CUBIC_STRUCT *ci);
|
||||
int cubicAddPoint(CUBIC_STRUCT *ci, double point);
|
||||
int cubicOffset(CUBIC_STRUCT *ci, double offset);
|
||||
double cubicGetInterpolationIncrement(CUBIC_STRUCT *ci);
|
||||
CUBIC_COEFF cubicGetCubicCoeff(CUBIC_STRUCT *ci);
|
||||
int cubicFilled(CUBIC_STRUCT *ci);
|
||||
double cubicInterpolate(CUBIC_STRUCT *ci, double *x, double *v, double *a, double *j);
|
||||
int cubicNeedNextPoint(CUBIC_STRUCT *ci);
|
||||
int cubicDrain(CUBIC_STRUCT *ci);
|
||||
#include "../../../linuxcnc/src/emc/kinematics/cubic.c"
|
||||
#undef cubicDrain
|
||||
#undef cubicNeedNextPoint
|
||||
#undef cubicInterpolate
|
||||
#undef cubicFilled
|
||||
#undef cubicGetCubicCoeff
|
||||
#undef cubicGetInterpolationIncrement
|
||||
#undef cubicOffset
|
||||
#undef cubicAddPoint
|
||||
#undef cubicGetInterpolationRate
|
||||
#undef cubicSetInterpolationRate
|
||||
#undef cubicGetSegmentTime
|
||||
#undef cubicSetSegmentTime
|
||||
#undef cubicInit
|
||||
#undef CUBIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_linuxcnc_cubic_second_segment_samples(double *x,
|
||||
double *v,
|
||||
double *a,
|
||||
double *j,
|
||||
int sample_count) {
|
||||
if (!x || !v || !a || !j || sample_count != 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CUBIC_STRUCT cubic;
|
||||
if (cnc_sim_cubic_cubicInit(&cubic) != 0 ||
|
||||
cnc_sim_cubic_cubicSetSegmentTime(&cubic, 1.0) != 0 ||
|
||||
cnc_sim_cubic_cubicSetInterpolationRate(&cubic, 4) != 0 ||
|
||||
cnc_sim_cubic_cubicAddPoint(&cubic, 0.0) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
cnc_sim_cubic_cubicInterpolate(&cubic, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
if (!cnc_sim_cubic_cubicNeedNextPoint(&cubic) ||
|
||||
cnc_sim_cubic_cubicAddPoint(&cubic, 10.0) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sample_count; ++i) {
|
||||
x[i] = cnc_sim_cubic_cubicInterpolate(&cubic, &x[i], &v[i], &a[i], &j[i]);
|
||||
}
|
||||
|
||||
return cnc_sim_cubic_cubicNeedNextPoint(&cubic) ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_cubic_rejects_invalid_configuration(void) {
|
||||
CUBIC_STRUCT cubic;
|
||||
return cnc_sim_cubic_cubicInit(&cubic) == 0 &&
|
||||
cnc_sim_cubic_cubicSetSegmentTime(&cubic, 0.0) != 0 &&
|
||||
cnc_sim_cubic_cubicSetInterpolationRate(&cubic, 0) != 0 &&
|
||||
cnc_sim_cubic_cubicAddPoint(&cubic, 1.0) != 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
36
core/src/linuxcnc_cubic_adapter.cpp
Normal file
36
core/src/linuxcnc_cubic_adapter.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "linuxcnc_cubic_adapter.h"
|
||||
|
||||
extern "C" {
|
||||
int cnc_sim_linuxcnc_cubic_second_segment_samples(double *x,
|
||||
double *v,
|
||||
double *a,
|
||||
double *j,
|
||||
int sample_count);
|
||||
int cnc_sim_linuxcnc_cubic_rejects_invalid_configuration(void);
|
||||
}
|
||||
|
||||
bool linuxcnc_cubic_source_second_segment_samples(LinuxCncCubicSample *samples, int sample_count) {
|
||||
if (!samples || sample_count != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double x[4] = {};
|
||||
double v[4] = {};
|
||||
double a[4] = {};
|
||||
double j[4] = {};
|
||||
if (cnc_sim_linuxcnc_cubic_second_segment_samples(x, v, a, j, sample_count) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sample_count; ++i) {
|
||||
samples[i].x = x[i];
|
||||
samples[i].v = v[i];
|
||||
samples[i].a = a[i];
|
||||
samples[i].j = j[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_cubic_source_rejects_invalid_configuration() {
|
||||
return cnc_sim_linuxcnc_cubic_rejects_invalid_configuration() != 0;
|
||||
}
|
||||
11
core/src/linuxcnc_cubic_adapter.h
Normal file
11
core/src/linuxcnc_cubic_adapter.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
struct LinuxCncCubicSample {
|
||||
double x;
|
||||
double v;
|
||||
double a;
|
||||
double j;
|
||||
};
|
||||
|
||||
bool linuxcnc_cubic_source_second_segment_samples(LinuxCncCubicSample *samples, int sample_count);
|
||||
bool linuxcnc_cubic_source_rejects_invalid_configuration();
|
||||
223
core/src/linuxcnc_genhexkins_adapter.c
Normal file
223
core/src/linuxcnc_genhexkins_adapter.c
Normal file
@@ -0,0 +1,223 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define SWITCHKINS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define RTAPI_MSG_INFO 2
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_bit_t;
|
||||
typedef uint32_t hal_u32_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
#include "../../../linuxcnc/src/libnml/posemath/posemath.h"
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
typedef int (*KF)(const double *joint,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
typedef int (*KI)(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cnc_sim_genhex_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_genhex_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_hal_pin_u32_newf(hal_pin_dir_t dir,
|
||||
hal_u32_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_hal_pin_bit_newf(hal_pin_dir_t dir,
|
||||
hal_bit_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_identityKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_identityKinematicsInverse(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_userkKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genhex_userkKinematicsInverse(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define rtapi_print_msg cnc_sim_genhex_rtapi_print_msg
|
||||
#define hal_pin_float_newf cnc_sim_genhex_hal_pin_float_newf
|
||||
#define hal_pin_u32_newf cnc_sim_genhex_hal_pin_u32_newf
|
||||
#define hal_pin_bit_newf cnc_sim_genhex_hal_pin_bit_newf
|
||||
#define identityKinematicsSetup cnc_sim_genhex_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_genhex_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_genhex_identityKinematicsInverse
|
||||
#define userkKinematicsSetup cnc_sim_genhex_userkKinematicsSetup
|
||||
#define userkKinematicsForward cnc_sim_genhex_userkKinematicsForward
|
||||
#define userkKinematicsInverse cnc_sim_genhex_userkKinematicsInverse
|
||||
#define switchkinsSetup cnc_sim_genhex_switchkinsSetup
|
||||
#define haldata cnc_sim_genhex_haldata
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_genhex_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/genhexkins.c"
|
||||
#undef hal_malloc
|
||||
#undef haldata
|
||||
#undef switchkinsSetup
|
||||
#undef userkKinematicsInverse
|
||||
#undef userkKinematicsForward
|
||||
#undef userkKinematicsSetup
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef hal_pin_bit_newf
|
||||
#undef hal_pin_u32_newf
|
||||
#undef hal_pin_float_newf
|
||||
#undef rtapi_print_msg
|
||||
|
||||
int cnc_sim_linuxcnc_genhexkins_setup(void) {
|
||||
kparms kp;
|
||||
memset(&kp, 0, sizeof(kp));
|
||||
static char kinsname[] = "genhexkins";
|
||||
static char halprefix[] = "genhexkins";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.max_joints = NUM_STRUTS;
|
||||
return genhexKinematicsSetup(0, "XYZABC", &kp);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_genhexkins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return genhexKinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_genhexkins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return genhexKinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
96
core/src/linuxcnc_genhexkins_adapter.cpp
Normal file
96
core/src/linuxcnc_genhexkins_adapter.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "linuxcnc_genhexkins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_genhexkins_setup(void);
|
||||
int cnc_sim_linuxcnc_genhexkins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_genhexkins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_genhexkins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_genhexkins_source_forward(const LinuxCncGenhexJoints &joints,
|
||||
const CncSimPose &initial_pose,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[6];
|
||||
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
|
||||
EmcPose emc_pose = to_emc_pose(initial_pose);
|
||||
if (cnc_sim_linuxcnc_genhexkins_forward(raw_joints, &emc_pose) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(emc_pose);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_genhexkins_source_inverse(const CncSimPose &pose, LinuxCncGenhexJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose emc_pose = to_emc_pose(pose);
|
||||
double raw_joints[6] = {};
|
||||
if (cnc_sim_linuxcnc_genhexkins_inverse(&emc_pose, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
|
||||
return true;
|
||||
}
|
||||
8
core/src/linuxcnc_genhexkins_adapter.h
Normal file
8
core/src/linuxcnc_genhexkins_adapter.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_genhexkins_source_forward(const LinuxCncGenhexJoints &joints,
|
||||
const CncSimPose &initial_pose,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_genhexkins_source_inverse(const CncSimPose &pose, LinuxCncGenhexJoints *joints);
|
||||
206
core/src/linuxcnc_genserfuncs_adapter.c
Normal file
206
core/src/linuxcnc_genserfuncs_adapter.c
Normal file
@@ -0,0 +1,206 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef unsigned int hal_u32_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cnc_sim_genser_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_genser_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_genser_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_genser_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genser_hal_pin_u32_newf(hal_pin_dir_t dir,
|
||||
hal_u32_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_genser_hal_pin_s32_newf(hal_pin_dir_t dir,
|
||||
hal_s32_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_genser_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_genser_rtapi_print_msg
|
||||
#define hal_pin_float_newf cnc_sim_genser_hal_pin_float_newf
|
||||
#define hal_pin_u32_newf cnc_sim_genser_hal_pin_u32_newf
|
||||
#define hal_pin_s32_newf cnc_sim_genser_hal_pin_s32_newf
|
||||
#define pm_sincos cnc_sim_genser_pm_sincos
|
||||
#include "../../../linuxcnc/src/libnml/posemath/sincos.c"
|
||||
#include "../../../linuxcnc/src/libnml/posemath/gomath.c"
|
||||
#define hal_malloc(size) cnc_sim_genser_hal_malloc(size)
|
||||
#include "../../../linuxcnc/src/emc/kinematics/genserfuncs.c"
|
||||
#undef hal_malloc
|
||||
#undef pm_sincos
|
||||
#undef hal_pin_s32_newf
|
||||
#undef hal_pin_u32_newf
|
||||
#undef hal_pin_float_newf
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_genserfuncs_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "genserkins";
|
||||
static char halprefix[] = "genserkins";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.max_joints = 6;
|
||||
return genserKinematicsSetup(0, "XYZABC", &kp);
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_genserfuncs_set_parameters(const double *a,
|
||||
const double *alpha,
|
||||
const double *d,
|
||||
const int *unrotate,
|
||||
int max_iterations) {
|
||||
for (int i = 0; i < GENSER_MAX_JOINTS; ++i) {
|
||||
*haldata->a[i] = a[i];
|
||||
*haldata->alpha[i] = alpha[i];
|
||||
*haldata->d[i] = d[i];
|
||||
*haldata->unrotate[i] = unrotate[i];
|
||||
}
|
||||
*haldata->max_iterations = (hal_u32_t)max_iterations;
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_genserfuncs_default_parameters(double *a,
|
||||
double *alpha,
|
||||
double *d,
|
||||
int *unrotate,
|
||||
int *max_iterations) {
|
||||
const double default_a[GENSER_MAX_JOINTS] = {
|
||||
DEFAULT_A1,
|
||||
DEFAULT_A2,
|
||||
DEFAULT_A3,
|
||||
DEFAULT_A4,
|
||||
DEFAULT_A5,
|
||||
DEFAULT_A6,
|
||||
};
|
||||
const double default_alpha[GENSER_MAX_JOINTS] = {
|
||||
DEFAULT_ALPHA1,
|
||||
DEFAULT_ALPHA2,
|
||||
DEFAULT_ALPHA3,
|
||||
DEFAULT_ALPHA4,
|
||||
DEFAULT_ALPHA5,
|
||||
DEFAULT_ALPHA6,
|
||||
};
|
||||
const double default_d[GENSER_MAX_JOINTS] = {
|
||||
DEFAULT_D1,
|
||||
DEFAULT_D2,
|
||||
DEFAULT_D3,
|
||||
DEFAULT_D4,
|
||||
DEFAULT_D5,
|
||||
DEFAULT_D6,
|
||||
};
|
||||
|
||||
for (int i = 0; i < GENSER_MAX_JOINTS; ++i) {
|
||||
a[i] = default_a[i];
|
||||
alpha[i] = default_alpha[i];
|
||||
d[i] = default_d[i];
|
||||
unrotate[i] = 0;
|
||||
}
|
||||
*max_iterations = GENSER_DEFAULT_MAX_ITERATIONS;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_genserfuncs_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return genserKinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_genserfuncs_inverse(const EmcPose *pos, double *joints, int *iterations) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
const int result = genserKinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
if (iterations) {
|
||||
*iterations = genser_kin_inv_iterations(KINS_PTR);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
166
core/src/linuxcnc_genserfuncs_adapter.cpp
Normal file
166
core/src/linuxcnc_genserfuncs_adapter.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "linuxcnc_genserfuncs_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_genserfuncs_setup(void);
|
||||
void cnc_sim_linuxcnc_genserfuncs_set_parameters(const double *a,
|
||||
const double *alpha,
|
||||
const double *d,
|
||||
const int *unrotate,
|
||||
int max_iterations);
|
||||
void cnc_sim_linuxcnc_genserfuncs_default_parameters(double *a,
|
||||
double *alpha,
|
||||
double *d,
|
||||
int *unrotate,
|
||||
int *max_iterations);
|
||||
int cnc_sim_linuxcnc_genserfuncs_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_genserfuncs_inverse(const EmcPose *pos, double *joints, int *iterations);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_genserfuncs_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void apply_parameters(const LinuxCncGenserParameters ¶meters, int max_iterations) {
|
||||
cnc_sim_linuxcnc_genserfuncs_set_parameters(parameters.a,
|
||||
parameters.alpha,
|
||||
parameters.d,
|
||||
parameters.unrotate,
|
||||
max_iterations);
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_genserfuncs_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters, 100);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_genserfuncs_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_genserfuncs_source_default_parameters(LinuxCncGenserParameters *parameters,
|
||||
int *max_iterations) {
|
||||
if (!parameters) {
|
||||
return false;
|
||||
}
|
||||
int raw_max_iterations = 0;
|
||||
cnc_sim_linuxcnc_genserfuncs_default_parameters(parameters->a,
|
||||
parameters->alpha,
|
||||
parameters->d,
|
||||
parameters->unrotate,
|
||||
&raw_max_iterations);
|
||||
if (max_iterations) {
|
||||
*max_iterations = raw_max_iterations;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_genserfuncs_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
int max_iterations,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *iterations) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters, max_iterations);
|
||||
double raw_joints[16];
|
||||
to_joints(joint_estimate, raw_joints);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
if (cnc_sim_linuxcnc_genserfuncs_inverse(&in, raw_joints, iterations) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
15
core/src/linuxcnc_genserfuncs_adapter.h
Normal file
15
core/src/linuxcnc_genserfuncs_adapter.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_genserfuncs_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_genserfuncs_source_default_parameters(LinuxCncGenserParameters *parameters,
|
||||
int *max_iterations);
|
||||
bool linuxcnc_genserfuncs_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
int max_iterations,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *iterations);
|
||||
116
core/src/linuxcnc_kins_util_adapter.c
Normal file
116
core/src/linuxcnc_kins_util_adapter.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define EMCMOT_MAX_AXIS 9
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cnc_sim_kins_util_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_kins_util_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
KINEMATICS_TYPE kinematicsType(void) {
|
||||
return KINEMATICS_BOTH;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_kins_util_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_kins_util_rtapi_print_msg
|
||||
#define map_coordinates_to_jnumbers cnc_sim_kins_util_map_coordinates_to_jnumbers
|
||||
#define mapped_joints_to_position cnc_sim_kins_util_mapped_joints_to_position
|
||||
#define position_to_mapped_joints cnc_sim_kins_util_position_to_mapped_joints
|
||||
#define identityKinematicsSetup cnc_sim_kins_util_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_kins_util_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_kins_util_identityKinematicsInverse
|
||||
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef position_to_mapped_joints
|
||||
#undef mapped_joints_to_position
|
||||
#undef map_coordinates_to_jnumbers
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_kins_util_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "kins_util_identity";
|
||||
static char halprefix[] = "identity";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.max_joints = EMCMOT_MAX_JOINTS;
|
||||
kp.allow_duplicates = 0;
|
||||
return cnc_sim_kins_util_identityKinematicsSetup(0, "XYZABCUVW", &kp);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_kins_util_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_kins_util_identityKinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_kins_util_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_kins_util_identityKinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
121
core/src/linuxcnc_kins_util_adapter.cpp
Normal file
121
core/src/linuxcnc_kins_util_adapter.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "linuxcnc_kins_util_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_kins_util_setup(void);
|
||||
int cnc_sim_linuxcnc_kins_util_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_kins_util_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_kins_util_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_kins_util_identity_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_kins_util_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_kins_util_identity_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_kins_util_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_kins_util_adapter.h
Normal file
6
core/src/linuxcnc_kins_util_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_kins_util_identity_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_kins_util_identity_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
|
||||
155
core/src/linuxcnc_lineardeltakins_adapter.c
Normal file
155
core/src/linuxcnc_lineardeltakins_adapter.c
Normal file
@@ -0,0 +1,155 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_lineardelta_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_lineardelta_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_lineardelta_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_lineardelta_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_lineardelta_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_lineardelta_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_lineardelta_hal_malloc(size))
|
||||
#define hal_pin_float_newf cnc_sim_lineardelta_hal_pin_float_newf
|
||||
#define hal_ready cnc_sim_lineardelta_hal_ready
|
||||
#define hal_exit cnc_sim_lineardelta_hal_exit
|
||||
#define kinematicsType cnc_sim_lineardelta_kinematicsType
|
||||
#define kinematicsForward cnc_sim_lineardelta_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_lineardelta_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_lineardelta_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_lineardelta_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_lineardelta_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_lineardelta_rtapi_app_exit
|
||||
#define comp_id cnc_sim_lineardelta_comp_id
|
||||
#define haldata cnc_sim_lineardelta_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/lineardeltakins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_float_newf
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_lineardeltakins_setup(void) {
|
||||
return cnc_sim_lineardelta_rtapi_app_main();
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_lineardeltakins_default_parameters(double *r, double *l) {
|
||||
*r = DELTA_RADIUS;
|
||||
*l = DELTA_DIAGONAL_ROD;
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_lineardeltakins_set_parameters(double r, double l) {
|
||||
*cnc_sim_lineardelta_haldata->r = r;
|
||||
*cnc_sim_lineardelta_haldata->l = l;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_lineardeltakins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_lineardelta_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_lineardeltakins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_lineardelta_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
138
core/src/linuxcnc_lineardeltakins_adapter.cpp
Normal file
138
core/src/linuxcnc_lineardeltakins_adapter.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "linuxcnc_lineardeltakins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_lineardeltakins_setup(void);
|
||||
void cnc_sim_linuxcnc_lineardeltakins_default_parameters(double *r, double *l);
|
||||
void cnc_sim_linuxcnc_lineardeltakins_set_parameters(double r, double l);
|
||||
int cnc_sim_linuxcnc_lineardeltakins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_lineardeltakins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_lineardeltakins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_lineardeltakins_source_default_parameters(LinuxCncLinearDeltaParameters *parameters) {
|
||||
double r = 0.0;
|
||||
double l = 0.0;
|
||||
cnc_sim_linuxcnc_lineardeltakins_default_parameters(&r, &l);
|
||||
parameters->r = r;
|
||||
parameters->l = l;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_lineardeltakins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncLinearDeltaParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_lineardeltakins_set_parameters(parameters.r, parameters.l);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_lineardeltakins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_lineardeltakins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncLinearDeltaParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_lineardeltakins_set_parameters(parameters.r, parameters.l);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_lineardeltakins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
11
core/src/linuxcnc_lineardeltakins_adapter.h
Normal file
11
core/src/linuxcnc_lineardeltakins_adapter.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_lineardeltakins_source_default_parameters(LinuxCncLinearDeltaParameters *parameters);
|
||||
bool linuxcnc_lineardeltakins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncLinearDeltaParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_lineardeltakins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncLinearDeltaParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints);
|
||||
168
core/src/linuxcnc_maxkins_adapter.c
Normal file
168
core/src/linuxcnc_maxkins_adapter.c
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_maxkins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_maxkins_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_maxkins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_maxkins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_maxkins_hal_pin_float_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_maxkins_hal_pin_bit_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_bit_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_maxkins_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_maxkins_hal_malloc(size))
|
||||
#define hal_pin_float_new cnc_sim_maxkins_hal_pin_float_new
|
||||
#define hal_pin_bit_new cnc_sim_maxkins_hal_pin_bit_new
|
||||
#define hal_ready cnc_sim_maxkins_hal_ready
|
||||
#define hal_exit cnc_sim_maxkins_hal_exit
|
||||
#define kinematicsType cnc_sim_maxkins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_maxkins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_maxkins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_maxkins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_maxkins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_maxkins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_maxkins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_maxkins_comp_id
|
||||
#define haldata cnc_sim_maxkins_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/maxkins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_bit_new
|
||||
#undef hal_pin_float_new
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_maxkins_setup(void) {
|
||||
return cnc_sim_maxkins_rtapi_app_main();
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_maxkins_default_parameters(double *pivot_length, int *conventional_directions) {
|
||||
*pivot_length = 0.666;
|
||||
*conventional_directions = 0;
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_maxkins_set_parameters(double pivot_length, int conventional_directions) {
|
||||
*cnc_sim_maxkins_haldata->pivot_length = pivot_length;
|
||||
*cnc_sim_maxkins_haldata->conventional_directions = conventional_directions != 0;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_maxkins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_maxkins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_maxkins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_maxkins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
140
core/src/linuxcnc_maxkins_adapter.cpp
Normal file
140
core/src/linuxcnc_maxkins_adapter.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "linuxcnc_maxkins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_maxkins_setup(void);
|
||||
void cnc_sim_linuxcnc_maxkins_default_parameters(double *pivot_length, int *conventional_directions);
|
||||
void cnc_sim_linuxcnc_maxkins_set_parameters(double pivot_length, int conventional_directions);
|
||||
int cnc_sim_linuxcnc_maxkins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_maxkins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_maxkins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_maxkins_source_default_parameters(LinuxCncMaxkinsParameters *parameters) {
|
||||
double pivot_length = 0.0;
|
||||
int conventional_directions = 0;
|
||||
cnc_sim_linuxcnc_maxkins_default_parameters(&pivot_length, &conventional_directions);
|
||||
parameters->pivot_length = pivot_length;
|
||||
parameters->conventional_directions = conventional_directions != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_maxkins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncMaxkinsParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_maxkins_set_parameters(parameters.pivot_length,
|
||||
parameters.conventional_directions ? 1 : 0);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_maxkins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_maxkins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncMaxkinsParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_maxkins_set_parameters(parameters.pivot_length,
|
||||
parameters.conventional_directions ? 1 : 0);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_maxkins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
11
core/src/linuxcnc_maxkins_adapter.h
Normal file
11
core/src/linuxcnc_maxkins_adapter.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_maxkins_source_default_parameters(LinuxCncMaxkinsParameters *parameters);
|
||||
bool linuxcnc_maxkins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncMaxkinsParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_maxkins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncMaxkinsParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints);
|
||||
172
core/src/linuxcnc_pentakins_adapter.c
Normal file
172
core/src/linuxcnc_pentakins_adapter.c
Normal file
@@ -0,0 +1,172 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef uint32_t hal_u32_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
typedef enum { HAL_RO = 64, HAL_RW = (HAL_RO | 128) } hal_param_dir_t;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
#include "../../../linuxcnc/src/libnml/posemath/posemath.h"
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_pentakins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_pentakins_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_pentakins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_pentakins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_pentakins_hal_param_float_newf(hal_param_dir_t dir,
|
||||
hal_float_t *data_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)data_addr;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_pentakins_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_pentakins_hal_pin_u32_newf(hal_pin_dir_t dir,
|
||||
hal_u32_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_u32_t *)calloc(1, sizeof(hal_u32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_pentakins_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_pentakins_hal_malloc(size))
|
||||
#define hal_param_float_newf cnc_sim_pentakins_hal_param_float_newf
|
||||
#define hal_pin_float_newf cnc_sim_pentakins_hal_pin_float_newf
|
||||
#define hal_pin_u32_newf cnc_sim_pentakins_hal_pin_u32_newf
|
||||
#define hal_ready cnc_sim_pentakins_hal_ready
|
||||
#define hal_exit cnc_sim_pentakins_hal_exit
|
||||
#define kinematicsType cnc_sim_pentakins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_pentakins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_pentakins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_pentakins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_pentakins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_pentakins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_pentakins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_pentakins_comp_id
|
||||
#define haldata cnc_sim_pentakins_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/pentakins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_u32_newf
|
||||
#undef hal_pin_float_newf
|
||||
#undef hal_param_float_newf
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_pentakins_setup(void) {
|
||||
return cnc_sim_pentakins_rtapi_app_main();
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_pentakins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_pentakins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_pentakins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_pentakins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
97
core/src/linuxcnc_pentakins_adapter.cpp
Normal file
97
core/src/linuxcnc_pentakins_adapter.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "linuxcnc_pentakins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_pentakins_setup(void);
|
||||
int cnc_sim_linuxcnc_pentakins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_pentakins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_pentakins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_pentakins_source_forward(const LinuxCncPentakinsJoints &joints,
|
||||
const CncSimPose &initial_pose,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[5];
|
||||
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
|
||||
EmcPose emc_pose = to_emc_pose(initial_pose);
|
||||
if (cnc_sim_linuxcnc_pentakins_forward(raw_joints, &emc_pose) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(emc_pose);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_pentakins_source_inverse(const CncSimPose &pose,
|
||||
LinuxCncPentakinsJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose emc_pose = to_emc_pose(pose);
|
||||
double raw_joints[5] = {};
|
||||
if (cnc_sim_linuxcnc_pentakins_inverse(&emc_pose, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
|
||||
return true;
|
||||
}
|
||||
9
core/src/linuxcnc_pentakins_adapter.h
Normal file
9
core/src/linuxcnc_pentakins_adapter.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_pentakins_source_forward(const LinuxCncPentakinsJoints &joints,
|
||||
const CncSimPose &initial_pose,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_pentakins_source_inverse(const CncSimPose &pose,
|
||||
LinuxCncPentakinsJoints *joints);
|
||||
218
core/src/linuxcnc_pumakins_adapter.c
Normal file
218
core/src/linuxcnc_pumakins_adapter.c
Normal file
@@ -0,0 +1,218 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define SWITCHKINS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CNC_SIM_EXTERN_C extern "C"
|
||||
#else
|
||||
#define CNC_SIM_EXTERN_C
|
||||
#endif
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
#include "../../../linuxcnc/src/libnml/posemath/sincos.c"
|
||||
#include "../../../linuxcnc/src/libnml/posemath/_posemath.c"
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
typedef int (*KF)(const double *joint,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
typedef int (*KI)(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
|
||||
|
||||
void cnc_sim_puma_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_puma_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_puma_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_puma_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_identityKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_identityKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_identityKinematicsInverse(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_userkKinematicsSetup(const int comp_id, const char *coordinates, kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_userkKinematicsForward(const double *joint,
|
||||
EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_puma_userkKinematicsInverse(const EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_puma_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_puma_rtapi_print_msg
|
||||
#define hal_pin_float_newf cnc_sim_puma_hal_pin_float_newf
|
||||
#define identityKinematicsSetup cnc_sim_puma_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_puma_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_puma_identityKinematicsInverse
|
||||
#define userkKinematicsSetup cnc_sim_puma_userkKinematicsSetup
|
||||
#define userkKinematicsForward cnc_sim_puma_userkKinematicsForward
|
||||
#define userkKinematicsInverse cnc_sim_puma_userkKinematicsInverse
|
||||
#define switchkinsSetup cnc_sim_puma_switchkinsSetup
|
||||
#define haldata cnc_sim_puma_haldata
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_puma_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/pumakins.c"
|
||||
#undef hal_malloc
|
||||
#undef haldata
|
||||
#undef switchkinsSetup
|
||||
#undef userkKinematicsInverse
|
||||
#undef userkKinematicsForward
|
||||
#undef userkKinematicsSetup
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef hal_pin_float_newf
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "pumakins";
|
||||
static char halprefix[] = "pumakins";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
return pumaKinematicsSetup(0, "XYZABC", &kp);
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C void cnc_sim_linuxcnc_pumakins_set_parameters(double a2,
|
||||
double a3,
|
||||
double d3,
|
||||
double d4,
|
||||
double d6) {
|
||||
*cnc_sim_puma_haldata->a2 = a2;
|
||||
*cnc_sim_puma_haldata->a3 = a3;
|
||||
*cnc_sim_puma_haldata->d3 = d3;
|
||||
*cnc_sim_puma_haldata->d4 = d4;
|
||||
*cnc_sim_puma_haldata->d6 = d6;
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_forward(const double *joints,
|
||||
struct EmcPose *pos,
|
||||
int *iflags) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS raw_iflags = 0;
|
||||
const int result = pumaKinematicsForward(joints, pos, &fflags, &raw_iflags);
|
||||
if (iflags) {
|
||||
*iflags = (int)raw_iflags;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_pumakins_inverse(const struct EmcPose *pos,
|
||||
double *joints,
|
||||
int iflags,
|
||||
int *fflags) {
|
||||
KINEMATICS_INVERSE_FLAGS raw_iflags = (KINEMATICS_INVERSE_FLAGS)iflags;
|
||||
KINEMATICS_FORWARD_FLAGS raw_fflags = 0;
|
||||
const int result = pumaKinematicsInverse(pos, joints, &raw_iflags, &raw_fflags);
|
||||
if (fflags) {
|
||||
*fflags = (int)raw_fflags;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
156
core/src/linuxcnc_pumakins_adapter.cpp
Normal file
156
core/src/linuxcnc_pumakins_adapter.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "linuxcnc_pumakins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_pumakins_setup(void);
|
||||
void cnc_sim_linuxcnc_pumakins_set_parameters(double a2,
|
||||
double a3,
|
||||
double d3,
|
||||
double d4,
|
||||
double d6);
|
||||
int cnc_sim_linuxcnc_pumakins_forward(const double *joints, EmcPose *pos, int *iflags);
|
||||
int cnc_sim_linuxcnc_pumakins_inverse(const EmcPose *pos,
|
||||
double *joints,
|
||||
int iflags,
|
||||
int *fflags);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_pumakins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void apply_parameters(const LinuxCncPumaParameters ¶meters) {
|
||||
cnc_sim_linuxcnc_pumakins_set_parameters(parameters.a2,
|
||||
parameters.a3,
|
||||
parameters.d3,
|
||||
parameters.d4,
|
||||
parameters.d6);
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_pumakins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
CncSimPose *pose,
|
||||
int *iflags) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
int raw_iflags = 0;
|
||||
if (cnc_sim_linuxcnc_pumakins_forward(raw_joints, &out, &raw_iflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (iflags) {
|
||||
*iflags = raw_iflags;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_pumakins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints ¤t_joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int iflags,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *fflags) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
double raw_joints[16];
|
||||
to_joints(current_joints, raw_joints);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
int raw_fflags = 0;
|
||||
if (cnc_sim_linuxcnc_pumakins_inverse(&in, raw_joints, iflags, &raw_fflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (fflags) {
|
||||
*fflags = raw_fflags;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
14
core/src/linuxcnc_pumakins_adapter.h
Normal file
14
core/src/linuxcnc_pumakins_adapter.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_pumakins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
CncSimPose *pose,
|
||||
int *iflags);
|
||||
bool linuxcnc_pumakins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints ¤t_joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int iflags,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *fflags);
|
||||
147
core/src/linuxcnc_rosekins_adapter.c
Normal file
147
core/src/linuxcnc_rosekins_adapter.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
#define PM_2_PI (2.0 * PM_PI)
|
||||
#define TO_RAD (PM_PI / 180.0)
|
||||
#define TO_DEG (180.0 / PM_PI)
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_rosekins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_rosekins_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_rosekins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_rosekins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_rosekins_hal_pin_float_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_rosekins_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_rosekins_hal_malloc(size))
|
||||
#define hal_pin_float_new cnc_sim_rosekins_hal_pin_float_new
|
||||
#define hal_ready cnc_sim_rosekins_hal_ready
|
||||
#define hal_exit cnc_sim_rosekins_hal_exit
|
||||
#define kinematicsType cnc_sim_rosekins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_rosekins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_rosekins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_rosekins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_rosekins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_rosekins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_rosekins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_rosekins_comp_id
|
||||
#define haldata cnc_sim_rosekins_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/rosekins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_float_new
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_rosekins_setup(void) {
|
||||
return cnc_sim_rosekins_rtapi_app_main();
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_rosekins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_rosekins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_rosekins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_rosekins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
121
core/src/linuxcnc_rosekins_adapter.cpp
Normal file
121
core/src/linuxcnc_rosekins_adapter.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "linuxcnc_rosekins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_rosekins_setup(void);
|
||||
int cnc_sim_linuxcnc_rosekins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_rosekins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_rosekins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_rosekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_rosekins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_rosekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_rosekins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_rosekins_adapter.h
Normal file
6
core/src/linuxcnc_rosekins_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_rosekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_rosekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
|
||||
165
core/src/linuxcnc_rotarydeltakins_adapter.c
Normal file
165
core/src/linuxcnc_rotarydeltakins_adapter.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_rotarydelta_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_rotarydelta_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_rotarydelta_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_rotarydelta_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_rotarydelta_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_rotarydelta_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_rotarydelta_hal_malloc(size))
|
||||
#define hal_pin_float_newf cnc_sim_rotarydelta_hal_pin_float_newf
|
||||
#define hal_ready cnc_sim_rotarydelta_hal_ready
|
||||
#define hal_exit cnc_sim_rotarydelta_hal_exit
|
||||
#define kinematicsType cnc_sim_rotarydelta_kinematicsType
|
||||
#define kinematicsForward cnc_sim_rotarydelta_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_rotarydelta_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_rotarydelta_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_rotarydelta_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_rotarydelta_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_rotarydelta_rtapi_app_exit
|
||||
#define comp_id cnc_sim_rotarydelta_comp_id
|
||||
#define haldata cnc_sim_rotarydelta_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/rotarydeltakins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_float_newf
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_setup(void) {
|
||||
return cnc_sim_rotarydelta_rtapi_app_main();
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_rotarydeltakins_default_parameters(double *platformradius,
|
||||
double *thighlength,
|
||||
double *shinlength,
|
||||
double *footradius) {
|
||||
*platformradius = RDELTA_PFR;
|
||||
*thighlength = RDELTA_TL;
|
||||
*shinlength = RDELTA_SL;
|
||||
*footradius = RDELTA_FR;
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_rotarydeltakins_set_parameters(double platformradius,
|
||||
double thighlength,
|
||||
double shinlength,
|
||||
double footradius) {
|
||||
*cnc_sim_rotarydelta_haldata->pfr = platformradius;
|
||||
*cnc_sim_rotarydelta_haldata->tl = thighlength;
|
||||
*cnc_sim_rotarydelta_haldata->sl = shinlength;
|
||||
*cnc_sim_rotarydelta_haldata->fr = footradius;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_rotarydelta_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_rotarydelta_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
157
core/src/linuxcnc_rotarydeltakins_adapter.cpp
Normal file
157
core/src/linuxcnc_rotarydeltakins_adapter.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#include "linuxcnc_rotarydeltakins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_setup(void);
|
||||
void cnc_sim_linuxcnc_rotarydeltakins_default_parameters(double *platformradius,
|
||||
double *thighlength,
|
||||
double *shinlength,
|
||||
double *footradius);
|
||||
void cnc_sim_linuxcnc_rotarydeltakins_set_parameters(double platformradius,
|
||||
double thighlength,
|
||||
double shinlength,
|
||||
double footradius);
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_rotarydeltakins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_rotarydeltakins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_rotarydeltakins_source_default_parameters(LinuxCncRotaryDeltaParameters *parameters) {
|
||||
double platformradius = 0.0;
|
||||
double thighlength = 0.0;
|
||||
double shinlength = 0.0;
|
||||
double footradius = 0.0;
|
||||
cnc_sim_linuxcnc_rotarydeltakins_default_parameters(&platformradius,
|
||||
&thighlength,
|
||||
&shinlength,
|
||||
&footradius);
|
||||
parameters->platformradius = platformradius;
|
||||
parameters->thighlength = thighlength;
|
||||
parameters->shinlength = shinlength;
|
||||
parameters->footradius = footradius;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_rotarydeltakins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_rotarydeltakins_set_parameters(parameters.platformradius,
|
||||
parameters.thighlength,
|
||||
parameters.shinlength,
|
||||
parameters.footradius);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_rotarydeltakins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_rotarydeltakins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
cnc_sim_linuxcnc_rotarydeltakins_set_parameters(parameters.platformradius,
|
||||
parameters.thighlength,
|
||||
parameters.shinlength,
|
||||
parameters.footradius);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_rotarydeltakins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
11
core/src/linuxcnc_rotarydeltakins_adapter.h
Normal file
11
core/src/linuxcnc_rotarydeltakins_adapter.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_rotarydeltakins_source_default_parameters(LinuxCncRotaryDeltaParameters *parameters);
|
||||
bool linuxcnc_rotarydeltakins_source_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_rotarydeltakins_source_inverse(const CncSimPose &pose,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints);
|
||||
118
core/src/linuxcnc_rotatekins_adapter.c
Normal file
118
core/src/linuxcnc_rotatekins_adapter.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define RTAPI_MSG_ERR 1
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_rotatekins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cnc_sim_rotatekins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_rotatekins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_rotatekins_hal_init
|
||||
#define hal_ready cnc_sim_rotatekins_hal_ready
|
||||
#define hal_exit cnc_sim_rotatekins_hal_exit
|
||||
#define kinematicsType cnc_sim_rotatekins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_rotatekins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_rotatekins_kinematicsInverse
|
||||
#define kinematicsHome cnc_sim_rotatekins_kinematicsHome
|
||||
#define kinematicsSwitchable cnc_sim_rotatekins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_rotatekins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_rotatekins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_rotatekins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_rotatekins_comp_id
|
||||
#include "../../../linuxcnc/src/emc/kinematics/rotatekins.c"
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsHome
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_rotatekins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_rotatekins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_rotatekins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_rotatekins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
104
core/src/linuxcnc_rotatekins_adapter.cpp
Normal file
104
core/src/linuxcnc_rotatekins_adapter.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "linuxcnc_rotatekins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_rotatekins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_rotatekins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_rotatekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_rotatekins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_rotatekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_rotatekins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_rotatekins_adapter.h
Normal file
6
core/src/linuxcnc_rotatekins_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_rotatekins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_rotatekins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "linuxcnc_rs274_backend.h"
|
||||
|
||||
#ifdef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
#include "boost/python/object.hpp"
|
||||
#else
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#include "linuxcnc_canon_bridge.h"
|
||||
#include "linuxcnc_tooldata_fixture.h"
|
||||
@@ -16,11 +20,15 @@
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
int _task = 0;
|
||||
char _parameter_file_name[LINELEN];
|
||||
|
||||
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
int _task = 0;
|
||||
|
||||
extern "C" PyObject *PyInit_interpreter(void);
|
||||
extern "C" PyObject *PyInit_emccanon(void);
|
||||
extern "C" struct _inittab builtin_modules[];
|
||||
@@ -29,6 +37,7 @@ struct _inittab builtin_modules[] = {
|
||||
{"emccanon", PyInit_emccanon},
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -73,6 +82,38 @@ bool file_mode_enabled() {
|
||||
return std::getenv("CNC_SIM_RS274_FILE_MODE") != nullptr;
|
||||
}
|
||||
|
||||
class ScopedEnvironmentVariable {
|
||||
public:
|
||||
ScopedEnvironmentVariable(const char *name, const std::string &value) : name_(name), active_(!value.empty()) {
|
||||
if (!active_) {
|
||||
return;
|
||||
}
|
||||
if (const char *old = std::getenv(name_)) {
|
||||
had_old_ = true;
|
||||
old_ = old;
|
||||
}
|
||||
setenv(name_, value.c_str(), 1);
|
||||
}
|
||||
|
||||
~ScopedEnvironmentVariable() {
|
||||
if (!active_) {
|
||||
return;
|
||||
}
|
||||
if (had_old_) {
|
||||
setenv(name_, old_.c_str(), 1);
|
||||
} else {
|
||||
unsetenv(name_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const char *name_;
|
||||
bool active_;
|
||||
bool had_old_ = false;
|
||||
std::string old_;
|
||||
};
|
||||
|
||||
#ifndef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
bool write_temp_program(const char *program,
|
||||
size_t program_len,
|
||||
std::string *path,
|
||||
@@ -113,6 +154,7 @@ bool write_temp_program(const char *program,
|
||||
*path = tmpl_buffer.data();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int execute_file_mode(InterpBase *interp,
|
||||
CanonEventSink &sink,
|
||||
@@ -164,6 +206,7 @@ int execute_file_mode(InterpBase *interp,
|
||||
int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
const char *program,
|
||||
size_t program_len,
|
||||
const GcodeBackendOptions &options,
|
||||
std::string *error) {
|
||||
if (!program && program_len != 0) {
|
||||
if (error) {
|
||||
@@ -172,14 +215,36 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// LinuxCNC source basis: rs274ngc_pre.cc uses
|
||||
// RS274NGC_PARAMETER_FILE_NAME_DEFAULT when the external parameter file
|
||||
// name is empty. Reset the bridge every parse so a prior native env
|
||||
// override does not leak into later default parses.
|
||||
if (const char *parameter_file = std::getenv("CNC_SIM_RS274_VAR")) {
|
||||
SET_PARAMETER_FILE_NAME(parameter_file);
|
||||
} else {
|
||||
SET_PARAMETER_FILE_NAME("rs274ngc.var");
|
||||
}
|
||||
cnc_sim_init_minimal_linuxcnc_tooldata();
|
||||
sink.clear_callback_status();
|
||||
cnc_sim_linuxcnc_set_canon_sink(&sink);
|
||||
|
||||
// LinuxCNC source basis: rs274ngc_pre.cc and interp_namedparams.cc read
|
||||
// INI_FILE_NAME for startup and #<_ini[section]key> named parameters.
|
||||
ScopedEnvironmentVariable ini_file_env("INI_FILE_NAME", options.ini_file_name);
|
||||
InterpBase *interp = makeInterp();
|
||||
if (!options.ini_file_name.empty()) {
|
||||
// LinuxCNC source basis: emctask.cc calls Interp::ini_load() before
|
||||
// Interp::init(), and rs274ngc_pre.cc ini_load() maps
|
||||
// [RS274NGC] PARAMETER_FILE through SET_PARAMETER_FILE_NAME().
|
||||
if (interp->ini_load(options.ini_file_name.c_str()) != INTERP_OK) {
|
||||
if (error) {
|
||||
*error = "ini_load failed: " + options.ini_file_name;
|
||||
}
|
||||
delete interp;
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int status = interp->init();
|
||||
if (status != INTERP_OK) {
|
||||
if (error) {
|
||||
@@ -192,6 +257,15 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
SET_BLOCK_DELETE(sink.block_delete());
|
||||
|
||||
if (file_mode_enabled()) {
|
||||
#ifdef CNC_SIM_ENABLE_LINUXCNC_WASM_SAFE_PROBE
|
||||
if (error) {
|
||||
*error = "linuxcnc-rs274 file mode is not available in wasm-safe builds";
|
||||
}
|
||||
interp->exit();
|
||||
delete interp;
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
#else
|
||||
std::string temp_path;
|
||||
if (!write_temp_program(program, program_len, &temp_path, error)) {
|
||||
interp->exit();
|
||||
@@ -207,6 +281,7 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
std::string source(program, program + program_len);
|
||||
std::istringstream input(source);
|
||||
@@ -217,21 +292,47 @@ int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
++line_number;
|
||||
cnc_sim_linuxcnc_set_current_line(line_number);
|
||||
std::vector<SimulatorGcodeControlAction> control_actions;
|
||||
if (parse_simulator_gcode_control_line(line, &control_actions)) {
|
||||
if (parse_simulator_gcode_control_line(line, sink.block_delete(), &control_actions)) {
|
||||
bool simulator_only_line = true;
|
||||
bool all_control_actions_handled = true;
|
||||
for (const auto &action : control_actions) {
|
||||
emit_simulator_gcode_control_action(sink, action, line_number);
|
||||
if (!can_emit_simulator_gcode_control_action(sink, action)) {
|
||||
all_control_actions_handled = false;
|
||||
simulator_only_line = false;
|
||||
}
|
||||
if (action.kind == SimulatorGcodeControlKind::RtcpState &&
|
||||
!action.rtcp_enabled) {
|
||||
simulator_only_line = false;
|
||||
}
|
||||
if (stop_if_callback_aborted(sink, error)) {
|
||||
interp->exit();
|
||||
delete interp;
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
if (!all_control_actions_handled && control_actions.size() > 1) {
|
||||
for (const auto &action : control_actions) {
|
||||
if (!can_emit_simulator_gcode_control_action(sink, action) &&
|
||||
action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M" + std::to_string(action.m_code);
|
||||
}
|
||||
interp->exit();
|
||||
delete interp;
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (all_control_actions_handled) {
|
||||
for (const auto &action : control_actions) {
|
||||
emit_simulator_gcode_control_action(sink, action, line_number);
|
||||
if (stop_if_callback_aborted(sink, error)) {
|
||||
interp->exit();
|
||||
delete interp;
|
||||
cnc_sim_linuxcnc_set_canon_sink(nullptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!all_control_actions_handled) {
|
||||
simulator_only_line = false;
|
||||
}
|
||||
if (simulator_only_line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "canon_event_sink.h"
|
||||
#include "gcode_backend.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
@@ -8,5 +9,5 @@
|
||||
int parse_linuxcnc_rs274_backend(CanonEventSink &sink,
|
||||
const char *program,
|
||||
size_t program_len,
|
||||
const GcodeBackendOptions &options,
|
||||
std::string *error);
|
||||
|
||||
|
||||
224
core/src/linuxcnc_scarakins_adapter.c
Normal file
224
core/src/linuxcnc_scarakins_adapter.c
Normal file
@@ -0,0 +1,224 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define SWITCHKINS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CNC_SIM_EXTERN_C extern "C"
|
||||
#else
|
||||
#define CNC_SIM_EXTERN_C
|
||||
#endif
|
||||
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
typedef int (*KF)(const double *joint,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
typedef int (*KI)(const struct EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
typedef int (*KS)(const int comp_id, const char *coordinates, kparms *ksetup_parms);
|
||||
|
||||
void cnc_sim_scara_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_scara_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_scara_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_scara_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_identityKinematicsSetup(const int comp_id,
|
||||
const char *coordinates,
|
||||
kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_identityKinematicsForward(const double *joint,
|
||||
struct EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_identityKinematicsInverse(const struct EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_userkKinematicsSetup(const int comp_id,
|
||||
const char *coordinates,
|
||||
kparms *ksetup_parms) {
|
||||
(void)comp_id;
|
||||
(void)coordinates;
|
||||
(void)ksetup_parms;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_userkKinematicsForward(const double *joint,
|
||||
struct EmcPose *world,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags) {
|
||||
(void)joint;
|
||||
(void)world;
|
||||
(void)fflags;
|
||||
(void)iflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cnc_sim_scara_userkKinematicsInverse(const struct EmcPose *world,
|
||||
double *joint,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags) {
|
||||
(void)world;
|
||||
(void)joint;
|
||||
(void)iflags;
|
||||
(void)fflags;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_scara_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_scara_rtapi_print_msg
|
||||
#define hal_pin_float_newf cnc_sim_scara_hal_pin_float_newf
|
||||
#define identityKinematicsSetup cnc_sim_scara_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_scara_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_scara_identityKinematicsInverse
|
||||
#define userkKinematicsSetup cnc_sim_scara_userkKinematicsSetup
|
||||
#define userkKinematicsForward cnc_sim_scara_userkKinematicsForward
|
||||
#define userkKinematicsInverse cnc_sim_scara_userkKinematicsInverse
|
||||
#define switchkinsSetup cnc_sim_scara_switchkinsSetup
|
||||
#define haldata cnc_sim_scara_haldata
|
||||
#define hal_malloc(size) ((struct scara_data *)cnc_sim_scara_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/scarakins.c"
|
||||
#undef hal_malloc
|
||||
#undef haldata
|
||||
#undef switchkinsSetup
|
||||
#undef userkKinematicsInverse
|
||||
#undef userkKinematicsForward
|
||||
#undef userkKinematicsSetup
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef hal_pin_float_newf
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "scarakins";
|
||||
static char halprefix[] = "scarakins";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
return scaraKinematicsSetup(0, "XYZABC", &kp);
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C void cnc_sim_linuxcnc_scarakins_set_parameters(double d1,
|
||||
double d2,
|
||||
double d3,
|
||||
double d4,
|
||||
double d5,
|
||||
double d6) {
|
||||
*cnc_sim_scara_haldata->d1 = d1;
|
||||
*cnc_sim_scara_haldata->d2 = d2;
|
||||
*cnc_sim_scara_haldata->d3 = d3;
|
||||
*cnc_sim_scara_haldata->d4 = d4;
|
||||
*cnc_sim_scara_haldata->d5 = d5;
|
||||
*cnc_sim_scara_haldata->d6 = d6;
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_forward(const double *joints,
|
||||
struct EmcPose *pos,
|
||||
int *iflags) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS raw_iflags = 0;
|
||||
const int result = scaraKinematicsForward(joints, pos, &fflags, &raw_iflags);
|
||||
if (iflags) {
|
||||
*iflags = (int)raw_iflags;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CNC_SIM_EXTERN_C int cnc_sim_linuxcnc_scarakins_inverse(const struct EmcPose *pos,
|
||||
double *joints,
|
||||
int iflags) {
|
||||
KINEMATICS_INVERSE_FLAGS raw_iflags = (KINEMATICS_INVERSE_FLAGS)iflags;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return scaraKinematicsInverse(pos, joints, &raw_iflags, &fflags);
|
||||
}
|
||||
144
core/src/linuxcnc_scarakins_adapter.cpp
Normal file
144
core/src/linuxcnc_scarakins_adapter.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "linuxcnc_scarakins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_scarakins_setup(void);
|
||||
void cnc_sim_linuxcnc_scarakins_set_parameters(double d1,
|
||||
double d2,
|
||||
double d3,
|
||||
double d4,
|
||||
double d5,
|
||||
double d6);
|
||||
int cnc_sim_linuxcnc_scarakins_forward(const double *joints, EmcPose *pos, int *iflags);
|
||||
int cnc_sim_linuxcnc_scarakins_inverse(const EmcPose *pos,
|
||||
double *joints,
|
||||
int iflags);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_scarakins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void apply_parameters(const LinuxCncScaraParameters ¶meters) {
|
||||
cnc_sim_linuxcnc_scarakins_set_parameters(parameters.d1,
|
||||
parameters.d2,
|
||||
parameters.d3,
|
||||
parameters.d4,
|
||||
parameters.d5,
|
||||
parameters.d6);
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncScaraJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.j0;
|
||||
out[1] = joints.j1;
|
||||
out[2] = joints.j2;
|
||||
out[3] = joints.j3;
|
||||
out[4] = joints.j4;
|
||||
out[5] = joints.j5;
|
||||
}
|
||||
|
||||
LinuxCncScaraJoints from_joints(const double joints[16]) {
|
||||
LinuxCncScaraJoints out{};
|
||||
out.j0 = joints[0];
|
||||
out.j1 = joints[1];
|
||||
out.j2 = joints[2];
|
||||
out.j3 = joints[3];
|
||||
out.j4 = joints[4];
|
||||
out.j5 = joints[5];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_scarakins_forward(const LinuxCncScaraJoints &joints,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
CncSimPose *pose,
|
||||
int *iflags) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
int raw_iflags = 0;
|
||||
if (cnc_sim_linuxcnc_scarakins_forward(raw_joints, &out, &raw_iflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (iflags) {
|
||||
*iflags = raw_iflags;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_scarakins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int iflags,
|
||||
LinuxCncScaraJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_scarakins_inverse(&in, raw_joints, iflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
12
core/src/linuxcnc_scarakins_adapter.h
Normal file
12
core/src/linuxcnc_scarakins_adapter.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_scarakins_forward(const LinuxCncScaraJoints &joints,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
CncSimPose *pose,
|
||||
int *iflags);
|
||||
bool linuxcnc_scarakins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int iflags,
|
||||
LinuxCncScaraJoints *joints);
|
||||
121
core/src/linuxcnc_scorbot_kins_adapter.c
Normal file
121
core/src/linuxcnc_scorbot_kins_adapter.c
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_GO_TYPES_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
#define TO_RAD (PM_PI / 180.0)
|
||||
#define TO_DEG (180.0 / PM_PI)
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_scorbot_kins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cnc_sim_scorbot_kins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_scorbot_kins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_scorbot_kins_hal_init
|
||||
#define hal_ready cnc_sim_scorbot_kins_hal_ready
|
||||
#define hal_exit cnc_sim_scorbot_kins_hal_exit
|
||||
#define kinematicsType cnc_sim_scorbot_kins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_scorbot_kins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_scorbot_kins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_scorbot_kins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_scorbot_kins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_scorbot_kins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_scorbot_kins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_scorbot_kins_comp_id
|
||||
#include "../../../linuxcnc/src/emc/kinematics/scorbot-kins.c"
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_scorbot_kins_setup(void) {
|
||||
return cnc_sim_scorbot_kins_rtapi_app_main();
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_scorbot_kins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_scorbot_kins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_scorbot_kins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_scorbot_kins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
110
core/src/linuxcnc_scorbot_kins_adapter.cpp
Normal file
110
core/src/linuxcnc_scorbot_kins_adapter.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "linuxcnc_scorbot_kins_adapter.h"
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_scorbot_kins_setup(void);
|
||||
int cnc_sim_linuxcnc_scorbot_kins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_scorbot_kins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_scorbot_kins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncScorbotJoints &joints, double out[5]) {
|
||||
out[0] = joints.j0;
|
||||
out[1] = joints.j1;
|
||||
out[2] = joints.j2;
|
||||
out[3] = joints.j3;
|
||||
out[4] = joints.j4;
|
||||
}
|
||||
|
||||
LinuxCncScorbotJoints from_joints(const double joints[5]) {
|
||||
LinuxCncScorbotJoints out{};
|
||||
out.j0 = joints[0];
|
||||
out.j1 = joints[1];
|
||||
out.j2 = joints[2];
|
||||
out.j3 = joints[3];
|
||||
out.j4 = joints[4];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_scorbot_kins_source_forward(const LinuxCncScorbotJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[5] = {};
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_scorbot_kins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_scorbot_kins_source_inverse(const CncSimPose &pose, LinuxCncScorbotJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[5] = {};
|
||||
if (cnc_sim_linuxcnc_scorbot_kins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_scorbot_kins_adapter.h
Normal file
6
core/src/linuxcnc_scorbot_kins_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_scorbot_kins_source_forward(const LinuxCncScorbotJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_scorbot_kins_source_inverse(const CncSimPose &pose, LinuxCncScorbotJoints *joints);
|
||||
180
core/src/linuxcnc_switchkins_remap_table.inc
Normal file
180
core/src/linuxcnc_switchkins_remap_table.inc
Normal file
@@ -0,0 +1,180 @@
|
||||
// Generated by ./generate-linuxcnc-switchkins-remap-table.sh.
|
||||
// Source: LinuxCNC INI MACHINE/KINEMATICS/HALFILE/POSTGUI_HALFILE/SUBROUTINE_PATH/REMAP entries and
|
||||
// adjacent remap_subs/{428,429,430}remap.ngc #<kinstype> assignments.
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/5axis.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill", 0, 1, 2},
|
||||
{"bridgemill", 0, 1, 2},
|
||||
{"5axis", 0, 1, 2},
|
||||
{"sim-5axisbridgemill(xyzbcw)", 0, 1, 2},
|
||||
{"sim-5axisbridgemill", 0, 1, 2},
|
||||
{"5axiskinscoordinates=xyzbcwy", 0, 1, 2},
|
||||
{"5axiskins", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/5axisgui.hal", 0, 1, 2},
|
||||
{"5axisgui.hal", 0, 1, 2},
|
||||
{"5axisgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/5axis_postgui.hal", 0, 1, 2},
|
||||
{"5axis_postgui.hal", 0, 1, 2},
|
||||
{"5axis_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary", 1, 0, -1},
|
||||
{"table-dual-rotary", 1, 0, -1},
|
||||
{"xyzab-tdr", 1, 0, -1},
|
||||
{"sim-xyzab-tdr-kins(switchkins)", 1, 0, -1},
|
||||
{"sim-xyzab-tdr-kins", 1, 0, -1},
|
||||
{"xyzab_tdr_kins", 1, 0, -1},
|
||||
{"xyzab_tdr", 1, 0, -1},
|
||||
{"xyzab-tdr-kins", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr-postgui.hal", 1, 0, -1},
|
||||
{"xyzab-tdr-postgui.hal", 1, 0, -1},
|
||||
{"xyzab-tdr-postgui", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-dual-rotary/remap_subs/429remap.ngc", 1, 0, -1},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting", 1, 0, 2},
|
||||
{"table-rotary-tilting", 1, 0, 2},
|
||||
{"xyzac-trt", 1, 0, 2},
|
||||
{"sim-xyzac-trt-kins(switchkins)", 1, 0, 2},
|
||||
{"sim-xyzac-trt-kins", 1, 0, 2},
|
||||
{"xyzac-trt-kinssparm=identityfirst", 1, 0, 2},
|
||||
{"xyzac-trt-kins", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal", 1, 0, 2},
|
||||
{"switchkins_postgui.hal", 1, 0, 2},
|
||||
{"switchkins_postgui", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini", 1, 0, 2},
|
||||
{"xyzbc-trt", 1, 0, 2},
|
||||
{"sim-xyzbc-trt-kins(switchkins)", 1, 0, 2},
|
||||
{"sim-xyzbc-trt-kins", 1, 0, 2},
|
||||
{"xyzbc-trt-kinssparm=identityfirst", 1, 0, 2},
|
||||
{"xyzbc-trt-kins", 1, 0, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp", 0, 1, 2},
|
||||
{"xyzacb-trsrn_twp", 0, 1, 2},
|
||||
{"xyzacb-trsrn", 0, 1, 2},
|
||||
{"xyzacb-trsrn(switchkins)", 0, 1, 2},
|
||||
{"xyzacb_trsrn", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn_postgui.hal", 0, 1, 2},
|
||||
{"xyzacb-trsrn_postgui.hal", 0, 1, 2},
|
||||
{"xyzacb-trsrn_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating", 0, 1, 2},
|
||||
{"table-rotary_spindle-rotary-nutating", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp", 0, 1, 2},
|
||||
{"xyzbca-trsrn_twp", 0, 1, 2},
|
||||
{"xyzbca-trsrn", 0, 1, 2},
|
||||
{"xyzbca-trsrn(switchkins)", 0, 1, 2},
|
||||
{"xyzbca_trsrn", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzbca-trsrn_twp/xyzbca-trsrn_postgui.hal", 0, 1, 2},
|
||||
{"xyzbca-trsrn_postgui.hal", 0, 1, 2},
|
||||
{"xyzbca-trsrn_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/hexapod.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim", 0, 1, 2},
|
||||
{"hexapod-sim", 0, 1, 2},
|
||||
{"hexapod", 0, 1, 2},
|
||||
{"hexapod(switchkins)", 0, 1, 2},
|
||||
{"genhexkins", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/kinematics.hal", 0, 1, 2},
|
||||
{"kinematics.hal", 0, 1, 2},
|
||||
{"kinematics", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/hexapod_postgui.hal", 0, 1, 2},
|
||||
{"hexapod_postgui.hal", 0, 1, 2},
|
||||
{"hexapod_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/hexapod-sim/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/melfa.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim", 0, 1, 2},
|
||||
{"melfa-sim", 0, 1, 2},
|
||||
{"melfa", 0, 1, 2},
|
||||
{"melfa(mm)", 0, 1, 2},
|
||||
{"genserkins", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/melfa_dh.hal", 0, 1, 2},
|
||||
{"melfa_dh.hal", 0, 1, 2},
|
||||
{"melfa_dh", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/melfa-postgui.hal", 0, 1, 2},
|
||||
{"melfa-postgui.hal", 0, 1, 2},
|
||||
{"melfa-postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/melfa-sim/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/millturn/millturn.ini", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn", 0, 1, -1},
|
||||
{"millturn", 0, 1, -1},
|
||||
{"millturn(mm)", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn/millturn.hal", 0, 1, -1},
|
||||
{"millturn.hal", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn/millturn-postgui.hal", 0, 1, -1},
|
||||
{"millturn-postgui.hal", 0, 1, -1},
|
||||
{"millturn-postgui", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn/remap_subs", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc", 0, 1, -1},
|
||||
{"configs/sim/axis/vismach/puma/puma.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma", 0, 1, 2},
|
||||
{"puma", 0, 1, 2},
|
||||
{"puma(pumakins,switchkins)", 0, 1, 2},
|
||||
{"pumakins", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma_dh.hal", 0, 1, 2},
|
||||
{"puma_dh.hal", 0, 1, 2},
|
||||
{"puma_dh", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma_postgui.hal", 0, 1, 2},
|
||||
{"puma_postgui.hal", 0, 1, 2},
|
||||
{"puma_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma_cube.ini", 0, 1, 2},
|
||||
{"puma_cube", 0, 1, 2},
|
||||
{"puma_cube.ini(pumakins)", 0, 1, 2},
|
||||
{"puma_cube.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma560.ini", 0, 1, 2},
|
||||
{"puma560", 0, 1, 2},
|
||||
{"puma560(switchkins)(inch)", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma560_dh.hal", 0, 1, 2},
|
||||
{"puma560_dh.hal", 0, 1, 2},
|
||||
{"puma560_dh", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma560_postgui.hal", 0, 1, 2},
|
||||
{"puma560_postgui.hal", 0, 1, 2},
|
||||
{"puma560_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/puma/puma560_uvw.ini", 0, 1, 2},
|
||||
{"puma560_uvw", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/scara.ini", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara", 0, 1, 2},
|
||||
{"scara", 0, 1, 2},
|
||||
{"scara(genserkins,switchkins)", 0, 1, 2},
|
||||
{"scarakinscoordinates=xyzcab", 0, 1, 2},
|
||||
{"scarakins", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/scara_postgui.hal", 0, 1, 2},
|
||||
{"scara_postgui.hal", 0, 1, 2},
|
||||
{"scara_postgui", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/axis/vismach/scara/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara/scara.ini", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtaxis/non-trivial/scara/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara/scara.ini", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara/remap_subs/428remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara/remap_subs", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara/remap_subs/429remap.ngc", 0, 1, 2},
|
||||
{"configs/sim/qtvcp_screens/non-trivial/scara/remap_subs/430remap.ngc", 0, 1, 2},
|
||||
142
core/src/linuxcnc_tripodkins_adapter.c
Normal file
142
core/src/linuxcnc_tripodkins_adapter.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int cnc_sim_tripodkins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *cnc_sim_tripodkins_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_tripodkins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_tripodkins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_tripodkins_hal_pin_float_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define hal_init cnc_sim_tripodkins_hal_init
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_tripodkins_hal_malloc(size))
|
||||
#define hal_pin_float_new cnc_sim_tripodkins_hal_pin_float_new
|
||||
#define hal_ready cnc_sim_tripodkins_hal_ready
|
||||
#define hal_exit cnc_sim_tripodkins_hal_exit
|
||||
#define kinematicsType cnc_sim_tripodkins_kinematicsType
|
||||
#define kinematicsForward cnc_sim_tripodkins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_tripodkins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_tripodkins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_tripodkins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_tripodkins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_tripodkins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_tripodkins_comp_id
|
||||
#define haldata cnc_sim_tripodkins_haldata
|
||||
#include "../../../linuxcnc/src/emc/kinematics/tripodkins.c"
|
||||
#undef haldata
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsType
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_pin_float_new
|
||||
#undef hal_malloc
|
||||
#undef hal_init
|
||||
|
||||
int cnc_sim_linuxcnc_tripodkins_setup(void) {
|
||||
return cnc_sim_tripodkins_rtapi_app_main();
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_tripodkins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_tripodkins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_tripodkins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_tripodkins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
94
core/src/linuxcnc_tripodkins_adapter.cpp
Normal file
94
core/src/linuxcnc_tripodkins_adapter.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "linuxcnc_tripodkins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_tripodkins_setup(void);
|
||||
int cnc_sim_linuxcnc_tripodkins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_tripodkins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_tripodkins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_tripodkins_source_forward(const LinuxCncTripodJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[3];
|
||||
std::memcpy(raw_joints, joints.strut, sizeof(raw_joints));
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_tripodkins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_tripodkins_source_inverse(const CncSimPose &pose, LinuxCncTripodJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose emc_pose = to_emc_pose(pose);
|
||||
double raw_joints[3] = {};
|
||||
if (cnc_sim_linuxcnc_tripodkins_inverse(&emc_pose, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy(joints->strut, raw_joints, sizeof(raw_joints));
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_tripodkins_adapter.h
Normal file
6
core/src/linuxcnc_tripodkins_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_tripodkins_source_forward(const LinuxCncTripodJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_tripodkins_source_inverse(const CncSimPose &pose, LinuxCncTripodJoints *joints);
|
||||
163
core/src/linuxcnc_trivkins_adapter.c
Normal file
163
core/src/linuxcnc_trivkins_adapter.c
Normal file
@@ -0,0 +1,163 @@
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define RTAPI_MP_STRING(name, desc)
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define EMCMOT_MAX_AXIS 9
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#define KINS_NOT_SWITCHABLE \
|
||||
extern int kinematicsSwitchable() { return 0; } \
|
||||
extern int kinematicsSwitch(int switchkins_type) { (void)switchkins_type; return 0; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cnc_sim_trivkins_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_trivkins_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
int cnc_sim_trivkins_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cnc_sim_trivkins_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cnc_sim_trivkins_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_trivkins_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_trivkins_rtapi_print_msg
|
||||
#define kinematicsType cnc_sim_trivkins_kinematicsType
|
||||
KINEMATICS_TYPE kinematicsType(void);
|
||||
#define map_coordinates_to_jnumbers cnc_sim_trivkins_map_coordinates_to_jnumbers
|
||||
#define mapped_joints_to_position cnc_sim_trivkins_mapped_joints_to_position
|
||||
#define position_to_mapped_joints cnc_sim_trivkins_position_to_mapped_joints
|
||||
#define identityKinematicsSetup cnc_sim_trivkins_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_trivkins_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_trivkins_identityKinematicsInverse
|
||||
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
|
||||
|
||||
#define hal_init cnc_sim_trivkins_hal_init
|
||||
#define hal_ready cnc_sim_trivkins_hal_ready
|
||||
#define hal_exit cnc_sim_trivkins_hal_exit
|
||||
#define kinematicsForward cnc_sim_trivkins_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_trivkins_kinematicsInverse
|
||||
#define kinematicsSwitchable cnc_sim_trivkins_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_trivkins_kinematicsSwitch
|
||||
#define rtapi_app_main cnc_sim_trivkins_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_trivkins_rtapi_app_exit
|
||||
#define comp_id cnc_sim_trivkins_comp_id
|
||||
#define coordinates cnc_sim_trivkins_coordinates
|
||||
#define kinstype cnc_sim_trivkins_kinstype
|
||||
#include "../../../linuxcnc/src/emc/kinematics/trivkins.c"
|
||||
#undef kinstype
|
||||
#undef coordinates
|
||||
#undef comp_id
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef hal_exit
|
||||
#undef hal_ready
|
||||
#undef hal_init
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef position_to_mapped_joints
|
||||
#undef mapped_joints_to_position
|
||||
#undef map_coordinates_to_jnumbers
|
||||
#undef kinematicsType
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_trivkins_setup(void) {
|
||||
return cnc_sim_trivkins_rtapi_app_main();
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_trivkins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_trivkins_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_trivkins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_trivkins_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_trivkins_type(void) {
|
||||
return (int)cnc_sim_trivkins_kinematicsType();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
129
core/src/linuxcnc_trivkins_adapter.cpp
Normal file
129
core/src/linuxcnc_trivkins_adapter.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "linuxcnc_trivkins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_trivkins_setup(void);
|
||||
int cnc_sim_linuxcnc_trivkins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_trivkins_inverse(const EmcPose *pos, double *joints);
|
||||
int cnc_sim_linuxcnc_trivkins_type(void);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_trivkins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_trivkins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_trivkins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_trivkins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_trivkins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
|
||||
int linuxcnc_trivkins_source_kinematics_type() {
|
||||
if (!ensure_initialized()) {
|
||||
return 0;
|
||||
}
|
||||
return cnc_sim_linuxcnc_trivkins_type();
|
||||
}
|
||||
7
core/src/linuxcnc_trivkins_adapter.h
Normal file
7
core/src/linuxcnc_trivkins_adapter.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_trivkins_source_forward(const LinuxCncAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_trivkins_source_inverse(const CncSimPose &pose, LinuxCncAxisJoints *joints);
|
||||
int linuxcnc_trivkins_source_kinematics_type();
|
||||
207
core/src/linuxcnc_trtfuncs_adapter.c
Normal file
207
core/src/linuxcnc_trtfuncs_adapter.c
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_RTAPI_CTYPE_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
#define TO_RAD (PM_PI / 180.0)
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define EMCMOT_MAX_AXIS 9
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
static int cnc_sim_axis_idx_for_jno[EMCMOT_MAX_JOINTS];
|
||||
static int cnc_sim_max_joints;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int hal_pin_float_newf(hal_pin_dir_t dir, hal_float_t **data_ptr_addr, int comp_id, const char *fmt, ...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int hal_pin_bit_newf(hal_pin_dir_t dir, hal_bit_t **data_ptr_addr, int comp_id, const char *fmt, ...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int map_coordinates_to_jnumbers(const char *coordinates,
|
||||
const int max_joints,
|
||||
const int allow_duplicates,
|
||||
int axis_idx_for_jno[]) {
|
||||
(void)allow_duplicates;
|
||||
const char *letters = "XYZABCUVW";
|
||||
int jno = 0;
|
||||
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
|
||||
axis_idx_for_jno[i] = -1;
|
||||
cnc_sim_axis_idx_for_jno[i] = -1;
|
||||
}
|
||||
while (*coordinates) {
|
||||
const char *found = strchr(letters, toupper((unsigned char)*coordinates));
|
||||
if (!found || jno >= max_joints) {
|
||||
return -1;
|
||||
}
|
||||
axis_idx_for_jno[jno++] = (int)(found - letters);
|
||||
++coordinates;
|
||||
}
|
||||
cnc_sim_max_joints = jno;
|
||||
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
|
||||
cnc_sim_axis_idx_for_jno[i] = axis_idx_for_jno[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int position_to_mapped_joints(const int max_joints, const EmcPose *pos, double *joints) {
|
||||
for (int jno = 0; jno < max_joints; ++jno) {
|
||||
switch (cnc_sim_axis_idx_for_jno[jno]) {
|
||||
case 0: joints[jno] = pos->tran.x; break;
|
||||
case 1: joints[jno] = pos->tran.y; break;
|
||||
case 2: joints[jno] = pos->tran.z; break;
|
||||
case 3: joints[jno] = pos->a; break;
|
||||
case 4: joints[jno] = pos->b; break;
|
||||
case 5: joints[jno] = pos->c; break;
|
||||
case 6: joints[jno] = pos->u; break;
|
||||
case 7: joints[jno] = pos->v; break;
|
||||
case 8: joints[jno] = pos->w; break;
|
||||
default: joints[jno] = 0.0; break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define hal_malloc(size) ((struct haldata *)cnc_sim_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/trtfuncs.c"
|
||||
#undef hal_malloc
|
||||
|
||||
void cnc_sim_linuxcnc_trtfuncs_reset_setup_state(void) {
|
||||
trtfuncs_max_joints = 0;
|
||||
JX = -1;
|
||||
JY = -1;
|
||||
JZ = -1;
|
||||
JA = -1;
|
||||
JB = -1;
|
||||
JC = -1;
|
||||
JU = -1;
|
||||
JV = -1;
|
||||
JW = -1;
|
||||
haldata = NULL;
|
||||
cnc_sim_max_joints = 0;
|
||||
for (int i = 0; i < EMCMOT_MAX_JOINTS; ++i) {
|
||||
cnc_sim_axis_idx_for_jno[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_trtfuncs_setup_xyzbc(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "xyzbc-trt-kins";
|
||||
static char halprefix[] = "xyzbc-trt-kins";
|
||||
static char required_coordinates[] = "XYZBC";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.required_coordinates = required_coordinates;
|
||||
kp.max_joints = EMCMOT_MAX_JOINTS;
|
||||
kp.allow_duplicates = 1;
|
||||
return trtKinematicsSetup(0, "XYZBC", &kp);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_trtfuncs_setup_xyzac(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "xyzac-trt-kins";
|
||||
static char halprefix[] = "xyzac-trt-kins";
|
||||
static char required_coordinates[] = "XYZAC";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.required_coordinates = required_coordinates;
|
||||
kp.max_joints = EMCMOT_MAX_JOINTS;
|
||||
kp.allow_duplicates = 1;
|
||||
return trtKinematicsSetup(0, "XYZAC", &kp);
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_trtfuncs_set_pins(double x_rot_point,
|
||||
double y_rot_point,
|
||||
double z_rot_point,
|
||||
double x_offset,
|
||||
double y_offset,
|
||||
double z_offset,
|
||||
double tool_offset,
|
||||
bool conventional_directions) {
|
||||
*haldata->x_rot_point = x_rot_point;
|
||||
*haldata->y_rot_point = y_rot_point;
|
||||
*haldata->z_rot_point = z_rot_point;
|
||||
*haldata->x_offset = x_offset;
|
||||
*haldata->y_offset = y_offset;
|
||||
*haldata->z_offset = z_offset;
|
||||
*haldata->tool_offset = tool_offset;
|
||||
*haldata->conventional_directions = conventional_directions;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
241
core/src/linuxcnc_trtfuncs_adapter.cpp
Normal file
241
core/src/linuxcnc_trtfuncs_adapter.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "linuxcnc_trtfuncs_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
int cnc_sim_linuxcnc_trtfuncs_setup_xyzbc(void);
|
||||
int cnc_sim_linuxcnc_trtfuncs_setup_xyzac(void);
|
||||
void cnc_sim_linuxcnc_trtfuncs_set_pins(double x_rot_point,
|
||||
double y_rot_point,
|
||||
double z_rot_point,
|
||||
double x_offset,
|
||||
double y_offset,
|
||||
double z_offset,
|
||||
double tool_offset,
|
||||
bool conventional_directions);
|
||||
void cnc_sim_linuxcnc_trtfuncs_reset_setup_state(void);
|
||||
int xyzbcKinematicsForward(const double *joints,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
int xyzbcKinematicsInverse(const EmcPose *pos,
|
||||
double *joints,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
int xyzacKinematicsForward(const double *joints,
|
||||
EmcPose *pos,
|
||||
const KINEMATICS_FORWARD_FLAGS *fflags,
|
||||
KINEMATICS_INVERSE_FLAGS *iflags);
|
||||
int xyzacKinematicsInverse(const EmcPose *pos,
|
||||
double *joints,
|
||||
const KINEMATICS_INVERSE_FLAGS *iflags,
|
||||
KINEMATICS_FORWARD_FLAGS *fflags);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum class TrtSetup {
|
||||
None,
|
||||
Xyzbc,
|
||||
Xyzac,
|
||||
};
|
||||
|
||||
TrtSetup current_setup = TrtSetup::None;
|
||||
|
||||
bool ensure_xyzbc() {
|
||||
if (current_setup == TrtSetup::Xyzbc) {
|
||||
return true;
|
||||
}
|
||||
cnc_sim_linuxcnc_trtfuncs_reset_setup_state();
|
||||
if (cnc_sim_linuxcnc_trtfuncs_setup_xyzbc() != 0) {
|
||||
current_setup = TrtSetup::None;
|
||||
return false;
|
||||
}
|
||||
current_setup = TrtSetup::Xyzbc;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ensure_xyzac() {
|
||||
if (current_setup == TrtSetup::Xyzac) {
|
||||
return true;
|
||||
}
|
||||
cnc_sim_linuxcnc_trtfuncs_reset_setup_state();
|
||||
if (cnc_sim_linuxcnc_trtfuncs_setup_xyzac() != 0) {
|
||||
current_setup = TrtSetup::None;
|
||||
return false;
|
||||
}
|
||||
current_setup = TrtSetup::Xyzac;
|
||||
return true;
|
||||
}
|
||||
|
||||
void apply_parameters(const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
cnc_sim_linuxcnc_trtfuncs_set_pins(parameters.x_rot_point,
|
||||
parameters.y_rot_point,
|
||||
parameters.z_rot_point,
|
||||
parameters.x_offset,
|
||||
parameters.y_offset,
|
||||
parameters.z_offset,
|
||||
parameters.tool_offset,
|
||||
parameters.conventional_directions);
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
void to_xyzbc_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.b;
|
||||
out[4] = joints.c;
|
||||
}
|
||||
|
||||
void to_xyzac_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.c;
|
||||
}
|
||||
|
||||
LinuxCncFiveAxisJoints from_xyzbc_joints(const double joints[16]) {
|
||||
LinuxCncFiveAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.b = joints[3];
|
||||
out.c = joints[4];
|
||||
return out;
|
||||
}
|
||||
|
||||
LinuxCncFiveAxisJoints from_xyzac_joints(const double joints[16]) {
|
||||
LinuxCncFiveAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.c = joints[4];
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_trtfuncs_xyzbc_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_xyzbc()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
double raw_joints[16];
|
||||
to_xyzbc_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
if (xyzbcKinematicsForward(raw_joints, &out, &fflags, &iflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_trtfuncs_xyzbc_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
LinuxCncFiveAxisJoints *joints) {
|
||||
if (!ensure_xyzbc()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
if (xyzbcKinematicsInverse(&in, raw_joints, &iflags, &fflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_xyzbc_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_trtfuncs_xyzac_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_xyzac()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
double raw_joints[16];
|
||||
to_xyzac_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
if (xyzacKinematicsForward(raw_joints, &out, &fflags, &iflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_trtfuncs_xyzac_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
LinuxCncFiveAxisJoints *joints) {
|
||||
if (!ensure_xyzac()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
if (xyzacKinematicsInverse(&in, raw_joints, &iflags, &fflags) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_xyzac_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
16
core/src/linuxcnc_trtfuncs_adapter.h
Normal file
16
core/src/linuxcnc_trtfuncs_adapter.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_trtfuncs_xyzbc_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_trtfuncs_xyzbc_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
LinuxCncFiveAxisJoints *joints);
|
||||
bool linuxcnc_trtfuncs_xyzac_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_trtfuncs_xyzac_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters,
|
||||
LinuxCncFiveAxisJoints *joints);
|
||||
154
core/src/linuxcnc_userkfuncs_adapter.c
Normal file
154
core/src/linuxcnc_userkfuncs_adapter.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_EMCMOTCFG_H
|
||||
#define __LINUXCNC_EMCPOS_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define EMCMOT_MAX_JOINTS 16
|
||||
#define EMCMOT_MAX_AXIS 9
|
||||
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cnc_sim_userk_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_userk_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_userk_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_userk_hal_pin_s32_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_s32_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
KINEMATICS_TYPE cnc_sim_userk_kinematicsType(void) {
|
||||
return KINEMATICS_BOTH;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_userk_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_userk_rtapi_print_msg
|
||||
#define kinematicsType cnc_sim_userk_kinematicsType
|
||||
#define hal_pin_s32_new cnc_sim_userk_hal_pin_s32_new
|
||||
#define map_coordinates_to_jnumbers cnc_sim_userk_map_coordinates_to_jnumbers
|
||||
#define mapped_joints_to_position cnc_sim_userk_mapped_joints_to_position
|
||||
#define position_to_mapped_joints cnc_sim_userk_position_to_mapped_joints
|
||||
#define identityKinematicsSetup cnc_sim_userk_identityKinematicsSetup
|
||||
#define identityKinematicsForward cnc_sim_userk_identityKinematicsForward
|
||||
#define identityKinematicsInverse cnc_sim_userk_identityKinematicsInverse
|
||||
#define userkKinematicsSetup cnc_sim_userk_userkKinematicsSetup
|
||||
#define userkKinematicsForward cnc_sim_userk_userkKinematicsForward
|
||||
#define userkKinematicsInverse cnc_sim_userk_userkKinematicsInverse
|
||||
#include "../../../linuxcnc/src/emc/kinematics/kins_util.c"
|
||||
#define hal_malloc(size) ((struct udata *)cnc_sim_userk_hal_malloc(size))
|
||||
#include "../../../linuxcnc/src/emc/kinematics/userkfuncs.c"
|
||||
#undef hal_malloc
|
||||
#undef userkKinematicsInverse
|
||||
#undef userkKinematicsForward
|
||||
#undef userkKinematicsSetup
|
||||
#undef identityKinematicsInverse
|
||||
#undef identityKinematicsForward
|
||||
#undef identityKinematicsSetup
|
||||
#undef position_to_mapped_joints
|
||||
#undef mapped_joints_to_position
|
||||
#undef map_coordinates_to_jnumbers
|
||||
#undef hal_pin_s32_new
|
||||
#undef kinematicsType
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_userkfuncs_setup(void) {
|
||||
kparms kp = {0};
|
||||
static char kinsname[] = "userkfuncs";
|
||||
static char halprefix[] = "userk";
|
||||
kp.kinsname = kinsname;
|
||||
kp.halprefix = halprefix;
|
||||
kp.max_joints = EMCMOT_MAX_JOINTS;
|
||||
kp.allow_duplicates = 1;
|
||||
if (cnc_sim_userk_identityKinematicsSetup(0, "XYZBC", &kp) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return cnc_sim_userk_userkKinematicsSetup(0, "XYZBC", &kp);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_userkfuncs_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_userk_userkKinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_userkfuncs_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_userk_userkKinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
113
core/src/linuxcnc_userkfuncs_adapter.cpp
Normal file
113
core/src/linuxcnc_userkfuncs_adapter.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "linuxcnc_userkfuncs_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_userkfuncs_setup(void);
|
||||
int cnc_sim_linuxcnc_userkfuncs_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_userkfuncs_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_userkfuncs_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncFiveAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.b;
|
||||
out[4] = joints.c;
|
||||
}
|
||||
|
||||
LinuxCncFiveAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncFiveAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.b = joints[3];
|
||||
out.c = joints[4];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_userkfuncs_forward(const LinuxCncFiveAxisJoints &joints, CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_userkfuncs_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_userkfuncs_inverse(const CncSimPose &pose, LinuxCncFiveAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_userkfuncs_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
6
core/src/linuxcnc_userkfuncs_adapter.h
Normal file
6
core/src/linuxcnc_userkfuncs_adapter.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_userkfuncs_forward(const LinuxCncFiveAxisJoints &joints, CncSimPose *pose);
|
||||
bool linuxcnc_userkfuncs_inverse(const CncSimPose &pose, LinuxCncFiveAxisJoints *joints);
|
||||
241
core/src/linuxcnc_xyzab_tdr_kins_adapter.c
Normal file
241
core/src/linuxcnc_xyzab_tdr_kins_adapter.c
Normal file
@@ -0,0 +1,241 @@
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __LINUXCNC_RTAPI_H
|
||||
#define __LINUXCNC_RTAPI_APP_H
|
||||
#define __LINUXCNC_RTAPI_STRING_H
|
||||
#define __LINUXCNC_RTAPI_ERRNO_H
|
||||
#define __LINUXCNC_RTAPI_MATH_H
|
||||
#define __LINUXCNC_RTAPI_MATH64_H
|
||||
#define __LINUXCNC_HAL_H
|
||||
#define __LINUXCNC_KINEMATICS_H
|
||||
|
||||
#define MODULE_INFO(...)
|
||||
#define MODULE_LICENSE(...)
|
||||
#define EXPORT_SYMBOL(symbol)
|
||||
#define RTAPI_MP_INT(name, description)
|
||||
#define RTAPI_MP_STRING(name, description)
|
||||
|
||||
#define RTAPI_MSG_ERR 1
|
||||
#define RTAPI_MSG_INFO 2
|
||||
#define HAL_NAME_LEN 47
|
||||
#define EINVAL 22
|
||||
#define PM_PI 3.1415926535897932384626433832795029
|
||||
#define TO_RAD (PM_PI / 180.0)
|
||||
|
||||
typedef double real_t;
|
||||
typedef double hal_float_t;
|
||||
typedef int hal_s32_t;
|
||||
typedef unsigned int hal_u32_t;
|
||||
typedef bool hal_bit_t;
|
||||
typedef enum { HAL_IN = 16, HAL_OUT = 32, HAL_IO = (HAL_IN | HAL_OUT) } hal_pin_dir_t;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} PmCartesian;
|
||||
|
||||
typedef struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
} EmcPose;
|
||||
|
||||
typedef enum {
|
||||
KINEMATICS_IDENTITY = 1,
|
||||
KINEMATICS_FORWARD_ONLY,
|
||||
KINEMATICS_INVERSE_ONLY,
|
||||
KINEMATICS_BOTH
|
||||
} KINEMATICS_TYPE;
|
||||
|
||||
typedef unsigned long int KINEMATICS_FORWARD_FLAGS;
|
||||
typedef unsigned long int KINEMATICS_INVERSE_FLAGS;
|
||||
|
||||
typedef struct kinematics_parms {
|
||||
char *sparm;
|
||||
char *kinsname;
|
||||
char *halprefix;
|
||||
char *required_coordinates;
|
||||
int max_joints;
|
||||
int allow_duplicates;
|
||||
int fwd_iterates_mask;
|
||||
int gui_kinstype;
|
||||
} kparms;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int __attribute__((weak)) rtapi_snprintf(char *str, unsigned long int size, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int result = vsnprintf(str, (size_t)size, fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
void cnc_sim_xyzab_tdr_rtapi_print(const char *fmt, ...) {
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void cnc_sim_xyzab_tdr_rtapi_print_msg(int level, const char *fmt, ...) {
|
||||
(void)level;
|
||||
(void)fmt;
|
||||
}
|
||||
|
||||
void *cnc_sim_xyzab_tdr_hal_malloc(long int size) {
|
||||
return calloc(1, (size_t)size);
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_init(const char *name) {
|
||||
(void)name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cnc_sim_xyzab_tdr_hal_exit(int comp_id) {
|
||||
(void)comp_id;
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_ready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_set_unready(int comp_id) {
|
||||
(void)comp_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_pin_s32_newf(hal_pin_dir_t dir,
|
||||
hal_s32_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_s32_t *)calloc(1, sizeof(hal_s32_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_pin_float_newf(hal_pin_dir_t dir,
|
||||
hal_float_t **data_ptr_addr,
|
||||
int comp_id,
|
||||
const char *fmt,
|
||||
...) {
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
(void)fmt;
|
||||
*data_ptr_addr = (hal_float_t *)calloc(1, sizeof(hal_float_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
int cnc_sim_xyzab_tdr_hal_pin_bit_new(const char *name,
|
||||
hal_pin_dir_t dir,
|
||||
hal_bit_t **data_ptr_addr,
|
||||
int comp_id) {
|
||||
(void)name;
|
||||
(void)dir;
|
||||
(void)comp_id;
|
||||
*data_ptr_addr = (hal_bit_t *)calloc(1, sizeof(hal_bit_t));
|
||||
return *data_ptr_addr ? 0 : -1;
|
||||
}
|
||||
|
||||
#define rtapi_print cnc_sim_xyzab_tdr_rtapi_print
|
||||
#define rtapi_print_msg cnc_sim_xyzab_tdr_rtapi_print_msg
|
||||
#define hal_malloc(size) cnc_sim_xyzab_tdr_hal_malloc(size)
|
||||
#define hal_init cnc_sim_xyzab_tdr_hal_init
|
||||
#define hal_exit cnc_sim_xyzab_tdr_hal_exit
|
||||
#define hal_ready cnc_sim_xyzab_tdr_hal_ready
|
||||
#define hal_set_unready cnc_sim_xyzab_tdr_hal_set_unready
|
||||
#define hal_pin_s32_newf cnc_sim_xyzab_tdr_hal_pin_s32_newf
|
||||
#define hal_pin_float_newf cnc_sim_xyzab_tdr_hal_pin_float_newf
|
||||
#define hal_pin_bit_new cnc_sim_xyzab_tdr_hal_pin_bit_new
|
||||
#define kinematicsType cnc_sim_xyzab_tdr_kinematicsType
|
||||
#define kinematicsSwitchable cnc_sim_xyzab_tdr_kinematicsSwitchable
|
||||
#define kinematicsSwitch cnc_sim_xyzab_tdr_kinematicsSwitch
|
||||
#define kinematicsForward cnc_sim_xyzab_tdr_kinematicsForward
|
||||
#define kinematicsInverse cnc_sim_xyzab_tdr_kinematicsInverse
|
||||
#define rtapi_app_main cnc_sim_xyzab_tdr_rtapi_app_main
|
||||
#define rtapi_app_exit cnc_sim_xyzab_tdr_rtapi_app_exit
|
||||
#define export cnc_sim_xyzab_tdr_export
|
||||
#include "../../../linuxcnc/src/objects/hal/components/xyzab_tdr_kins.c"
|
||||
#undef export
|
||||
#undef rtapi_app_exit
|
||||
#undef rtapi_app_main
|
||||
#undef kinematicsInverse
|
||||
#undef kinematicsForward
|
||||
#undef kinematicsSwitch
|
||||
#undef kinematicsSwitchable
|
||||
#undef kinematicsType
|
||||
#undef hal_pin_bit_new
|
||||
#undef hal_pin_float_newf
|
||||
#undef hal_pin_s32_newf
|
||||
#undef hal_set_unready
|
||||
#undef hal_ready
|
||||
#undef hal_exit
|
||||
#undef hal_init
|
||||
#undef hal_malloc
|
||||
#undef rtapi_print_msg
|
||||
#undef rtapi_print
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_setup(void) {
|
||||
return cnc_sim_xyzab_tdr_kinematicsType() == KINEMATICS_BOTH ? 0 : -1;
|
||||
}
|
||||
|
||||
void cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(double tool_offset_z,
|
||||
double x_offset,
|
||||
double z_offset,
|
||||
double x_rot_point,
|
||||
double y_rot_point,
|
||||
double z_rot_point) {
|
||||
*haldata->tool_offset_z = tool_offset_z;
|
||||
*haldata->x_offset = x_offset;
|
||||
*haldata->z_offset = z_offset;
|
||||
*haldata->x_rot_point = x_rot_point;
|
||||
*haldata->y_rot_point = y_rot_point;
|
||||
*haldata->z_rot_point = z_rot_point;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch(int switchkins_type) {
|
||||
return cnc_sim_xyzab_tdr_kinematicsSwitch(switchkins_type);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(int *kinstype_is_0, int *kinstype_is_1) {
|
||||
if (!haldata || !haldata->kinstype_is_0 || !haldata->kinstype_is_1) {
|
||||
return -1;
|
||||
}
|
||||
if (kinstype_is_0) {
|
||||
*kinstype_is_0 = *haldata->kinstype_is_0 ? 1 : 0;
|
||||
}
|
||||
if (kinstype_is_1) {
|
||||
*kinstype_is_1 = *haldata->kinstype_is_1 ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_forward(const double *joints, EmcPose *pos) {
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
return cnc_sim_xyzab_tdr_kinematicsForward(joints, pos, &fflags, &iflags);
|
||||
}
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(const EmcPose *pos, double *joints) {
|
||||
KINEMATICS_INVERSE_FLAGS iflags = 0;
|
||||
KINEMATICS_FORWARD_FLAGS fflags = 0;
|
||||
return cnc_sim_xyzab_tdr_kinematicsInverse(pos, joints, &iflags, &fflags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
177
core/src/linuxcnc_xyzab_tdr_kins_adapter.cpp
Normal file
177
core/src/linuxcnc_xyzab_tdr_kins_adapter.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#include "linuxcnc_xyzab_tdr_kins_adapter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
struct PmCartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct EmcPose {
|
||||
PmCartesian tran;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_setup(void);
|
||||
void cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(double tool_offset_z,
|
||||
double x_offset,
|
||||
double z_offset,
|
||||
double x_rot_point,
|
||||
double y_rot_point,
|
||||
double z_rot_point);
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch(int switchkins_type);
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(int *kinstype_is_0, int *kinstype_is_1);
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_forward(const double *joints, EmcPose *pos);
|
||||
int cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(const EmcPose *pos, double *joints);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
bool ensure_initialized() {
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
initialized = cnc_sim_linuxcnc_xyzab_tdr_kins_setup() == 0;
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void apply_parameters(const LinuxCncXyzabTdrParameters ¶meters) {
|
||||
cnc_sim_linuxcnc_xyzab_tdr_kins_set_parameters(parameters.tool_offset_z,
|
||||
parameters.x_offset,
|
||||
parameters.z_offset,
|
||||
parameters.x_rot_point,
|
||||
parameters.y_rot_point,
|
||||
parameters.z_rot_point);
|
||||
}
|
||||
|
||||
void to_joints(const LinuxCncAxisJoints &joints, double out[16]) {
|
||||
std::memset(out, 0, sizeof(double) * 16);
|
||||
out[0] = joints.x;
|
||||
out[1] = joints.y;
|
||||
out[2] = joints.z;
|
||||
out[3] = joints.a;
|
||||
out[4] = joints.b;
|
||||
out[5] = joints.c;
|
||||
out[6] = joints.u;
|
||||
out[7] = joints.v;
|
||||
out[8] = joints.w;
|
||||
}
|
||||
|
||||
LinuxCncAxisJoints from_joints(const double joints[16]) {
|
||||
LinuxCncAxisJoints out{};
|
||||
out.x = joints[0];
|
||||
out.y = joints[1];
|
||||
out.z = joints[2];
|
||||
out.a = joints[3];
|
||||
out.b = joints[4];
|
||||
out.c = joints[5];
|
||||
out.u = joints[6];
|
||||
out.v = joints[7];
|
||||
out.w = joints[8];
|
||||
return out;
|
||||
}
|
||||
|
||||
EmcPose to_emc_pose(const CncSimPose &pose) {
|
||||
EmcPose emc{};
|
||||
emc.tran.x = pose.x;
|
||||
emc.tran.y = pose.y;
|
||||
emc.tran.z = pose.z;
|
||||
emc.a = pose.a;
|
||||
emc.b = pose.b;
|
||||
emc.c = pose.c;
|
||||
emc.u = pose.u;
|
||||
emc.v = pose.v;
|
||||
emc.w = pose.w;
|
||||
return emc;
|
||||
}
|
||||
|
||||
CncSimPose from_emc_pose(const EmcPose &emc) {
|
||||
CncSimPose pose{};
|
||||
pose.x = emc.tran.x;
|
||||
pose.y = emc.tran.y;
|
||||
pose.z = emc.tran.z;
|
||||
pose.a = emc.a;
|
||||
pose.b = emc.b;
|
||||
pose.c = emc.c;
|
||||
pose.u = emc.u;
|
||||
pose.v = emc.v;
|
||||
pose.w = emc.w;
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool linuxcnc_xyzab_tdr_kins_switch(int switchkins_type) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
return cnc_sim_linuxcnc_xyzab_tdr_kins_switch(switchkins_type) == 0;
|
||||
}
|
||||
|
||||
bool linuxcnc_xyzab_tdr_kins_switch_state(bool *kinstype_is_0, bool *kinstype_is_1) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
int raw_kinstype_is_0 = 0;
|
||||
int raw_kinstype_is_1 = 0;
|
||||
if (cnc_sim_linuxcnc_xyzab_tdr_kins_switch_state(&raw_kinstype_is_0, &raw_kinstype_is_1) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (kinstype_is_0) {
|
||||
*kinstype_is_0 = raw_kinstype_is_0 != 0;
|
||||
}
|
||||
if (kinstype_is_1) {
|
||||
*kinstype_is_1 = raw_kinstype_is_1 != 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_xyzab_tdr_kins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncXyzabTdrParameters ¶meters,
|
||||
int switchkins_type,
|
||||
CncSimPose *pose) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
if (!linuxcnc_xyzab_tdr_kins_switch(switchkins_type)) {
|
||||
return false;
|
||||
}
|
||||
double raw_joints[16];
|
||||
to_joints(joints, raw_joints);
|
||||
EmcPose out{};
|
||||
if (cnc_sim_linuxcnc_xyzab_tdr_kins_forward(raw_joints, &out) != 0) {
|
||||
return false;
|
||||
}
|
||||
*pose = from_emc_pose(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linuxcnc_xyzab_tdr_kins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzabTdrParameters ¶meters,
|
||||
int switchkins_type,
|
||||
LinuxCncAxisJoints *joints) {
|
||||
if (!ensure_initialized()) {
|
||||
return false;
|
||||
}
|
||||
apply_parameters(parameters);
|
||||
if (!linuxcnc_xyzab_tdr_kins_switch(switchkins_type)) {
|
||||
return false;
|
||||
}
|
||||
const EmcPose in = to_emc_pose(pose);
|
||||
double raw_joints[16] = {};
|
||||
if (cnc_sim_linuxcnc_xyzab_tdr_kins_inverse(&in, raw_joints) != 0) {
|
||||
return false;
|
||||
}
|
||||
*joints = from_joints(raw_joints);
|
||||
return true;
|
||||
}
|
||||
14
core/src/linuxcnc_xyzab_tdr_kins_adapter.h
Normal file
14
core/src/linuxcnc_xyzab_tdr_kins_adapter.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
bool linuxcnc_xyzab_tdr_kins_switch(int switchkins_type);
|
||||
bool linuxcnc_xyzab_tdr_kins_switch_state(bool *kinstype_is_0, bool *kinstype_is_1);
|
||||
bool linuxcnc_xyzab_tdr_kins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncXyzabTdrParameters ¶meters,
|
||||
int switchkins_type,
|
||||
CncSimPose *pose);
|
||||
bool linuxcnc_xyzab_tdr_kins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzabTdrParameters ¶meters,
|
||||
int switchkins_type,
|
||||
LinuxCncAxisJoints *joints);
|
||||
@@ -1,72 +1,497 @@
|
||||
#include "rtcp_kinematics.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "linuxcnc_5axiskins_adapter.h"
|
||||
#include "linuxcnc_corexykins_adapter.h"
|
||||
#include "linuxcnc_genhexkins_adapter.h"
|
||||
#include "linuxcnc_genserfuncs_adapter.h"
|
||||
#include "linuxcnc_kins_util_adapter.h"
|
||||
#include "linuxcnc_lineardeltakins_adapter.h"
|
||||
#include "linuxcnc_maxkins_adapter.h"
|
||||
#include "linuxcnc_pentakins_adapter.h"
|
||||
#include "linuxcnc_pumakins_adapter.h"
|
||||
#include "linuxcnc_rotatekins_adapter.h"
|
||||
#include "linuxcnc_rosekins_adapter.h"
|
||||
#include "linuxcnc_rotarydeltakins_adapter.h"
|
||||
#include "linuxcnc_scarakins_adapter.h"
|
||||
#include "linuxcnc_scorbot_kins_adapter.h"
|
||||
#include "linuxcnc_tripodkins_adapter.h"
|
||||
#include "linuxcnc_trtfuncs_adapter.h"
|
||||
#include "linuxcnc_userkfuncs_adapter.h"
|
||||
#include "linuxcnc_xyzab_tdr_kins_adapter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr double kPi = 3.141592653589793238462643383279502884;
|
||||
|
||||
double radians(double degrees) {
|
||||
return degrees * kPi / 180.0;
|
||||
LinuxCncAxisJoints linuxcnc_identity_default_joints() {
|
||||
return {};
|
||||
}
|
||||
|
||||
RtcpVector rotate_x(RtcpVector vector, double angle) {
|
||||
const double c = std::cos(angle);
|
||||
const double s = std::sin(angle);
|
||||
return {
|
||||
vector.x,
|
||||
vector.y * c - vector.z * s,
|
||||
vector.y * s + vector.z * c,
|
||||
};
|
||||
// Source: linuxcnc/src/emc/kinematics/kins_util.c
|
||||
// Mirrors identityKinematicsForward() with default XYZABCUVW coordinate mapping.
|
||||
CncSimPose linuxcnc_identity_forward(const LinuxCncAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_kins_util_identity_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
RtcpVector rotate_y(RtcpVector vector, double angle) {
|
||||
const double c = std::cos(angle);
|
||||
const double s = std::sin(angle);
|
||||
return {
|
||||
vector.x * c + vector.z * s,
|
||||
vector.y,
|
||||
-vector.x * s + vector.z * c,
|
||||
};
|
||||
// Source: linuxcnc/src/emc/kinematics/kins_util.c
|
||||
// Mirrors identityKinematicsInverse() with default XYZABCUVW coordinate mapping.
|
||||
LinuxCncAxisJoints linuxcnc_identity_inverse(const CncSimPose &pose) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_kins_util_identity_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
RtcpVector rotate_z(RtcpVector vector, double angle) {
|
||||
const double c = std::cos(angle);
|
||||
const double s = std::sin(angle);
|
||||
return {
|
||||
vector.x * c - vector.y * s,
|
||||
vector.x * s + vector.y * c,
|
||||
vector.z,
|
||||
};
|
||||
// Source: linuxcnc/src/emc/kinematics/trivkins.c
|
||||
// kinematicsForward()/kinematicsInverse() delegate to identityKinematics*().
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/corexykins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_corexykins_forward(const LinuxCncAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_corexykins_source_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RtcpVector rtcp_rotate_abc_degrees(RtcpVector vector, double a_deg, double b_deg, double c_deg) {
|
||||
vector = rotate_x(vector, radians(a_deg));
|
||||
vector = rotate_y(vector, radians(b_deg));
|
||||
vector = rotate_z(vector, radians(c_deg));
|
||||
return vector;
|
||||
// Source: linuxcnc/src/emc/kinematics/corexykins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_corexykins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_corexykins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
RtcpVector rtcp_tool_vector_from_pose(const CncSimPose &pose, double tool_length) {
|
||||
return rtcp_rotate_abc_degrees({0.0, 0.0, -tool_length}, pose.a, pose.b, pose.c);
|
||||
// Source: linuxcnc/src/emc/kinematics/rotatekins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_rotatekins_forward(const LinuxCncAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_rotatekins_source_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
CncSimPose rtcp_pivot_from_tool_tip(const CncSimPose &tool_tip, double tool_length) {
|
||||
const RtcpVector tool = rtcp_tool_vector_from_pose(tool_tip, tool_length);
|
||||
CncSimPose pivot = tool_tip;
|
||||
pivot.x = tool_tip.x - tool.x;
|
||||
pivot.y = tool_tip.y - tool.y;
|
||||
pivot.z = tool_tip.z - tool.z;
|
||||
return pivot;
|
||||
// Source: linuxcnc/src/emc/kinematics/rotatekins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_rotatekins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_rotatekins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
CncSimPose rtcp_tool_tip_from_pivot(const CncSimPose &pivot, double tool_length) {
|
||||
const RtcpVector tool = rtcp_tool_vector_from_pose(pivot, tool_length);
|
||||
CncSimPose tool_tip = pivot;
|
||||
tool_tip.x = pivot.x + tool.x;
|
||||
tool_tip.y = pivot.y + tool.y;
|
||||
tool_tip.z = pivot.z + tool.z;
|
||||
return tool_tip;
|
||||
// Source: linuxcnc/src/emc/kinematics/genhexkins.c
|
||||
// Mirrors genhexKinematicsInverse().
|
||||
LinuxCncGenhexJoints linuxcnc_genhex_inverse(const CncSimPose &pose) {
|
||||
LinuxCncGenhexJoints joints{};
|
||||
linuxcnc_genhexkins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/genhexkins.c
|
||||
// Mirrors genhexKinematicsForward().
|
||||
CncSimPose linuxcnc_genhex_forward(const LinuxCncGenhexJoints &joints, const CncSimPose &initial_pose) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_genhexkins_source_forward(joints, initial_pose, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/pentakins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncPentakinsJoints linuxcnc_pentakins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncPentakinsJoints joints{};
|
||||
linuxcnc_pentakins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/pentakins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_pentakins_forward(const LinuxCncPentakinsJoints &joints,
|
||||
const CncSimPose &initial_pose) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_pentakins_source_forward(joints, initial_pose, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/tripodkins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncTripodJoints linuxcnc_tripodkins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncTripodJoints joints{};
|
||||
linuxcnc_tripodkins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/tripodkins.c
|
||||
// Mirrors kinematicsForward() with the default positive-Z forward flag.
|
||||
CncSimPose linuxcnc_tripodkins_forward(const LinuxCncTripodJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_tripodkins_source_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/scorbot-kins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncScorbotJoints linuxcnc_scorbot_kins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncScorbotJoints joints{};
|
||||
linuxcnc_scorbot_kins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/scorbot-kins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_scorbot_kins_forward(const LinuxCncScorbotJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_scorbot_kins_source_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source defaults: linuxcnc/src/emc/kinematics/lineardeltakins-common.h
|
||||
LinuxCncLinearDeltaParameters linuxcnc_lineardelta_default_parameters() {
|
||||
LinuxCncLinearDeltaParameters parameters{};
|
||||
linuxcnc_lineardeltakins_source_default_parameters(¶meters);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/lineardeltakins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_lineardelta_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncLinearDeltaParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_lineardeltakins_source_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/lineardeltakins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_lineardelta_inverse(const CncSimPose &pose,
|
||||
const LinuxCncLinearDeltaParameters ¶meters) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_lineardeltakins_source_inverse(pose, parameters, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source defaults: linuxcnc/src/emc/kinematics/rotarydeltakins-common.h
|
||||
LinuxCncRotaryDeltaParameters linuxcnc_rotarydelta_default_parameters() {
|
||||
LinuxCncRotaryDeltaParameters parameters{};
|
||||
linuxcnc_rotarydeltakins_source_default_parameters(¶meters);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/rotarydeltakins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_rotarydelta_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_rotarydeltakins_source_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/rotarydeltakins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_rotarydelta_inverse(const CncSimPose &pose,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_rotarydeltakins_source_inverse(pose, parameters, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source defaults: linuxcnc/src/emc/kinematics/maxkins.c
|
||||
LinuxCncMaxkinsParameters linuxcnc_maxkins_default_parameters() {
|
||||
LinuxCncMaxkinsParameters parameters{};
|
||||
linuxcnc_maxkins_source_default_parameters(¶meters);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/maxkins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_maxkins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncMaxkinsParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_maxkins_source_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/maxkins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_maxkins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncMaxkinsParameters ¶meters) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_maxkins_source_inverse(pose, parameters, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/rosekins.c
|
||||
// Mirrors kinematicsForward().
|
||||
CncSimPose linuxcnc_rosekins_forward(const LinuxCncAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_rosekins_source_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/rosekins.c
|
||||
// Mirrors kinematicsInverse().
|
||||
LinuxCncAxisJoints linuxcnc_rosekins_inverse(const CncSimPose &pose) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_rosekins_source_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/5axiskins.c
|
||||
// Mirrors s2r(), fiveaxis_KinematicsForward().
|
||||
CncSimPose linuxcnc_5axis_forward(const LinuxCncFiveAxisJoints &joints, double pivot_length) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_5axiskins_forward(joints, pivot_length, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/5axiskins.c
|
||||
// Mirrors s2r(), fiveaxis_KinematicsInverse().
|
||||
LinuxCncFiveAxisJoints linuxcnc_5axis_inverse(const CncSimPose &pose, double pivot_length) {
|
||||
LinuxCncFiveAxisJoints joints{};
|
||||
linuxcnc_5axiskins_inverse(pose, pivot_length, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source defaults: linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzbc-trt.ini
|
||||
LinuxCncXyzbcTrtParameters linuxcnc_xyzbc_trt_default_parameters(double tool_offset) {
|
||||
LinuxCncXyzbcTrtParameters parameters{};
|
||||
parameters.x_offset = -20.0;
|
||||
parameters.y_offset = 0.0;
|
||||
parameters.z_offset = -15.0;
|
||||
parameters.tool_offset = tool_offset;
|
||||
parameters.conventional_directions = false;
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/trtfuncs.c
|
||||
// Mirrors xyzbcKinematicsForward().
|
||||
CncSimPose linuxcnc_xyzbc_trt_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_trtfuncs_xyzbc_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/trtfuncs.c
|
||||
// Mirrors xyzbcKinematicsInverse().
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzbc_trt_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
LinuxCncFiveAxisJoints joints{};
|
||||
linuxcnc_trtfuncs_xyzbc_inverse(pose, parameters, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/trtfuncs.c
|
||||
// Mirrors xyzacKinematicsForward().
|
||||
CncSimPose linuxcnc_xyzac_trt_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_trtfuncs_xyzac_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/trtfuncs.c
|
||||
// Mirrors xyzacKinematicsInverse().
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzac_trt_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters) {
|
||||
LinuxCncFiveAxisJoints joints{};
|
||||
linuxcnc_trtfuncs_xyzac_inverse(pose, parameters, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/userkfuncs.c
|
||||
// userkKinematicsForward() delegates to identityKinematicsForward(),
|
||||
// implemented in linuxcnc/src/emc/kinematics/kins_util.c.
|
||||
CncSimPose linuxcnc_xyzbc_userk_forward(const LinuxCncFiveAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_userkfuncs_forward(joints, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/userkfuncs.c
|
||||
// userkKinematicsInverse() delegates to identityKinematicsInverse(),
|
||||
// implemented in linuxcnc/src/emc/kinematics/kins_util.c.
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzbc_userk_inverse(const CncSimPose &pose) {
|
||||
LinuxCncFiveAxisJoints joints{};
|
||||
linuxcnc_userkfuncs_inverse(pose, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source defaults: linuxcnc/src/emc/kinematics/scarakins.c
|
||||
LinuxCncScaraParameters linuxcnc_scara_default_parameters() {
|
||||
LinuxCncScaraParameters parameters{};
|
||||
parameters.d1 = 490.0;
|
||||
parameters.d2 = 340.0;
|
||||
parameters.d3 = 50.0;
|
||||
parameters.d4 = 250.0;
|
||||
parameters.d5 = 50.0;
|
||||
parameters.d6 = 50.0;
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/scarakins.c
|
||||
CncSimPose linuxcnc_scara_forward(const LinuxCncScaraJoints &joints,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int *iflags) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_scarakins_forward(joints, parameters, &pose, iflags);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/scarakins.c
|
||||
LinuxCncScaraJoints linuxcnc_scara_inverse(const CncSimPose &pose,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int iflags) {
|
||||
LinuxCncScaraJoints joints{};
|
||||
linuxcnc_scarakins_inverse(pose, parameters, iflags, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
LinuxCncXyzabTdrParameters linuxcnc_xyzab_tdr_default_parameters(double tool_offset_z) {
|
||||
LinuxCncXyzabTdrParameters parameters{};
|
||||
parameters.tool_offset_z = tool_offset_z;
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/hal/components/xyzab_tdr_kins.comp
|
||||
// Mirrors kinematicsForward() switchkins type 0.
|
||||
CncSimPose linuxcnc_xyzab_tdr_identity_forward(const LinuxCncAxisJoints &joints) {
|
||||
CncSimPose pose{};
|
||||
LinuxCncXyzabTdrParameters parameters{};
|
||||
linuxcnc_xyzab_tdr_kins_forward(joints, parameters, 0, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/hal/components/xyzab_tdr_kins.comp
|
||||
// Mirrors kinematicsInverse() switchkins type 0.
|
||||
LinuxCncAxisJoints linuxcnc_xyzab_tdr_identity_inverse(const CncSimPose &pose) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
LinuxCncXyzabTdrParameters parameters{};
|
||||
linuxcnc_xyzab_tdr_kins_inverse(pose, parameters, 0, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/hal/components/xyzab_tdr_kins.comp
|
||||
// Mirrors kinematicsForward() switchkins type 1.
|
||||
CncSimPose linuxcnc_xyzab_tdr_tcp_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncXyzabTdrParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_xyzab_tdr_kins_forward(joints, parameters, 1, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/hal/components/xyzab_tdr_kins.comp
|
||||
// Mirrors kinematicsInverse() switchkins type 1.
|
||||
LinuxCncAxisJoints linuxcnc_xyzab_tdr_tcp_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzabTdrParameters ¶meters) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_xyzab_tdr_kins_inverse(pose, parameters, 1, &joints);
|
||||
return joints;
|
||||
}
|
||||
|
||||
LinuxCncPumaParameters linuxcnc_puma_default_parameters() {
|
||||
LinuxCncPumaParameters parameters{};
|
||||
parameters.a2 = 300.0;
|
||||
parameters.a3 = 50.0;
|
||||
parameters.d3 = 70.0;
|
||||
parameters.d4 = 400.0;
|
||||
parameters.d6 = 70.0;
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/pumakins.c
|
||||
CncSimPose linuxcnc_puma_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int *iflags) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_pumakins_forward(joints, parameters, &pose, iflags);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/pumakins.c
|
||||
LinuxCncAxisJoints linuxcnc_puma_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints ¤t_joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int iflags,
|
||||
int *fflags) {
|
||||
LinuxCncAxisJoints joints{};
|
||||
linuxcnc_pumakins_inverse(pose, current_joints, parameters, iflags, &joints, fflags);
|
||||
return joints;
|
||||
}
|
||||
|
||||
LinuxCncGenserParameters linuxcnc_genser_puma560_parameters() {
|
||||
LinuxCncGenserParameters parameters{};
|
||||
// Source: linuxcnc/configs/sim/axis/vismach/puma/puma560_dh.hal.
|
||||
parameters.a[0] = 0.0;
|
||||
parameters.a[1] = 0.0;
|
||||
parameters.a[2] = 17.0;
|
||||
parameters.a[3] = 0.0;
|
||||
parameters.a[4] = 0.0;
|
||||
parameters.a[5] = 0.0;
|
||||
|
||||
parameters.alpha[0] = 0.0;
|
||||
parameters.alpha[1] = 1.570796326;
|
||||
parameters.alpha[2] = 0.0;
|
||||
parameters.alpha[3] = 1.570796326;
|
||||
parameters.alpha[4] = -1.570796326;
|
||||
parameters.alpha[5] = 1.570796326;
|
||||
|
||||
parameters.d[0] = 26.45;
|
||||
parameters.d[1] = -5.5;
|
||||
parameters.d[2] = 0.0;
|
||||
parameters.d[3] = 17.05;
|
||||
parameters.d[4] = 0.0;
|
||||
parameters.d[5] = 2.2;
|
||||
return parameters;
|
||||
}
|
||||
|
||||
LinuxCncGenserParameters linuxcnc_genser_default_parameters(int *max_iterations) {
|
||||
LinuxCncGenserParameters parameters{};
|
||||
linuxcnc_genserfuncs_source_default_parameters(¶meters, max_iterations);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/genserfuncs.c
|
||||
// Mirrors genserKinematicsForward() -> genser_kin_fwd() -> go_link_pose_build()
|
||||
// for the six angular DH joints used by the LinuxCNC puma560 M428 configuration.
|
||||
CncSimPose linuxcnc_genser_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncGenserParameters ¶meters) {
|
||||
CncSimPose pose{};
|
||||
linuxcnc_genserfuncs_forward(joints, parameters, &pose);
|
||||
return pose;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/genserfuncs.c
|
||||
// Mirrors genserKinematicsInverse() for the six angular DH joints used by
|
||||
// the LinuxCNC puma560 M428 configuration.
|
||||
LinuxCncAxisJoints linuxcnc_genser_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
int *iterations,
|
||||
int max_iterations) {
|
||||
if (iterations) {
|
||||
*iterations = -1;
|
||||
}
|
||||
LinuxCncAxisJoints joints = joint_estimate;
|
||||
linuxcnc_genserfuncs_inverse(pose, joint_estimate, parameters, max_iterations, &joints, iterations);
|
||||
return joints;
|
||||
}
|
||||
|
||||
// Source: linuxcnc/src/emc/kinematics/genserfuncs.c
|
||||
// Exposes genserKinematicsInverse() success/failure without changing the
|
||||
// LinuxCNC-computed joint buffer.
|
||||
bool linuxcnc_genser_inverse_checked(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *iterations,
|
||||
int max_iterations) {
|
||||
if (iterations) {
|
||||
*iterations = -1;
|
||||
}
|
||||
LinuxCncAxisJoints out = joint_estimate;
|
||||
const bool ok = linuxcnc_genserfuncs_inverse(pose,
|
||||
joint_estimate,
|
||||
parameters,
|
||||
max_iterations,
|
||||
&out,
|
||||
iterations);
|
||||
if (joints) {
|
||||
*joints = out;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,207 @@ struct RtcpVector {
|
||||
double z;
|
||||
};
|
||||
|
||||
// Rotation order is intrinsic tool orientation A then B then C, represented as
|
||||
// Rz(C) * Ry(B) * Rx(A) applied to a local tool vector.
|
||||
RtcpVector rtcp_rotate_abc_degrees(RtcpVector vector, double a_deg, double b_deg, double c_deg);
|
||||
struct LinuxCncFiveAxisJoints {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double w;
|
||||
};
|
||||
|
||||
RtcpVector rtcp_tool_vector_from_pose(const CncSimPose &pose, double tool_length);
|
||||
CncSimPose rtcp_pivot_from_tool_tip(const CncSimPose &tool_tip, double tool_length);
|
||||
CncSimPose rtcp_tool_tip_from_pivot(const CncSimPose &pivot, double tool_length);
|
||||
struct LinuxCncAxisJoints {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
struct LinuxCncXyzbcTrtParameters {
|
||||
double x_rot_point;
|
||||
double y_rot_point;
|
||||
double z_rot_point;
|
||||
double x_offset;
|
||||
double y_offset;
|
||||
double z_offset;
|
||||
double tool_offset;
|
||||
bool conventional_directions;
|
||||
};
|
||||
|
||||
struct LinuxCncScaraParameters {
|
||||
double d1;
|
||||
double d2;
|
||||
double d3;
|
||||
double d4;
|
||||
double d5;
|
||||
double d6;
|
||||
};
|
||||
|
||||
struct LinuxCncXyzabTdrParameters {
|
||||
double tool_offset_z;
|
||||
double x_offset;
|
||||
double z_offset;
|
||||
double x_rot_point;
|
||||
double y_rot_point;
|
||||
double z_rot_point;
|
||||
};
|
||||
|
||||
struct LinuxCncPumaParameters {
|
||||
double a2;
|
||||
double a3;
|
||||
double d3;
|
||||
double d4;
|
||||
double d6;
|
||||
};
|
||||
|
||||
struct LinuxCncGenserParameters {
|
||||
double a[6];
|
||||
double alpha[6];
|
||||
double d[6];
|
||||
int unrotate[6];
|
||||
};
|
||||
|
||||
struct LinuxCncScaraJoints {
|
||||
double j0;
|
||||
double j1;
|
||||
double j2;
|
||||
double j3;
|
||||
double j4;
|
||||
double j5;
|
||||
};
|
||||
|
||||
struct LinuxCncGenhexJoints {
|
||||
double strut[6];
|
||||
};
|
||||
|
||||
struct LinuxCncPentakinsJoints {
|
||||
double strut[5];
|
||||
};
|
||||
|
||||
struct LinuxCncTripodJoints {
|
||||
double strut[3];
|
||||
};
|
||||
|
||||
struct LinuxCncScorbotJoints {
|
||||
double j0;
|
||||
double j1;
|
||||
double j2;
|
||||
double j3;
|
||||
double j4;
|
||||
};
|
||||
|
||||
struct LinuxCncLinearDeltaParameters {
|
||||
double r;
|
||||
double l;
|
||||
};
|
||||
|
||||
struct LinuxCncRotaryDeltaParameters {
|
||||
double platformradius;
|
||||
double thighlength;
|
||||
double shinlength;
|
||||
double footradius;
|
||||
};
|
||||
|
||||
struct LinuxCncMaxkinsParameters {
|
||||
double pivot_length;
|
||||
bool conventional_directions;
|
||||
};
|
||||
|
||||
LinuxCncAxisJoints linuxcnc_identity_default_joints();
|
||||
CncSimPose linuxcnc_identity_forward(const LinuxCncAxisJoints &joints);
|
||||
LinuxCncAxisJoints linuxcnc_identity_inverse(const CncSimPose &pose);
|
||||
|
||||
CncSimPose linuxcnc_corexykins_forward(const LinuxCncAxisJoints &joints);
|
||||
LinuxCncAxisJoints linuxcnc_corexykins_inverse(const CncSimPose &pose);
|
||||
|
||||
CncSimPose linuxcnc_rotatekins_forward(const LinuxCncAxisJoints &joints);
|
||||
LinuxCncAxisJoints linuxcnc_rotatekins_inverse(const CncSimPose &pose);
|
||||
LinuxCncGenhexJoints linuxcnc_genhex_inverse(const CncSimPose &pose);
|
||||
CncSimPose linuxcnc_genhex_forward(const LinuxCncGenhexJoints &joints, const CncSimPose &initial_pose);
|
||||
LinuxCncPentakinsJoints linuxcnc_pentakins_inverse(const CncSimPose &pose);
|
||||
CncSimPose linuxcnc_pentakins_forward(const LinuxCncPentakinsJoints &joints,
|
||||
const CncSimPose &initial_pose);
|
||||
LinuxCncTripodJoints linuxcnc_tripodkins_inverse(const CncSimPose &pose);
|
||||
CncSimPose linuxcnc_tripodkins_forward(const LinuxCncTripodJoints &joints);
|
||||
LinuxCncScorbotJoints linuxcnc_scorbot_kins_inverse(const CncSimPose &pose);
|
||||
CncSimPose linuxcnc_scorbot_kins_forward(const LinuxCncScorbotJoints &joints);
|
||||
LinuxCncLinearDeltaParameters linuxcnc_lineardelta_default_parameters();
|
||||
CncSimPose linuxcnc_lineardelta_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncLinearDeltaParameters ¶meters);
|
||||
LinuxCncAxisJoints linuxcnc_lineardelta_inverse(const CncSimPose &pose,
|
||||
const LinuxCncLinearDeltaParameters ¶meters);
|
||||
LinuxCncRotaryDeltaParameters linuxcnc_rotarydelta_default_parameters();
|
||||
CncSimPose linuxcnc_rotarydelta_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters);
|
||||
LinuxCncAxisJoints linuxcnc_rotarydelta_inverse(const CncSimPose &pose,
|
||||
const LinuxCncRotaryDeltaParameters ¶meters);
|
||||
LinuxCncMaxkinsParameters linuxcnc_maxkins_default_parameters();
|
||||
CncSimPose linuxcnc_maxkins_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncMaxkinsParameters ¶meters);
|
||||
LinuxCncAxisJoints linuxcnc_maxkins_inverse(const CncSimPose &pose,
|
||||
const LinuxCncMaxkinsParameters ¶meters);
|
||||
CncSimPose linuxcnc_rosekins_forward(const LinuxCncAxisJoints &joints);
|
||||
LinuxCncAxisJoints linuxcnc_rosekins_inverse(const CncSimPose &pose);
|
||||
|
||||
CncSimPose linuxcnc_5axis_forward(const LinuxCncFiveAxisJoints &joints, double pivot_length);
|
||||
LinuxCncFiveAxisJoints linuxcnc_5axis_inverse(const CncSimPose &pose, double pivot_length);
|
||||
|
||||
LinuxCncXyzbcTrtParameters linuxcnc_xyzbc_trt_default_parameters(double tool_offset);
|
||||
CncSimPose linuxcnc_xyzbc_trt_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzbc_trt_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
CncSimPose linuxcnc_xyzac_trt_forward(const LinuxCncFiveAxisJoints &joints,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzac_trt_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzbcTrtParameters ¶meters);
|
||||
CncSimPose linuxcnc_xyzbc_userk_forward(const LinuxCncFiveAxisJoints &joints);
|
||||
LinuxCncFiveAxisJoints linuxcnc_xyzbc_userk_inverse(const CncSimPose &pose);
|
||||
|
||||
LinuxCncScaraParameters linuxcnc_scara_default_parameters();
|
||||
CncSimPose linuxcnc_scara_forward(const LinuxCncScaraJoints &joints,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int *iflags);
|
||||
LinuxCncScaraJoints linuxcnc_scara_inverse(const CncSimPose &pose,
|
||||
const LinuxCncScaraParameters ¶meters,
|
||||
int iflags);
|
||||
|
||||
LinuxCncXyzabTdrParameters linuxcnc_xyzab_tdr_default_parameters(double tool_offset_z);
|
||||
CncSimPose linuxcnc_xyzab_tdr_identity_forward(const LinuxCncAxisJoints &joints);
|
||||
LinuxCncAxisJoints linuxcnc_xyzab_tdr_identity_inverse(const CncSimPose &pose);
|
||||
CncSimPose linuxcnc_xyzab_tdr_tcp_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncXyzabTdrParameters ¶meters);
|
||||
LinuxCncAxisJoints linuxcnc_xyzab_tdr_tcp_inverse(const CncSimPose &pose,
|
||||
const LinuxCncXyzabTdrParameters ¶meters);
|
||||
|
||||
LinuxCncPumaParameters linuxcnc_puma_default_parameters();
|
||||
CncSimPose linuxcnc_puma_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int *iflags);
|
||||
LinuxCncAxisJoints linuxcnc_puma_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints ¤t_joints,
|
||||
const LinuxCncPumaParameters ¶meters,
|
||||
int iflags,
|
||||
int *fflags);
|
||||
|
||||
LinuxCncGenserParameters linuxcnc_genser_puma560_parameters();
|
||||
LinuxCncGenserParameters linuxcnc_genser_default_parameters(int *max_iterations = nullptr);
|
||||
CncSimPose linuxcnc_genser_forward(const LinuxCncAxisJoints &joints,
|
||||
const LinuxCncGenserParameters ¶meters);
|
||||
LinuxCncAxisJoints linuxcnc_genser_inverse(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
int *iterations,
|
||||
int max_iterations = 100);
|
||||
bool linuxcnc_genser_inverse_checked(const CncSimPose &pose,
|
||||
const LinuxCncAxisJoints &joint_estimate,
|
||||
const LinuxCncGenserParameters ¶meters,
|
||||
LinuxCncAxisJoints *joints,
|
||||
int *iterations,
|
||||
int max_iterations = 100);
|
||||
|
||||
@@ -6,31 +6,155 @@
|
||||
|
||||
namespace {
|
||||
|
||||
std::string strip_line_comment(const std::string &line) {
|
||||
bool strip_line_comment(const std::string &line, bool block_delete, std::string *stripped) {
|
||||
std::string out;
|
||||
bool in_paren = false;
|
||||
bool saw_code = false;
|
||||
for (char raw : line) {
|
||||
const char ch = static_cast<char>(std::toupper(static_cast<unsigned char>(raw)));
|
||||
if (in_paren) {
|
||||
if (ch == '(') {
|
||||
return false;
|
||||
}
|
||||
if (ch == ')') {
|
||||
in_paren = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ch == '(') {
|
||||
saw_code = true;
|
||||
in_paren = true;
|
||||
continue;
|
||||
}
|
||||
if (ch == ';') {
|
||||
break;
|
||||
}
|
||||
if (!saw_code && std::isspace(static_cast<unsigned char>(ch))) {
|
||||
out.push_back(ch);
|
||||
continue;
|
||||
}
|
||||
if (!saw_code && ch == '/') {
|
||||
if (block_delete) {
|
||||
return false;
|
||||
}
|
||||
saw_code = true;
|
||||
continue;
|
||||
}
|
||||
saw_code = true;
|
||||
out.push_back(ch);
|
||||
}
|
||||
return out;
|
||||
if (in_paren) {
|
||||
return false;
|
||||
}
|
||||
*stripped = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool g_code_is(double actual, double expected) {
|
||||
return std::fabs(actual - expected) < 0.0001;
|
||||
bool linuxcnc_integer_word_value(double value, int *integer) {
|
||||
*integer = static_cast<int>(std::floor(value));
|
||||
const double fraction = value - *integer;
|
||||
if (fraction > 0.9999) {
|
||||
*integer = static_cast<int>(std::ceil(value));
|
||||
return true;
|
||||
}
|
||||
return fraction <= 0.0001;
|
||||
}
|
||||
|
||||
bool linuxcnc_g_word_value(double value, int *g_code) {
|
||||
const double scaled = value * 10.0;
|
||||
int parsed = static_cast<int>(std::floor(scaled));
|
||||
const double fraction = scaled - parsed;
|
||||
if (fraction > 0.999) {
|
||||
parsed = static_cast<int>(std::ceil(scaled));
|
||||
} else if (fraction > 0.001) {
|
||||
return false;
|
||||
}
|
||||
if (parsed < 0 || parsed > 999) {
|
||||
return false;
|
||||
}
|
||||
*g_code = parsed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_linuxcnc_real_number(const char *text, size_t start, double *value, size_t *end_index) {
|
||||
const char first = text[start];
|
||||
const char next = text[start + 1];
|
||||
if (first == '[') {
|
||||
double nested = 0.0;
|
||||
size_t nested_end = start + 1;
|
||||
if (!read_linuxcnc_real_number(text, start + 1, &nested, &nested_end) ||
|
||||
text[nested_end] != ']') {
|
||||
return false;
|
||||
}
|
||||
*value = nested;
|
||||
*end_index = nested_end + 1;
|
||||
return true;
|
||||
}
|
||||
if ((first == '+' || first == '-') &&
|
||||
next != '\0' &&
|
||||
!std::isdigit(static_cast<unsigned char>(next)) &&
|
||||
next != '.') {
|
||||
double nested = 0.0;
|
||||
size_t nested_end = start + 1;
|
||||
if (!read_linuxcnc_real_number(text, start + 1, &nested, &nested_end)) {
|
||||
return false;
|
||||
}
|
||||
*value = first == '-' ? -nested : nested;
|
||||
*end_index = nested_end;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t i = start;
|
||||
while (text[i] == '+' || text[i] == '-') {
|
||||
++i;
|
||||
}
|
||||
const size_t number_start = i;
|
||||
while (std::isdigit(static_cast<unsigned char>(text[i])) || text[i] == '.') {
|
||||
++i;
|
||||
}
|
||||
if (i == start || i == number_start) {
|
||||
return false;
|
||||
}
|
||||
std::string token(text + start, i - start);
|
||||
char *end = nullptr;
|
||||
const double parsed = std::strtod(token.c_str(), &end);
|
||||
if (end != token.c_str() + token.size()) {
|
||||
return false;
|
||||
}
|
||||
*value = parsed;
|
||||
*end_index = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skip_linuxcnc_leading_n_number(const std::string &stripped, std::string *without_n) {
|
||||
size_t i = 0;
|
||||
while (std::isspace(static_cast<unsigned char>(stripped[i]))) {
|
||||
++i;
|
||||
}
|
||||
if (stripped[i] != 'N') {
|
||||
*without_n = stripped;
|
||||
return true;
|
||||
}
|
||||
++i;
|
||||
const size_t integer_start = i;
|
||||
while (std::isdigit(static_cast<unsigned char>(stripped[i]))) {
|
||||
++i;
|
||||
}
|
||||
if (i == integer_start) {
|
||||
return false;
|
||||
}
|
||||
if (stripped[i] == '.') {
|
||||
++i;
|
||||
const size_t fraction_start = i;
|
||||
while (std::isdigit(static_cast<unsigned char>(stripped[i]))) {
|
||||
++i;
|
||||
}
|
||||
if (i == fraction_start) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*without_n = stripped.substr(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_m_control_line(const std::string &stripped,
|
||||
@@ -46,9 +170,13 @@ bool parse_m_control_line(const std::string &stripped,
|
||||
return false;
|
||||
}
|
||||
++i;
|
||||
char *end = nullptr;
|
||||
const long value = std::strtol(text + i, &end, 10);
|
||||
if (end == text + i) {
|
||||
double raw_value = 0.0;
|
||||
size_t end = i;
|
||||
if (!read_linuxcnc_real_number(text, i, &raw_value, &end)) {
|
||||
return false;
|
||||
}
|
||||
int value = 0;
|
||||
if (!linuxcnc_integer_word_value(raw_value, &value) || value < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -56,19 +184,19 @@ bool parse_m_control_line(const std::string &stripped,
|
||||
action.kind = SimulatorGcodeControlKind::KinematicsSwitch;
|
||||
if (value == 428) {
|
||||
action.value = 1;
|
||||
action.rtcp_enabled = true;
|
||||
action.m_code = 428;
|
||||
} else if (value == 429) {
|
||||
action.value = 0;
|
||||
action.rtcp_enabled = false;
|
||||
action.m_code = 429;
|
||||
} else if (value == 430) {
|
||||
action.value = 2;
|
||||
action.rtcp_enabled = true;
|
||||
action.m_code = 430;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
actions->push_back(action);
|
||||
saw_code = true;
|
||||
i = static_cast<size_t>(end - text);
|
||||
i = end;
|
||||
}
|
||||
return saw_code;
|
||||
}
|
||||
@@ -78,7 +206,9 @@ bool parse_rtcp_control_line(const std::string &stripped,
|
||||
const char *text = stripped.c_str();
|
||||
std::vector<SimulatorGcodeControlAction> parsed;
|
||||
int h_code = 0;
|
||||
bool saw_h_word = false;
|
||||
bool saw_rtcp_code = false;
|
||||
bool saw_rtcp_g_word = false;
|
||||
|
||||
for (size_t i = 0; text[i] != '\0';) {
|
||||
if (std::isspace(static_cast<unsigned char>(text[i]))) {
|
||||
@@ -90,26 +220,44 @@ bool parse_rtcp_control_line(const std::string &stripped,
|
||||
return false;
|
||||
}
|
||||
++i;
|
||||
char *end = nullptr;
|
||||
const double value = std::strtod(text + i, &end);
|
||||
if (end == text + i) {
|
||||
double value = 0.0;
|
||||
size_t end = i;
|
||||
if (!read_linuxcnc_real_number(text, i, &value, &end)) {
|
||||
return false;
|
||||
}
|
||||
if (letter == 'H') {
|
||||
h_code = static_cast<int>(std::lround(value));
|
||||
} else if (g_code_is(value, 43.4) || g_code_is(value, 43.5) || g_code_is(value, 49.0)) {
|
||||
if (saw_h_word) {
|
||||
return false;
|
||||
}
|
||||
if (!linuxcnc_integer_word_value(value, &h_code) || h_code < -1) {
|
||||
return false;
|
||||
}
|
||||
saw_h_word = true;
|
||||
} else {
|
||||
int g_code = 0;
|
||||
if (!linuxcnc_g_word_value(value, &g_code) ||
|
||||
(g_code != 434 && g_code != 435 && g_code != 490)) {
|
||||
return false;
|
||||
}
|
||||
if (saw_rtcp_g_word) {
|
||||
return false;
|
||||
}
|
||||
SimulatorGcodeControlAction action{};
|
||||
action.kind = SimulatorGcodeControlKind::RtcpState;
|
||||
action.value = static_cast<int>(std::lround(value * 10.0));
|
||||
action.rtcp_enabled = g_code_is(value, 43.4) || g_code_is(value, 43.5);
|
||||
action.value = g_code;
|
||||
action.rtcp_enabled = g_code == 434 || g_code == 435;
|
||||
parsed.push_back(action);
|
||||
saw_rtcp_code = true;
|
||||
} else {
|
||||
return false;
|
||||
saw_rtcp_g_word = true;
|
||||
}
|
||||
i = static_cast<size_t>(end - text);
|
||||
i = end;
|
||||
}
|
||||
|
||||
for (const auto &action : parsed) {
|
||||
if (!action.rtcp_enabled && saw_h_word) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto &action : parsed) {
|
||||
action.h_code = action.rtcp_enabled ? h_code : 0;
|
||||
actions->push_back(action);
|
||||
@@ -121,25 +269,51 @@ bool parse_rtcp_control_line(const std::string &stripped,
|
||||
|
||||
bool parse_simulator_gcode_control_line(const std::string &line,
|
||||
std::vector<SimulatorGcodeControlAction> *actions) {
|
||||
return parse_simulator_gcode_control_line(line, false, actions);
|
||||
}
|
||||
|
||||
bool parse_simulator_gcode_control_line(const std::string &line,
|
||||
bool block_delete,
|
||||
std::vector<SimulatorGcodeControlAction> *actions) {
|
||||
actions->clear();
|
||||
const std::string stripped = strip_line_comment(line);
|
||||
if (parse_m_control_line(stripped, actions)) {
|
||||
std::string stripped;
|
||||
if (!strip_line_comment(line, block_delete, &stripped)) {
|
||||
return false;
|
||||
}
|
||||
std::string control_line;
|
||||
if (!skip_linuxcnc_leading_n_number(stripped, &control_line)) {
|
||||
return false;
|
||||
}
|
||||
if (parse_m_control_line(control_line, actions)) {
|
||||
return true;
|
||||
}
|
||||
actions->clear();
|
||||
if (parse_rtcp_control_line(stripped, actions)) {
|
||||
if (parse_rtcp_control_line(control_line, actions)) {
|
||||
return true;
|
||||
}
|
||||
actions->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
void emit_simulator_gcode_control_action(CanonEventSink &sink,
|
||||
bool can_emit_simulator_gcode_control_action(const CanonEventSink &sink,
|
||||
const SimulatorGcodeControlAction &action) {
|
||||
if (action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
|
||||
return sink.can_switch_m_code_kinematics(action.m_code);
|
||||
}
|
||||
if (action.kind == SimulatorGcodeControlKind::RtcpState) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool emit_simulator_gcode_control_action(CanonEventSink &sink,
|
||||
const SimulatorGcodeControlAction &action,
|
||||
int line) {
|
||||
if (action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
|
||||
sink.switch_kinematics(action.value, action.rtcp_enabled, line);
|
||||
return sink.switch_m_code_kinematics(action.m_code, action.value, line);
|
||||
} else if (action.kind == SimulatorGcodeControlKind::RtcpState) {
|
||||
sink.set_rtcp_state(action.rtcp_enabled, action.h_code, line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,18 @@ enum class SimulatorGcodeControlKind {
|
||||
struct SimulatorGcodeControlAction {
|
||||
SimulatorGcodeControlKind kind;
|
||||
int value;
|
||||
int m_code;
|
||||
bool rtcp_enabled;
|
||||
int h_code;
|
||||
};
|
||||
|
||||
bool parse_simulator_gcode_control_line(const std::string &line,
|
||||
std::vector<SimulatorGcodeControlAction> *actions);
|
||||
void emit_simulator_gcode_control_action(CanonEventSink &sink,
|
||||
bool parse_simulator_gcode_control_line(const std::string &line,
|
||||
bool block_delete,
|
||||
std::vector<SimulatorGcodeControlAction> *actions);
|
||||
bool can_emit_simulator_gcode_control_action(const CanonEventSink &sink,
|
||||
const SimulatorGcodeControlAction &action);
|
||||
bool emit_simulator_gcode_control_action(CanonEventSink &sink,
|
||||
const SimulatorGcodeControlAction &action,
|
||||
int line);
|
||||
|
||||
@@ -149,11 +149,13 @@ constexpr double kRadiusToleranceMm = kRadiusToleranceInch * kMmPerInch;
|
||||
constexpr double kCenterArcRadiusToleranceInch = 2.0 * 0.001 * M_SQRT2;
|
||||
constexpr double kCenterArcRadiusToleranceMm = 2.0 * 0.01 * M_SQRT2;
|
||||
constexpr double kSpiralRelativeTolerance = 0.001;
|
||||
constexpr int kConstantRpmSpindleModeEvent = 970;
|
||||
constexpr int kCutterCompOffEvent = 400;
|
||||
constexpr int kCutterCompLeftEvent = 410;
|
||||
constexpr int kCutterCompRightEvent = 420;
|
||||
constexpr int kCutterCompLeftExplicitEvent = 411;
|
||||
constexpr int kCutterCompRightExplicitEvent = 421;
|
||||
constexpr int kToolLengthOffsetEvent = 430;
|
||||
|
||||
enum class LinuxCncReaderSymbol {
|
||||
None,
|
||||
@@ -178,6 +180,13 @@ size_t leading_special_word_start(const std::string &line);
|
||||
bool is_numeric_m98_subprogram_header(const std::string &line);
|
||||
OwordKind oword_kind(const std::string &line);
|
||||
bool integer_word_value(const std::unordered_map<char, double> &words, char letter, int *value);
|
||||
bool smoke_ini_raw_value(const std::string §ion, const std::string &key, std::string *value);
|
||||
bool evaluate_expression(const std::string &text,
|
||||
const std::vector<CallFrame> &call_stack,
|
||||
const std::unordered_map<int, double> ¶meters,
|
||||
const std::unordered_map<std::string, double> &named_parameters,
|
||||
double *value,
|
||||
std::string *error);
|
||||
|
||||
template <size_t Size>
|
||||
bool contains_int(const std::array<int, Size> &values, int value) {
|
||||
@@ -436,6 +445,20 @@ bool parse_smoke_hal_named_parameter(const std::string &name, std::string *pin)
|
||||
}
|
||||
|
||||
bool smoke_ini_value(const std::string §ion, const std::string &key, double *value) {
|
||||
std::string raw_value;
|
||||
if (!smoke_ini_raw_value(section, key, &raw_value)) {
|
||||
return false;
|
||||
}
|
||||
char *end = nullptr;
|
||||
const double parsed = std::strtod(raw_value.c_str(), &end);
|
||||
if (end == raw_value.c_str()) {
|
||||
return false;
|
||||
}
|
||||
*value = parsed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smoke_ini_raw_value(const std::string §ion, const std::string &key, std::string *value) {
|
||||
const char *path = std::getenv("INI_FILE_NAME");
|
||||
if (!path || !*path) {
|
||||
return false;
|
||||
@@ -466,18 +489,20 @@ bool smoke_ini_value(const std::string §ion, const std::string &key, double
|
||||
if (ini_lookup_key(text.substr(0, equals)) != key) {
|
||||
continue;
|
||||
}
|
||||
char *end = nullptr;
|
||||
const std::string raw_value = trim(text.substr(equals + 1));
|
||||
const double parsed = std::strtod(raw_value.c_str(), &end);
|
||||
if (end == raw_value.c_str()) {
|
||||
return false;
|
||||
}
|
||||
*value = parsed;
|
||||
*value = trim(text.substr(equals + 1));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double smoke_metric_machine_value() {
|
||||
std::string linear_units;
|
||||
if (!smoke_ini_raw_value("TRAJ", "LINEAR_UNITS", &linear_units)) {
|
||||
return -1.0;
|
||||
}
|
||||
return linear_units == "inch" ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
bool smoke_hal_value(const std::string &pin, double *value) {
|
||||
const char *path = std::getenv("HAL_PIN_FILE");
|
||||
if (path && *path) {
|
||||
@@ -685,6 +710,91 @@ LinuxCncIntegerReadResult read_linuxcnc_integer_value(const std::string &text,
|
||||
return LinuxCncIntegerReadResult::Ok;
|
||||
}
|
||||
|
||||
bool is_current_position_parameter_index(int index) {
|
||||
return index >= 5420 && index <= 5428;
|
||||
}
|
||||
|
||||
bool line_reads_current_position_parameter(const std::string &line,
|
||||
const std::vector<CallFrame> &call_stack,
|
||||
const std::unordered_map<int, double> ¶meters,
|
||||
const std::unordered_map<std::string, double> &named_parameters) {
|
||||
for (size_t i = 0; i < line.size(); ++i) {
|
||||
if (line[i] != '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
size_t index_end = i + 1;
|
||||
size_t parameter_start = i + 1;
|
||||
while (parameter_start < line.size() &&
|
||||
std::isspace(static_cast<unsigned char>(line[parameter_start]))) {
|
||||
++parameter_start;
|
||||
}
|
||||
if (parameter_start < line.size() && line[parameter_start] == '[') {
|
||||
const size_t close = find_matching_square_bracket(line, parameter_start);
|
||||
if (close != std::string::npos) {
|
||||
size_t bracket_index_end = parameter_start + 1;
|
||||
const LinuxCncIntegerReadResult bracket_result =
|
||||
read_linuxcnc_integer_value(line, parameter_start + 1, &index, &bracket_index_end);
|
||||
size_t after_bracket_index = bracket_index_end;
|
||||
while (after_bracket_index < close &&
|
||||
std::isspace(static_cast<unsigned char>(line[after_bracket_index]))) {
|
||||
++after_bracket_index;
|
||||
}
|
||||
bool has_current_position_index =
|
||||
bracket_result == LinuxCncIntegerReadResult::Ok &&
|
||||
after_bracket_index == close &&
|
||||
is_current_position_parameter_index(index);
|
||||
if (!has_current_position_index) {
|
||||
double index_value = 0.0;
|
||||
if (evaluate_expression(line.substr(parameter_start + 1,
|
||||
close - parameter_start - 1),
|
||||
call_stack,
|
||||
parameters,
|
||||
named_parameters,
|
||||
&index_value,
|
||||
nullptr)) {
|
||||
int expression_index = 0;
|
||||
has_current_position_index =
|
||||
linuxcnc_integer_from_real(index_value, &expression_index) ==
|
||||
LinuxCncIntegerReadResult::Ok &&
|
||||
is_current_position_parameter_index(expression_index);
|
||||
}
|
||||
}
|
||||
if (has_current_position_index) {
|
||||
size_t after_close = close + 1;
|
||||
while (after_close < line.size() &&
|
||||
std::isspace(static_cast<unsigned char>(line[after_close]))) {
|
||||
++after_close;
|
||||
}
|
||||
if (after_close < line.size() && line[after_close] == '=') {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const LinuxCncIntegerReadResult result =
|
||||
read_linuxcnc_integer_value(line, i + 1, &index, &index_end);
|
||||
if (result != LinuxCncIntegerReadResult::Ok ||
|
||||
!is_current_position_parameter_index(index)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t after_index = index_end;
|
||||
while (after_index < line.size() &&
|
||||
std::isspace(static_cast<unsigned char>(line[after_index]))) {
|
||||
++after_index;
|
||||
}
|
||||
if (after_index < line.size() && line[after_index] == '=') {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_linuxcnc_real_number(const char *text, double *value, size_t *consumed) {
|
||||
size_t end = 0;
|
||||
while (text[end] == '+' || text[end] == '-') {
|
||||
@@ -1190,6 +1300,7 @@ bool parse_word_list_impl(const std::string &line, ParsedWordList *parsed, std::
|
||||
parsed->theta_flag = false;
|
||||
parsed->theta_value = 0.0;
|
||||
std::array<bool, 26> seen_letters{};
|
||||
std::array<double, 26> seen_letter_values{};
|
||||
const char *text = line.c_str();
|
||||
for (size_t i = 0; text[i] != '\0';) {
|
||||
if (std::isspace(static_cast<unsigned char>(text[i]))) {
|
||||
@@ -1338,13 +1449,27 @@ bool parse_word_list_impl(const std::string &line, ParsedWordList *parsed, std::
|
||||
if (letter != 'G' && letter != 'M') {
|
||||
const size_t letter_index = static_cast<size_t>(letter - 'A');
|
||||
if (strict && seen_letters[letter_index]) {
|
||||
if (error) {
|
||||
*error = "Multiple " + std::string(1, static_cast<char>(std::tolower(static_cast<unsigned char>(letter)))) +
|
||||
" words on one line";
|
||||
if ((letter == 'P' || letter == 'Q') && seen_letter_values[letter_index] <= -1.0) {
|
||||
parsed->words.erase(std::remove_if(parsed->words.begin(),
|
||||
parsed->words.end(),
|
||||
[letter](const Word &word) {
|
||||
return word.letter == letter;
|
||||
}),
|
||||
parsed->words.end());
|
||||
} else {
|
||||
if (error) {
|
||||
const char duplicate_letter =
|
||||
(letter == 'U' || letter == 'V' || letter == 'W')
|
||||
? letter
|
||||
: static_cast<char>(std::tolower(static_cast<unsigned char>(letter)));
|
||||
*error = "Multiple " + std::string(1, duplicate_letter) +
|
||||
" words on one line";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
seen_letters[letter_index] = true;
|
||||
seen_letter_values[letter_index] = value;
|
||||
}
|
||||
parsed->words.push_back({letter, value});
|
||||
i = next;
|
||||
@@ -1627,6 +1752,18 @@ bool smoke_tool_number_exists(int tool_number) {
|
||||
return tool_number == 0 || tool_number == 1 || tool_number == 4;
|
||||
}
|
||||
|
||||
template <typename ToolTable>
|
||||
double smoke_pocket_named_parameter_value(const ToolTable &tool_table, int pocket_index, bool selected_pocket) {
|
||||
const auto it = tool_table.find(pocket_index);
|
||||
if (it == tool_table.end()) {
|
||||
return -1.0;
|
||||
}
|
||||
if (selected_pocket && it->second.pocketno == 0) {
|
||||
return -1.0;
|
||||
}
|
||||
return static_cast<double>(it->second.pocketno);
|
||||
}
|
||||
|
||||
int supported_linuxcnc_g_modal_group(double value) {
|
||||
const int code = linuxcnc_g_code_number(value);
|
||||
if (code < 0 || code >= kLinuxCncGCodeTableSize) {
|
||||
@@ -2225,13 +2362,7 @@ bool is_smoke_readonly_named_parameter(const std::string &name) {
|
||||
name == "_ABS_B" ||
|
||||
name == "_abs_b" ||
|
||||
name == "_ABS_C" ||
|
||||
name == "_abs_c" ||
|
||||
name == "_ABS_U" ||
|
||||
name == "_abs_u" ||
|
||||
name == "_ABS_V" ||
|
||||
name == "_abs_v" ||
|
||||
name == "_ABS_W" ||
|
||||
name == "_abs_w";
|
||||
name == "_abs_c";
|
||||
}
|
||||
|
||||
bool is_smoke_readonly_numbered_parameter(int index) {
|
||||
@@ -3309,7 +3440,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(line, function_start);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated bracket expression";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3356,7 +3487,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(line, i);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated bracket expression";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3391,7 +3522,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(line, end);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated indirect parameter expression";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3400,7 +3531,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = line.find('>', end + 1);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated indirect named parameter expression";
|
||||
*error = "Named parameter not terminated";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3445,7 +3576,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(line, j);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated indexed parameter expression";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3491,7 +3622,7 @@ std::string expand_expressions_and_parameters(const std::string &line,
|
||||
const size_t close = line.find('>', j + 1);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated named parameter expression";
|
||||
*error = "Named parameter not terminated";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -3653,7 +3784,7 @@ bool parse_parameter_assignment(const std::string &line,
|
||||
const size_t close = text.find('>', pos + 1);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated named parameter assignment";
|
||||
*error = "Named parameter not terminated";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3669,7 +3800,7 @@ bool parse_parameter_assignment(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(text, pos);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated indexed parameter assignment";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3793,7 +3924,7 @@ bool parse_parameter_assignment(const std::string &line,
|
||||
const size_t close = find_matching_square_bracket(text, pos);
|
||||
if (close == std::string::npos) {
|
||||
if (error) {
|
||||
*error = "unterminated parameter assignment expression";
|
||||
*error = "Unclosed expression";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -4994,6 +5125,119 @@ bool validate_r_arc_reaches_end_point(const CncSimEvent &event, int plane, doubl
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_absolute_center_arc_axis_words(const std::unordered_map<char, double> &words,
|
||||
int plane,
|
||||
bool absolute,
|
||||
std::string *error) {
|
||||
if (!absolute || words.count('R')) {
|
||||
return true;
|
||||
}
|
||||
auto missing = [error](char axis) {
|
||||
if (error) {
|
||||
*error = std::string(1, axis) + " word missing in absolute center arc";
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (plane == 17 && (words.count('I') || words.count('J'))) {
|
||||
if (!words.count('I')) {
|
||||
return missing('I');
|
||||
}
|
||||
if (!words.count('J')) {
|
||||
return missing('J');
|
||||
}
|
||||
} else if (plane == 18 && (words.count('I') || words.count('K'))) {
|
||||
if (!words.count('I')) {
|
||||
return missing('I');
|
||||
}
|
||||
if (!words.count('K')) {
|
||||
return missing('K');
|
||||
}
|
||||
} else if (plane == 19 && (words.count('J') || words.count('K'))) {
|
||||
if (!words.count('J')) {
|
||||
return missing('J');
|
||||
}
|
||||
if (!words.count('K')) {
|
||||
return missing('K');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_arc_format_words(const std::unordered_map<char, double> &words, std::string *error) {
|
||||
const bool has_r = words.count('R') != 0;
|
||||
const bool has_ijk = words.count('I') || words.count('J') || words.count('K');
|
||||
if (has_r && has_ijk) {
|
||||
if (error) {
|
||||
*error = "Mixed radius ijk format for arc";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!has_r && !has_ijk) {
|
||||
if (error) {
|
||||
*error = "R i j k words all missing for arc";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_arc_plane_center_words(const std::unordered_map<char, double> &words,
|
||||
int plane,
|
||||
std::string *error) {
|
||||
if (plane == 17 && words.count('K')) {
|
||||
if (error) {
|
||||
*error = "K word given for arc in xy plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (plane == 18 && words.count('J')) {
|
||||
if (error) {
|
||||
*error = "J word given for arc in xz plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (plane == 19 && words.count('I')) {
|
||||
if (error) {
|
||||
*error = "I word given for arc in yz plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_r_arc_endpoint_words(const std::unordered_map<char, double> &words,
|
||||
const ParsedWordList &parsed,
|
||||
int plane,
|
||||
std::string *error) {
|
||||
if (!words.count('R')) {
|
||||
return true;
|
||||
}
|
||||
if (plane == 17) {
|
||||
if (!words.count('X') && !words.count('Y') &&
|
||||
!parsed.radius_flag && !parsed.theta_flag) {
|
||||
if (error) {
|
||||
*error = "X and y words missing for arc in xy plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if (plane == 18) {
|
||||
if (!words.count('X') && !words.count('Z')) {
|
||||
if (error) {
|
||||
*error = "X and z words missing for arc in xz plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if (plane == 19) {
|
||||
if (!words.count('Y') && !words.count('Z')) {
|
||||
if (error) {
|
||||
*error = "Y and z words missing for arc in yz plane";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool modal_motion_is_threading(int modal_motion) {
|
||||
return modal_motion == kModalMotionG33 ||
|
||||
modal_motion == kModalMotionG331;
|
||||
@@ -5101,7 +5345,7 @@ void emit_tool_length_offset(CanonEventSink &sink, const CncSimPose &offset, int
|
||||
event.version = 1;
|
||||
event.type = CNC_SIM_EVENT_COMMENT;
|
||||
event.line = line;
|
||||
event.reserved = 430;
|
||||
event.reserved = kToolLengthOffsetEvent;
|
||||
event.start = offset;
|
||||
sink.emit_raw(event);
|
||||
}
|
||||
@@ -5187,6 +5431,8 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
spindle_css_mode_ = false;
|
||||
spindle_tool_id_ = 0;
|
||||
selected_tool_id_ = 0;
|
||||
current_pocket_index_ = 0;
|
||||
selected_pocket_index_ = 0;
|
||||
feed_mode_ = 0;
|
||||
canned_cycle_ = 0;
|
||||
canned_return_to_initial_ = false;
|
||||
@@ -5212,13 +5458,16 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
oword_value_returned_ = false;
|
||||
tool_table_.clear();
|
||||
tool_table_[0] = {};
|
||||
tool_table_[0].pocketno = 0;
|
||||
tool_table_[1] = {};
|
||||
tool_table_[1].pocketno = 1;
|
||||
tool_table_[1].offset.z = 12.5;
|
||||
tool_table_[1].diameter = 6.0;
|
||||
tool_table_[1].frontangle = 12.0;
|
||||
tool_table_[1].backangle = 34.0;
|
||||
tool_table_[1].orientation = 5.0;
|
||||
tool_table_[4] = {};
|
||||
tool_table_[4].pocketno = 4;
|
||||
tool_table_[4].offset.z = 0.7;
|
||||
tool_table_[4].diameter = 1.0;
|
||||
|
||||
@@ -5464,9 +5713,13 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
named_parameters["_CURRENT_TOOL"] = named_parameters["_current_tool"];
|
||||
named_parameters["_selected_tool"] = static_cast<double>(selected_tool_id_);
|
||||
named_parameters["_SELECTED_TOOL"] = named_parameters["_selected_tool"];
|
||||
named_parameters["_current_pocket"] = static_cast<double>(spindle_tool_id_);
|
||||
named_parameters["_current_pocket"] = smoke_pocket_named_parameter_value(tool_table_,
|
||||
current_pocket_index_,
|
||||
false);
|
||||
named_parameters["_CURRENT_POCKET"] = named_parameters["_current_pocket"];
|
||||
named_parameters["_selected_pocket"] = static_cast<double>(selected_tool_id_);
|
||||
named_parameters["_selected_pocket"] = smoke_pocket_named_parameter_value(tool_table_,
|
||||
selected_pocket_index_,
|
||||
true);
|
||||
named_parameters["_SELECTED_POCKET"] = named_parameters["_selected_pocket"];
|
||||
named_parameters["_spindle_rpm_mode"] = spindle_css_mode_ ? 0.0 : 1.0;
|
||||
named_parameters["_SPINDLE_RPM_MODE"] = named_parameters["_spindle_rpm_mode"];
|
||||
@@ -5486,8 +5739,8 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
named_parameters["_VMAJOR"] = 2.10;
|
||||
named_parameters["_vminor"] = 0.0;
|
||||
named_parameters["_VMINOR"] = 0.0;
|
||||
named_parameters["_metric_machine"] = -1.0;
|
||||
named_parameters["_METRIC_MACHINE"] = -1.0;
|
||||
named_parameters["_metric_machine"] = smoke_metric_machine_value();
|
||||
named_parameters["_METRIC_MACHINE"] = named_parameters["_metric_machine"];
|
||||
named_parameters["_task"] = 0.0;
|
||||
named_parameters["_TASK"] = 0.0;
|
||||
const bool has_tool_offset = tool_length_offset.x != 0.0 ||
|
||||
@@ -5526,18 +5779,12 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
named_parameters["_abs_a"] = position.a;
|
||||
named_parameters["_abs_b"] = position.b;
|
||||
named_parameters["_abs_c"] = position.c;
|
||||
named_parameters["_abs_u"] = position.u;
|
||||
named_parameters["_abs_v"] = position.v;
|
||||
named_parameters["_abs_w"] = position.w;
|
||||
named_parameters["_ABS_X"] = position.x;
|
||||
named_parameters["_ABS_Y"] = position.y;
|
||||
named_parameters["_ABS_Z"] = position.z;
|
||||
named_parameters["_ABS_A"] = position.a;
|
||||
named_parameters["_ABS_B"] = position.b;
|
||||
named_parameters["_ABS_C"] = position.c;
|
||||
named_parameters["_ABS_U"] = position.u;
|
||||
named_parameters["_ABS_V"] = position.v;
|
||||
named_parameters["_ABS_W"] = position.w;
|
||||
|
||||
const CncSimPose &probe_position = sink_.probe_position();
|
||||
parameters[5061] = probe_position.x;
|
||||
@@ -5645,6 +5892,13 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
|
||||
refresh_readonly_named_parameters(line_number);
|
||||
if (cutter_comp_on_ &&
|
||||
line_reads_current_position_parameter(line, call_stack, parameters, named_parameters)) {
|
||||
if (error) {
|
||||
*error = "Cannot read current position with cutter radius compensation on";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
std::string parameter_error;
|
||||
std::vector<PendingParameterAssignment> pending_assignments;
|
||||
if (!extract_parameter_assignments(line,
|
||||
@@ -5726,16 +5980,36 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
std::vector<SimulatorGcodeControlAction> simulator_control_actions;
|
||||
if (!has_keyword_oword &&
|
||||
parse_simulator_gcode_control_line(line, &simulator_control_actions)) {
|
||||
parse_simulator_gcode_control_line(line, sink_.block_delete(), &simulator_control_actions)) {
|
||||
bool simulator_only_line = true;
|
||||
bool all_control_actions_handled = true;
|
||||
for (const auto &action : simulator_control_actions) {
|
||||
emit_simulator_gcode_control_action(sink_, action, line_number);
|
||||
if (!can_emit_simulator_gcode_control_action(sink_, action)) {
|
||||
all_control_actions_handled = false;
|
||||
simulator_only_line = false;
|
||||
}
|
||||
if (action.kind == SimulatorGcodeControlKind::RtcpState &&
|
||||
!action.rtcp_enabled) {
|
||||
simulator_only_line = false;
|
||||
}
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
if (!all_control_actions_handled && simulator_control_actions.size() > 1) {
|
||||
for (const auto &action : simulator_control_actions) {
|
||||
if (!can_emit_simulator_gcode_control_action(sink_, action) &&
|
||||
action.kind == SimulatorGcodeControlKind::KinematicsSwitch) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M" + std::to_string(action.m_code);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (all_control_actions_handled) {
|
||||
for (const auto &action : simulator_control_actions) {
|
||||
emit_simulator_gcode_control_action(sink_, action, line_number);
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (simulator_only_line) {
|
||||
@@ -6578,7 +6852,8 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
if (l == 0) {
|
||||
if (spindle_tool_id_ > 0) {
|
||||
if (error) {
|
||||
*error = "G10 L0 not allowed with loaded tool";
|
||||
*error = "G10 L0 not allowed with loaded tool <" +
|
||||
std::to_string(spindle_tool_id_) + ">";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -6761,21 +7036,30 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
if (explicit_comp) {
|
||||
if (!words.count('D')) {
|
||||
if (error) {
|
||||
*error = "G41.1/G42.1 requires a D word";
|
||||
*error = std::string(cutter_comp_left ? "G41.1" : "G42.1") +
|
||||
" with no D word";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (words.count('L') && sink_.plane() != 18) {
|
||||
if (error) {
|
||||
*error = "G41.1/G42.1 with L word requires G18";
|
||||
*error = std::string(cutter_comp_left ? "G41.1" : "G42.1") +
|
||||
" with L word, but plane is not G18";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else if (words.count('D')) {
|
||||
const double d_value = words.at('D');
|
||||
if (std::fabs(d_value - std::round(d_value)) > 0.0001 || d_value < 0.0) {
|
||||
if (std::fabs(d_value - std::round(d_value)) > 0.0001) {
|
||||
if (error) {
|
||||
*error = "G41/G42 requires a non-negative whole-number D word";
|
||||
*error = std::string(cutter_comp_left ? "G41" : "G42") +
|
||||
" requires D word to be a whole number";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (d_value < 0.0) {
|
||||
if (error) {
|
||||
*error = "Negative d word tool radius index used";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -7466,6 +7750,15 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
for (int m : m_codes) {
|
||||
if ((m == 428 || m == 429 || m == 430) &&
|
||||
!sink_.can_switch_m_code_kinematics(m)) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M" + std::to_string(m);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (modal_motion_is_threading(modal_motion) && words.count('F')) {
|
||||
if (error) {
|
||||
@@ -7526,6 +7819,7 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
sink_.select_tool(tool_id);
|
||||
selected_tool_id_ = tool_id;
|
||||
selected_pocket_index_ = tool_id;
|
||||
tool_selected_ = true;
|
||||
}
|
||||
|
||||
@@ -7626,6 +7920,16 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
break;
|
||||
}
|
||||
const int spindle = selected_spindle;
|
||||
if ((m == 3 || m == 4 || m == 5) &&
|
||||
parsed_word_list.dollar_flag &&
|
||||
!smoke_spindle_selector_valid_for_speed(parsed_word_list.dollar_value)) {
|
||||
if (error) {
|
||||
*error = "Spindle ($) number out of range in M" + std::to_string(m) +
|
||||
" Command\nnum_spindles =" + std::to_string(kSmokeNumSpindles) +
|
||||
". $=" + std::to_string(rounded_value(parsed_word_list.dollar_value)) + "\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (m == 3) {
|
||||
sink_.start_spindle(spindle, 1, line_number);
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
@@ -7662,6 +7966,10 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
if (selected_tool_id_ == 0) {
|
||||
spindle_tool_id_ = 0;
|
||||
}
|
||||
current_pocket_index_ = selected_pocket_index_;
|
||||
} else if (m == 7) {
|
||||
sink_.set_mist_on(true);
|
||||
emit_comment_state(sink_, line_number, 11);
|
||||
@@ -7810,6 +8118,10 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
sink_.select_tool(tool_number);
|
||||
sink_.change_tool(line_number);
|
||||
if (tool_number == 0) {
|
||||
spindle_tool_id_ = 0;
|
||||
}
|
||||
current_pocket_index_ = tool_number;
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -7944,17 +8256,32 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
return -1;
|
||||
}
|
||||
} else if (m == 428) {
|
||||
sink_.switch_kinematics(1, true, line_number);
|
||||
if (!sink_.switch_m_code_kinematics(428, 1, line_number)) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M428";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (m == 429) {
|
||||
sink_.switch_kinematics(0, false, line_number);
|
||||
if (!sink_.switch_m_code_kinematics(429, 0, line_number)) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M429";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (m == 430) {
|
||||
sink_.switch_kinematics(2, true, line_number);
|
||||
if (!sink_.switch_m_code_kinematics(430, 2, line_number)) {
|
||||
if (error) {
|
||||
*error = "M-code greater than 199: M430";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -8077,8 +8404,15 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
const bool arc_center_or_radius_words =
|
||||
(modal_motion == 2 || modal_motion == 3) &&
|
||||
(words.count('I') || words.count('J') || words.count('K') ||
|
||||
(words.count('R') && !has_m_code(word_list, 19)));
|
||||
const bool current_line_requests_motion =
|
||||
has_axis_words || parsed_word_list.radius_flag || parsed_word_list.theta_flag;
|
||||
has_axis_words ||
|
||||
parsed_word_list.radius_flag ||
|
||||
parsed_word_list.theta_flag ||
|
||||
arc_center_or_radius_words;
|
||||
const bool explicit_threading_motion =
|
||||
has_g_code(word_list, 33.0) || has_g_code(word_list, 33.1) || has_g_code(word_list, 76.0);
|
||||
if ((current_line_requests_motion || explicit_threading_motion) && !has_axis_words &&
|
||||
@@ -8723,11 +9057,23 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (!validate_arc_format_words(words, error)) {
|
||||
return -1;
|
||||
}
|
||||
if (!validate_arc_plane_center_words(words, sink_.plane(), error)) {
|
||||
return -1;
|
||||
}
|
||||
if (!validate_r_arc_endpoint_words(words, parsed_word_list, sink_.plane(), error)) {
|
||||
return -1;
|
||||
}
|
||||
event.arc_turns = modal_motion == 2 ? -1 : 1;
|
||||
if (words.count('R') &&
|
||||
!validate_r_arc_reaches_end_point(event, sink_.plane(), words.at('R') * sink_.unit_scale(), error)) {
|
||||
return -1;
|
||||
}
|
||||
if (!validate_absolute_center_arc_axis_words(words, sink_.plane(), arc_absolute_, error)) {
|
||||
return -1;
|
||||
}
|
||||
set_arc_center(&event, words, sink_.plane(), sink_.unit_scale(), arc_absolute_);
|
||||
if (!words.count('R') &&
|
||||
!validate_arc_center_radius_consistency(event, sink_.plane(), sink_.unit_scale(), error)) {
|
||||
@@ -8964,7 +9310,7 @@ int SmokeGcodeParser::parse(const char *program, size_t program_len, std::string
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
emit_comment_state(sink_, line_number, 970);
|
||||
emit_comment_state(sink_, line_number, kConstantRpmSpindleModeEvent);
|
||||
if (stop_if_callback_aborted(sink_, error)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
|
||||
private:
|
||||
struct SmokeToolTableEntry {
|
||||
int pocketno = 0;
|
||||
CncSimPose offset{};
|
||||
double diameter = 0.0;
|
||||
double frontangle = 0.0;
|
||||
@@ -64,5 +65,7 @@ private:
|
||||
double oword_return_value_ = 0.0;
|
||||
bool oword_value_returned_ = false;
|
||||
int selected_tool_id_ = 0;
|
||||
int current_pocket_index_ = 0;
|
||||
int selected_pocket_index_ = 0;
|
||||
std::unordered_map<int, SmokeToolTableEntry> tool_table_;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "canon_event_sink.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
@@ -25,6 +26,18 @@ bool expect(bool value, const char *message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool near(double actual, double expected) {
|
||||
return std::fabs(actual - expected) < 1e-9;
|
||||
}
|
||||
|
||||
bool expect_near(double actual, double expected, const char *message) {
|
||||
if (!near(actual, expected)) {
|
||||
std::cerr << "FAIL: " << message << " actual=" << actual << " expected=" << expected << '\n';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
@@ -32,6 +45,8 @@ int main() {
|
||||
std::vector<CncSimEvent> events;
|
||||
CanonEventSink sink;
|
||||
sink.set_callback(collect_event, &events);
|
||||
ok &= expect(sink.kinematics_type() == 0,
|
||||
"expected LinuxCNC xyzbc-trt identityfirst startup kinematics type 0");
|
||||
|
||||
CncSimPose end{};
|
||||
end.x = 10.0;
|
||||
@@ -49,6 +64,8 @@ int main() {
|
||||
|
||||
int abort_count = 0;
|
||||
sink.reset();
|
||||
ok &= expect(sink.kinematics_type() == 0,
|
||||
"expected LinuxCNC xyzbc-trt identityfirst reset kinematics type 0");
|
||||
sink.set_callback(abort_on_second_event, &abort_count);
|
||||
sink.select_plane(17, 1);
|
||||
sink.set_feed_rate(100.0, 2);
|
||||
@@ -56,6 +73,290 @@ int main() {
|
||||
ok &= expect(sink.callback_aborted(), "expected callback abort state");
|
||||
ok &= expect(abort_count == 2, "expected no further callbacks after abort");
|
||||
|
||||
events.clear();
|
||||
sink.reset();
|
||||
sink.set_callback(collect_event, &events);
|
||||
sink.configure_rtcp(false, 250.0);
|
||||
sink.switch_kinematics(2, 1);
|
||||
CncSimPose five_axis_end{};
|
||||
five_axis_end.x = 260.0;
|
||||
five_axis_end.y = 20.0;
|
||||
five_axis_end.z = 280.0;
|
||||
five_axis_end.b = 90.0;
|
||||
five_axis_end.c = 45.0;
|
||||
five_axis_end.w = 12.0;
|
||||
sink.straight_feed(2, five_axis_end);
|
||||
bool saw_userk_before_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_userk_before_g434 = saw_userk_before_g434 || event.type == CNC_SIM_EVENT_RTCP_PIVOT;
|
||||
}
|
||||
ok &= expect(!saw_userk_before_g434, "expected M430 not to enable RTCP without G43.4/G43.5");
|
||||
|
||||
events.clear();
|
||||
sink.set_rtcp_state(true, 0, 2);
|
||||
sink.straight_feed(3, five_axis_end);
|
||||
bool saw_userk_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_userk_pivot = saw_userk_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 2 &&
|
||||
near(event.dwell_seconds, 250.0) &&
|
||||
near(event.end.x, 260.0) &&
|
||||
near(event.end.y, 20.0) &&
|
||||
near(event.end.z, 280.0) &&
|
||||
near(event.end.b, 90.0) &&
|
||||
near(event.end.c, 45.0) &&
|
||||
near(event.end.w, 0.0));
|
||||
}
|
||||
ok &= expect(saw_userk_pivot, "expected M430-style RTCP pivot to use LinuxCNC userk identity inverse");
|
||||
|
||||
events.clear();
|
||||
sink.configure_rtcp(true, 0.0);
|
||||
sink.switch_kinematics(2, 3);
|
||||
bool saw_userk_remap_m68 = false;
|
||||
bool saw_userk_remap_m66 = false;
|
||||
bool saw_userk_switch_rtcp_feed = false;
|
||||
for (const auto &event : events) {
|
||||
saw_userk_remap_m68 = saw_userk_remap_m68 ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 68 &&
|
||||
event.tool == 3 &&
|
||||
near(event.feed, 2.0));
|
||||
saw_userk_remap_m66 = saw_userk_remap_m66 ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 66 &&
|
||||
event.tool == 0 &&
|
||||
near(event.feed, 0.0) &&
|
||||
near(event.dwell_seconds, 0.0));
|
||||
saw_userk_switch_rtcp_feed = saw_userk_switch_rtcp_feed ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 2 &&
|
||||
near(event.feed, 1.0));
|
||||
}
|
||||
ok &= expect(saw_userk_remap_m68, "expected M430 remap to emit LinuxCNC M68 E3 Q2 side effect");
|
||||
ok &= expect(saw_userk_remap_m66, "expected M430 remap to emit LinuxCNC M66 E0 L0 side effect");
|
||||
ok &= expect(!saw_userk_switch_rtcp_feed,
|
||||
"expected kinematics switch event not to carry RTCP state");
|
||||
|
||||
events.clear();
|
||||
CncSimPose zero_tool_end{};
|
||||
zero_tool_end.x = 7.0;
|
||||
zero_tool_end.y = 8.0;
|
||||
zero_tool_end.z = 9.0;
|
||||
zero_tool_end.b = 10.0;
|
||||
zero_tool_end.c = 11.0;
|
||||
sink.straight_feed(4, zero_tool_end);
|
||||
bool saw_zero_tool_userk_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_zero_tool_userk_pivot = saw_zero_tool_userk_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 4 &&
|
||||
event.reserved == 2 &&
|
||||
near(event.dwell_seconds, 0.0) &&
|
||||
near(event.end.x, 7.0) &&
|
||||
near(event.end.y, 8.0) &&
|
||||
near(event.end.z, 9.0) &&
|
||||
near(event.end.b, 10.0) &&
|
||||
near(event.end.c, 11.0));
|
||||
}
|
||||
ok &= expect(saw_zero_tool_userk_pivot, "expected M430 userk inverse to run with zero tool offset");
|
||||
|
||||
events.clear();
|
||||
sink.configure_rtcp(false, 250.0);
|
||||
sink.switch_kinematics(1, 3);
|
||||
CncSimPose trt_end{};
|
||||
trt_end.x = 225.0;
|
||||
trt_end.y = 20.0;
|
||||
trt_end.z = -205.0;
|
||||
trt_end.b = 90.0;
|
||||
sink.straight_feed(4, trt_end);
|
||||
bool saw_trt_before_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_trt_before_g434 = saw_trt_before_g434 || event.type == CNC_SIM_EVENT_RTCP_PIVOT;
|
||||
}
|
||||
ok &= expect(!saw_trt_before_g434, "expected M428 not to enable RTCP without G43.4/G43.5");
|
||||
|
||||
events.clear();
|
||||
sink.set_rtcp_state(true, 0, 4);
|
||||
sink.straight_feed(5, trt_end);
|
||||
bool saw_xyzbc_trt_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_xyzbc_trt_pivot = saw_xyzbc_trt_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 5 &&
|
||||
event.reserved == 1 &&
|
||||
near(event.dwell_seconds, 250.0) &&
|
||||
near(event.end.x, 10.0) &&
|
||||
near(event.end.y, 20.0) &&
|
||||
near(event.end.z, 30.0) &&
|
||||
near(event.end.b, 90.0));
|
||||
}
|
||||
ok &= expect(saw_xyzbc_trt_pivot, "expected M428-style RTCP pivot to use LinuxCNC xyzbc-trt inverse");
|
||||
|
||||
events.clear();
|
||||
LinuxCncXyzbcTrtParameters trt_parameters = linuxcnc_xyzbc_trt_default_parameters(0.0);
|
||||
trt_parameters.x_rot_point = 3.0;
|
||||
trt_parameters.y_rot_point = -4.0;
|
||||
trt_parameters.z_rot_point = 5.0;
|
||||
trt_parameters.x_offset = 2.0;
|
||||
trt_parameters.z_offset = 7.0;
|
||||
trt_parameters.conventional_directions = true;
|
||||
sink.configure_rtcp(false, 11.0);
|
||||
sink.configure_xyzbc_trt(trt_parameters);
|
||||
sink.switch_kinematics(1, 5);
|
||||
sink.set_rtcp_state(true, 0, 5);
|
||||
CncSimPose configured_trt_end{};
|
||||
configured_trt_end.x = 30.0;
|
||||
configured_trt_end.y = 40.0;
|
||||
configured_trt_end.z = 50.0;
|
||||
configured_trt_end.b = 20.0;
|
||||
configured_trt_end.c = -30.0;
|
||||
sink.straight_feed(6, configured_trt_end);
|
||||
LinuxCncXyzbcTrtParameters expected_trt_parameters = trt_parameters;
|
||||
expected_trt_parameters.tool_offset = 11.0;
|
||||
const LinuxCncFiveAxisJoints expected_configured_trt =
|
||||
linuxcnc_xyzbc_trt_inverse(configured_trt_end, expected_trt_parameters);
|
||||
bool saw_configured_trt_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_configured_trt_pivot = saw_configured_trt_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 6 &&
|
||||
event.reserved == 1 &&
|
||||
near(event.dwell_seconds, 11.0) &&
|
||||
near(event.end.x, expected_configured_trt.x) &&
|
||||
near(event.end.y, expected_configured_trt.y) &&
|
||||
near(event.end.z, expected_configured_trt.z) &&
|
||||
near(event.end.b, expected_configured_trt.b) &&
|
||||
near(event.end.c, expected_configured_trt.c));
|
||||
}
|
||||
ok &= expect(saw_configured_trt_pivot, "expected M428 xyzbc-trt inverse to use configured HAL-style pins");
|
||||
|
||||
events.clear();
|
||||
LinuxCncXyzbcTrtParameters xyzac_parameters = linuxcnc_xyzbc_trt_default_parameters(0.0);
|
||||
xyzac_parameters.y_offset = 20.0;
|
||||
xyzac_parameters.z_offset = 10.0;
|
||||
sink.configure_rtcp(false, 7.0);
|
||||
sink.configure_xyzac_trt(xyzac_parameters);
|
||||
sink.switch_kinematics(1, 6);
|
||||
sink.set_rtcp_state(true, 0, 6);
|
||||
CncSimPose xyzac_end{};
|
||||
xyzac_end.x = 12.0;
|
||||
xyzac_end.y = -8.0;
|
||||
xyzac_end.z = 42.0;
|
||||
xyzac_end.a = 35.0;
|
||||
xyzac_end.c = -25.0;
|
||||
sink.straight_feed(7, xyzac_end);
|
||||
LinuxCncXyzbcTrtParameters expected_xyzac_parameters = xyzac_parameters;
|
||||
expected_xyzac_parameters.tool_offset = 7.0;
|
||||
const LinuxCncFiveAxisJoints expected_xyzac =
|
||||
linuxcnc_xyzac_trt_inverse(xyzac_end, expected_xyzac_parameters);
|
||||
bool saw_xyzac_trt_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_xyzac_trt_pivot = saw_xyzac_trt_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 7 &&
|
||||
event.reserved == 1 &&
|
||||
near(event.dwell_seconds, 7.0) &&
|
||||
near(event.end.x, expected_xyzac.x) &&
|
||||
near(event.end.y, expected_xyzac.y) &&
|
||||
near(event.end.z, expected_xyzac.z) &&
|
||||
near(event.end.a, expected_xyzac.a) &&
|
||||
near(event.end.c, expected_xyzac.c));
|
||||
}
|
||||
ok &= expect(saw_xyzac_trt_pivot, "expected M428 xyzac-trt inverse to use LinuxCNC xyzacKinematicsInverse");
|
||||
|
||||
std::vector<CncSimEvent> fiveaxis_events;
|
||||
CanonEventSink fiveaxis_sink;
|
||||
fiveaxis_sink.set_callback(collect_event, &fiveaxis_events);
|
||||
fiveaxis_sink.configure_rtcp(true, 250.0);
|
||||
fiveaxis_sink.configure_fiveaxis(250.0, 0);
|
||||
fiveaxis_sink.switch_m_code_kinematics(428, 1, 8);
|
||||
CncSimPose bridgemill_end{};
|
||||
bridgemill_end.x = 260.0;
|
||||
bridgemill_end.y = 20.0;
|
||||
bridgemill_end.z = 280.0;
|
||||
bridgemill_end.b = 90.0;
|
||||
bridgemill_end.c = 0.0;
|
||||
fiveaxis_sink.straight_feed(9, bridgemill_end);
|
||||
bool saw_fiveaxis_pivot = false;
|
||||
for (const auto &event : fiveaxis_events) {
|
||||
saw_fiveaxis_pivot = saw_fiveaxis_pivot ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.line == 9 &&
|
||||
event.reserved == 0 &&
|
||||
near(event.dwell_seconds, 250.0) &&
|
||||
near(event.end.x, 10.0) &&
|
||||
near(event.end.y, 20.0) &&
|
||||
near(event.end.z, 30.0) &&
|
||||
near(event.end.b, 90.0) &&
|
||||
near(event.end.c, 0.0));
|
||||
}
|
||||
ok &= expect(saw_fiveaxis_pivot, "expected M428 bridgemill RTCP pivot to use LinuxCNC 5axiskins inverse");
|
||||
|
||||
std::vector<CncSimEvent> switchkins_events;
|
||||
CanonEventSink switchkins_sink;
|
||||
switchkins_sink.set_callback(collect_event, &switchkins_events);
|
||||
switchkins_sink.configure_switchkins_remap(0, 1, 2);
|
||||
switchkins_sink.switch_m_code_kinematics(428, 1, 10);
|
||||
switchkins_sink.switch_m_code_kinematics(429, 0, 11);
|
||||
bool saw_scara_m428 = false;
|
||||
bool saw_scara_m429 = false;
|
||||
for (const auto &event : switchkins_events) {
|
||||
saw_scara_m428 = saw_scara_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 10 &&
|
||||
event.reserved == 0);
|
||||
saw_scara_m429 = saw_scara_m429 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 11 &&
|
||||
event.reserved == 1);
|
||||
}
|
||||
ok &= expect(saw_scara_m428,
|
||||
"expected M428 scara/bridgemill/melfa remap to select LinuxCNC kinstype 0");
|
||||
ok &= expect(saw_scara_m429,
|
||||
"expected M429 scara/bridgemill/melfa remap to select LinuxCNC identity kinstype 1");
|
||||
|
||||
std::vector<CncSimEvent> table_dual_events;
|
||||
CanonEventSink table_dual_sink;
|
||||
table_dual_sink.set_callback(collect_event, &table_dual_events);
|
||||
table_dual_sink.configure_switchkins_remap(1, 0, -1);
|
||||
const bool table_dual_m430_handled = table_dual_sink.switch_m_code_kinematics(430, 2, 12);
|
||||
bool saw_table_dual_m430 = false;
|
||||
for (const auto &event : table_dual_events) {
|
||||
saw_table_dual_m430 = saw_table_dual_m430 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 12);
|
||||
}
|
||||
ok &= expect(!table_dual_m430_handled,
|
||||
"expected LinuxCNC table-dual-rotary config without 430remap.ngc to leave M430 unhandled");
|
||||
ok &= expect(!saw_table_dual_m430,
|
||||
"expected LinuxCNC table-dual-rotary config without 430remap.ngc to skip M430 switch");
|
||||
|
||||
events.clear();
|
||||
sink.configure_rtcp(true, 250.0);
|
||||
sink.switch_kinematics(0, 3);
|
||||
five_axis_end.x = 300.0;
|
||||
sink.straight_feed(4, five_axis_end);
|
||||
bool saw_disabled_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_disabled_pivot = saw_disabled_pivot || event.type == CNC_SIM_EVENT_RTCP_PIVOT;
|
||||
}
|
||||
ok &= expect(!saw_disabled_pivot, "expected M429-style kinematics switch to disable RTCP pivot events");
|
||||
|
||||
events.clear();
|
||||
sink.configure_rtcp(true, 250.0);
|
||||
sink.switch_kinematics(3, 5);
|
||||
sink.straight_feed(6, five_axis_end);
|
||||
bool saw_unknown_switchkins_pivot = false;
|
||||
for (const auto &event : events) {
|
||||
saw_unknown_switchkins_pivot = saw_unknown_switchkins_pivot || event.type == CNC_SIM_EVENT_RTCP_PIVOT;
|
||||
}
|
||||
ok &= expect(!saw_unknown_switchkins_pivot,
|
||||
"expected unsupported switchkins type to avoid generic RTCP fallback");
|
||||
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
#include "cnc_sim_api.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kToolLengthOffsetEvent = 430;
|
||||
constexpr int kCssSpindleModeEvent = 960;
|
||||
constexpr int kConstantRpmSpindleModeEvent = 970;
|
||||
|
||||
int collect_event(const CncSimEvent *event, void *user_data) {
|
||||
auto *events = static_cast<std::vector<CncSimEvent> *>(user_data);
|
||||
events->push_back(*event);
|
||||
@@ -30,6 +39,59 @@ bool near(double lhs, double rhs) {
|
||||
return std::fabs(lhs - rhs) < 0.000001;
|
||||
}
|
||||
|
||||
class ScopedEnv {
|
||||
public:
|
||||
ScopedEnv(const char *name, const char *value) : name_(name) {
|
||||
const char *old = std::getenv(name);
|
||||
if (old) {
|
||||
had_old_ = true;
|
||||
old_ = old;
|
||||
}
|
||||
setenv(name, value, 1);
|
||||
}
|
||||
|
||||
~ScopedEnv() {
|
||||
if (had_old_) {
|
||||
setenv(name_, old_.c_str(), 1);
|
||||
} else {
|
||||
unsetenv(name_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const char *name_;
|
||||
bool had_old_ = false;
|
||||
std::string old_;
|
||||
};
|
||||
|
||||
class ScopedTempDir {
|
||||
public:
|
||||
explicit ScopedTempDir(const char *prefix) {
|
||||
const char *tmpdir = std::getenv("TMPDIR");
|
||||
std::string tmpl = std::string(tmpdir ? tmpdir : "/tmp") + "/" + prefix + ".XXXXXX";
|
||||
std::vector<char> buffer(tmpl.begin(), tmpl.end());
|
||||
buffer.push_back('\0');
|
||||
char *dir = mkdtemp(buffer.data());
|
||||
if (!dir) {
|
||||
std::perror("mkdtemp");
|
||||
std::exit(1);
|
||||
}
|
||||
path_ = dir;
|
||||
}
|
||||
|
||||
~ScopedTempDir() {
|
||||
std::error_code error;
|
||||
std::filesystem::remove_all(path_, error);
|
||||
}
|
||||
|
||||
std::string file(const char *name) const {
|
||||
return path_ + "/" + name;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
bool saw_comment_state(const std::vector<CncSimEvent> &events,
|
||||
int line,
|
||||
int reserved,
|
||||
@@ -51,9 +113,235 @@ bool saw_comment_state(const std::vector<CncSimEvent> &events,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saw_any_kinematics_switch(const std::vector<CncSimEvent> &events, int line) {
|
||||
for (const auto &event : events) {
|
||||
if (event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == line) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saw_kinematics_switch(const std::vector<CncSimEvent> &events, int line, int kinstype) {
|
||||
for (const auto &event : events) {
|
||||
if (event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == line &&
|
||||
event.reserved == kinstype) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_ini_file_name_field(const std::string &field) {
|
||||
return field == "ini" ||
|
||||
field == "iniFile" ||
|
||||
field == "inifile" ||
|
||||
field == "iniFileName" ||
|
||||
field == "inifilename" ||
|
||||
field == "ini_file" ||
|
||||
field == "ini_file_name" ||
|
||||
field == "INI_FILE_NAME";
|
||||
}
|
||||
|
||||
bool expect_switchkins_remap_config(const std::string &json,
|
||||
int m428_type,
|
||||
int m429_type,
|
||||
int m430_type,
|
||||
const char *message) {
|
||||
std::vector<CncSimEvent> events;
|
||||
CncSimHandle *sim = cnc_sim_create();
|
||||
cnc_sim_set_event_callback(sim, collect_event, &events);
|
||||
const char supported_program[] =
|
||||
"M428\n"
|
||||
"M429\n";
|
||||
const char full_program[] =
|
||||
"M428\n"
|
||||
"M429\n"
|
||||
"M430\n";
|
||||
const char *program = m430_type >= 0 ? full_program : supported_program;
|
||||
const size_t program_len = m430_type >= 0 ? sizeof(full_program) - 1 : sizeof(supported_program) - 1;
|
||||
|
||||
bool ok = true;
|
||||
const std::string load_message = std::string(message) + " load";
|
||||
const std::string parse_message = std::string(message) + " parse M428/M429";
|
||||
const std::string m428_message = std::string(message) + " M428 kinstype";
|
||||
const std::string m429_message = std::string(message) + " M429 kinstype";
|
||||
ok &= expect(cnc_sim_load_config_json(sim, json.c_str(), json.size()) == 0, load_message.c_str());
|
||||
ok &= expect(cnc_sim_parse_program(sim, program, program_len) == 0, parse_message.c_str());
|
||||
ok &= expect(saw_kinematics_switch(events, 1, m428_type), m428_message.c_str());
|
||||
ok &= expect(saw_kinematics_switch(events, 2, m429_type), m429_message.c_str());
|
||||
if (m430_type >= 0) {
|
||||
const std::string m430_message = std::string(message) + " M430 kinstype";
|
||||
ok &= expect(saw_kinematics_switch(events, 3, m430_type), m430_message.c_str());
|
||||
} else {
|
||||
const std::string m430_reject_message = std::string(message) + " reject M430";
|
||||
const std::string m430_error_message = std::string(message) + " M430 error";
|
||||
const std::string m430_no_switch_message = std::string(message) + " M430 no switch";
|
||||
const std::string mixed_load_message = std::string(message) + " mixed load";
|
||||
const std::string mixed_reject_message = std::string(message) + " reject mixed M428/M430";
|
||||
const std::string mixed_error_message = std::string(message) + " mixed M430 error";
|
||||
const std::string mixed_no_switch_message = std::string(message) + " mixed no partial switch";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim, "M430\n", 5) != 0, m430_reject_message.c_str());
|
||||
// Source: LinuxCNC interp_read.cc reports NCE_M_CODE_GREATER_THAN_199;
|
||||
// linuxcnc_rs274_backend.cpp preserves the read-stage context.
|
||||
ok &= expect(std::string(cnc_sim_last_error(sim)) == "read failed: M-code greater than 199: M430",
|
||||
m430_error_message.c_str());
|
||||
ok &= expect(!saw_kinematics_switch(events, 1, 2), m430_no_switch_message.c_str());
|
||||
|
||||
std::vector<CncSimEvent> mixed_events;
|
||||
CncSimHandle *mixed_sim = cnc_sim_create();
|
||||
cnc_sim_set_event_callback(mixed_sim, collect_event, &mixed_events);
|
||||
ok &= expect(cnc_sim_load_config_json(mixed_sim, json.c_str(), json.size()) == 0,
|
||||
mixed_load_message.c_str());
|
||||
ok &= expect(cnc_sim_parse_program(mixed_sim, "M428 M430\n", 9) != 0,
|
||||
mixed_reject_message.c_str());
|
||||
ok &= expect(std::string(cnc_sim_last_error(mixed_sim)) == "M-code greater than 199: M430",
|
||||
mixed_error_message.c_str());
|
||||
ok &= expect(!saw_any_kinematics_switch(mixed_events, 1), mixed_no_switch_message.c_str());
|
||||
cnc_sim_destroy(mixed_sim);
|
||||
}
|
||||
cnc_sim_destroy(sim);
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
ScopedTempDir temp_dir("cnc_sim_api_linuxcnc_rs274_smoke");
|
||||
|
||||
{
|
||||
std::vector<CncSimEvent> default_events;
|
||||
CncSimHandle *default_sim = cnc_sim_create();
|
||||
cnc_sim_set_event_callback(default_sim, collect_event, &default_events);
|
||||
const char default_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"G0 X1\n"
|
||||
"M30\n";
|
||||
bool default_ok = true;
|
||||
default_ok &= expect(cnc_sim_parse_program(default_sim,
|
||||
default_program,
|
||||
sizeof(default_program) - 1) == 0,
|
||||
cnc_sim_last_error(default_sim));
|
||||
bool saw_default_linuxcnc_rapid = false;
|
||||
for (const auto &event : default_events) {
|
||||
saw_default_linuxcnc_rapid = saw_default_linuxcnc_rapid ||
|
||||
(event.type == CNC_SIM_EVENT_RAPID &&
|
||||
event.line == 2 &&
|
||||
near(event.end.x, 1.0));
|
||||
}
|
||||
default_ok &= expect(saw_default_linuxcnc_rapid,
|
||||
"expected compiled API default backend to use LinuxCNC rs274");
|
||||
cnc_sim_destroy(default_sim);
|
||||
if (!default_ok) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const std::string ini_parameter_var_path = temp_dir.file("ini_parameter.var");
|
||||
{
|
||||
std::ofstream var_file(ini_parameter_var_path);
|
||||
var_file << "5001\t44.000000\n";
|
||||
}
|
||||
const std::string rs274_ini_path = temp_dir.file("rs274_parameter.ini");
|
||||
{
|
||||
std::ofstream ini_file(rs274_ini_path);
|
||||
ini_file << "[RS274NGC]\n";
|
||||
ini_file << "PARAMETER_FILE = " << ini_parameter_var_path << "\n";
|
||||
ini_file << "[SETUP]\n";
|
||||
ini_file << "XPOS = 12\n";
|
||||
}
|
||||
std::vector<CncSimEvent> ini_events;
|
||||
CncSimHandle *ini_sim = cnc_sim_create();
|
||||
cnc_sim_set_event_callback(ini_sim, collect_event, &ini_events);
|
||||
const std::string ini_config =
|
||||
std::string("{\"backend\":\"linuxcnc-rs274\",\"iniFileName\":\"") +
|
||||
rs274_ini_path +
|
||||
"\"}";
|
||||
bool ini_ok = true;
|
||||
ini_ok &= expect(cnc_sim_load_config_json(ini_sim, ini_config.c_str(), ini_config.size()) == 0,
|
||||
cnc_sim_last_error(ini_sim));
|
||||
ScopedEnv file_mode_env("CNC_SIM_RS274_FILE_MODE", "1");
|
||||
const char ini_parameter_check_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"F100\n"
|
||||
"G1 X#5001\n"
|
||||
"G1 X#<_ini[setup]xpos>\n"
|
||||
"M30\n";
|
||||
const int ini_parse_rc = cnc_sim_parse_program(ini_sim,
|
||||
ini_parameter_check_program,
|
||||
sizeof(ini_parameter_check_program) - 1);
|
||||
const std::string ini_parse_error = cnc_sim_last_error(ini_sim);
|
||||
ini_ok &= expect(ini_parse_rc == 0, ini_parse_error.c_str());
|
||||
bool saw_ini_parameter_restore = false;
|
||||
bool saw_ini_named_parameter = false;
|
||||
for (const auto &event : ini_events) {
|
||||
saw_ini_parameter_restore = saw_ini_parameter_restore ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 3 &&
|
||||
near(event.end.x, 44.0));
|
||||
saw_ini_named_parameter = saw_ini_named_parameter ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 4 &&
|
||||
near(event.end.x, 12.0));
|
||||
}
|
||||
// LinuxCNC source basis: emctask.cc calls interp.ini_load(), and
|
||||
// rs274ngc_pre.cc ini_load() maps [RS274NGC] PARAMETER_FILE through
|
||||
// SET_PARAMETER_FILE_NAME before rs274_ngc_init() restores parameters.
|
||||
ini_ok &= expect(saw_ini_parameter_restore,
|
||||
"expected LinuxCNC INI PARAMETER_FILE to restore numbered parameters");
|
||||
// LinuxCNC source basis: rs274ngc_pre.cc and interp_namedparams.cc
|
||||
// read INI_FILE_NAME for #<_ini[section]key> lookups.
|
||||
ini_ok &= expect(saw_ini_named_parameter,
|
||||
"expected LinuxCNC config INI_FILE_NAME to back #<_ini[]> named parameters");
|
||||
cnc_sim_destroy(ini_sim);
|
||||
if (!ini_ok) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<CncSimEvent> percent_events;
|
||||
CncSimHandle *percent_sim = cnc_sim_create();
|
||||
cnc_sim_set_event_callback(percent_sim, collect_event, &percent_events);
|
||||
ScopedEnv file_mode_env("CNC_SIM_RS274_FILE_MODE", "1");
|
||||
const char percent_program[] =
|
||||
"%\n"
|
||||
"G21 G90\n"
|
||||
"F100\n"
|
||||
"G1 X1\n"
|
||||
"%\n"
|
||||
"G1 X99\n";
|
||||
bool percent_ok = true;
|
||||
percent_ok &= expect(cnc_sim_parse_program(percent_sim,
|
||||
percent_program,
|
||||
sizeof(percent_program) - 1) == 0,
|
||||
cnc_sim_last_error(percent_sim));
|
||||
std::vector<int> feed_lines;
|
||||
std::vector<double> feed_x;
|
||||
for (const auto &event : percent_events) {
|
||||
if (event.type == CNC_SIM_EVENT_LINEAR_FEED) {
|
||||
feed_lines.push_back(event.line);
|
||||
feed_x.push_back(event.end.x);
|
||||
}
|
||||
}
|
||||
// LinuxCNC source basis: rs274ngc_pre.cc open() enables percent-file
|
||||
// mode when the first nonblank line is '%'; interp_read.cc read_text()
|
||||
// stops at the matching '%', so later program text is ignored.
|
||||
percent_ok &= expect(feed_lines.size() == 1 &&
|
||||
feed_lines[0] == 4 &&
|
||||
feed_x.size() == 1 &&
|
||||
near(feed_x[0], 1.0),
|
||||
"expected LinuxCNC percent-file mode to ignore trailing text");
|
||||
cnc_sim_destroy(percent_sim);
|
||||
if (!percent_ok) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const char config[] =
|
||||
"{\"backend\":\"linuxcnc-rs274\",\"rtcp\":{\"enabled\":true,\"toolLength\":100,\"toolLengths\":{\"7\":125}}}";
|
||||
const char program[] =
|
||||
@@ -62,6 +350,7 @@ int main() {
|
||||
"M428 M429 M430\n"
|
||||
"G49\n"
|
||||
"G43.4 H7\n"
|
||||
"G43.5 H7\n"
|
||||
"S8000 M3\n"
|
||||
"G0 X0 Y0 Z5\n"
|
||||
"F600\n"
|
||||
@@ -91,6 +380,7 @@ int main() {
|
||||
bool saw_m430 = false;
|
||||
bool saw_g49 = false;
|
||||
bool saw_g434 = false;
|
||||
bool saw_g435 = false;
|
||||
bool saw_g5x_offset = false;
|
||||
bool saw_xy_rotation = false;
|
||||
bool saw_g92_clear = false;
|
||||
@@ -180,22 +470,20 @@ int main() {
|
||||
saw_end = saw_end || event.type == CNC_SIM_EVENT_PROGRAM_END;
|
||||
saw_rtcp = saw_rtcp ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_PIVOT &&
|
||||
event.end.z == 130.0);
|
||||
event.reserved == 2 &&
|
||||
event.end.z == 5.0);
|
||||
saw_m428 = saw_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 1 &&
|
||||
event.feed == 1.0);
|
||||
event.reserved == 1);
|
||||
saw_m429 = saw_m429 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 0 &&
|
||||
event.feed == 0.0);
|
||||
event.reserved == 0);
|
||||
saw_m430 = saw_m430 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 2 &&
|
||||
event.feed == 1.0);
|
||||
event.reserved == 2);
|
||||
saw_g49 = saw_g49 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 4 &&
|
||||
@@ -206,6 +494,12 @@ int main() {
|
||||
event.feed == 1.0 &&
|
||||
event.tool == 7 &&
|
||||
event.dwell_seconds == 125.0);
|
||||
saw_g435 = saw_g435 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 6 &&
|
||||
event.feed == 1.0 &&
|
||||
event.tool == 7 &&
|
||||
event.dwell_seconds == 125.0);
|
||||
}
|
||||
|
||||
ok &= expect(saw_tool, "expected LinuxCNC tool-change event");
|
||||
@@ -217,8 +511,17 @@ int main() {
|
||||
ok &= expect(saw_m428, "expected LinuxCNC M428 kinematics switch");
|
||||
ok &= expect(saw_m429, "expected LinuxCNC M429 kinematics switch");
|
||||
ok &= expect(saw_m430, "expected LinuxCNC M430 kinematics switch");
|
||||
ok &= expect(saw_comment_state(events, 3, 68, 3, 1.0),
|
||||
"expected LinuxCNC M428 remap M68 E3 Q1 side effect");
|
||||
ok &= expect(saw_comment_state(events, 3, 68, 3, 0.0),
|
||||
"expected LinuxCNC M429 remap M68 E3 Q0 side effect");
|
||||
ok &= expect(saw_comment_state(events, 3, 68, 3, 2.0),
|
||||
"expected LinuxCNC M430 remap M68 E3 Q2 side effect");
|
||||
ok &= expect(saw_comment_state(events, 3, 66, 0, 0.0),
|
||||
"expected LinuxCNC M428/M429/M430 remap M66 E0 L0 side effect");
|
||||
ok &= expect(saw_g49, "expected LinuxCNC G49 RTCP off state");
|
||||
ok &= expect(saw_g434, "expected LinuxCNC G43.4 RTCP on state with H code");
|
||||
ok &= expect(saw_g435, "expected LinuxCNC G43.5 RTCP on state with H code");
|
||||
|
||||
const char arc_planes_program[] =
|
||||
"G21 G90 G17\n"
|
||||
@@ -416,25 +719,25 @@ int main() {
|
||||
saw_g431_tool_length = saw_g431_tool_length ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
event.start.x == 1.0 &&
|
||||
event.start.z == 2.0);
|
||||
saw_g432_tool_length = saw_g432_tool_length ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
event.start.x == 1.25 &&
|
||||
event.start.z == 2.5);
|
||||
saw_g49_dynamic_tool_length_clear = saw_g49_dynamic_tool_length_clear ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 5 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
event.start.x == 0.0 &&
|
||||
event.start.z == 0.0);
|
||||
saw_g432_h_tool_length = saw_g432_h_tool_length ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 4 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
event.start.x == 1.25 &&
|
||||
event.start.z == 15.0);
|
||||
}
|
||||
@@ -474,6 +777,109 @@ int main() {
|
||||
ok &= expect(saw_g49_tool_offset_parameter_before && saw_g49_tool_offset_parameter_after,
|
||||
"expected LinuxCNC G49 to clear the applied tool offset parameter before the next motion");
|
||||
|
||||
const char tool_pocket_named_parameter_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"T1\n"
|
||||
"O10 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 0]]\n"
|
||||
"G1 X1 F100\n"
|
||||
"O10 endif\n"
|
||||
"M6\n"
|
||||
"O20 if [[#<_selected_tool> EQ 1] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ 1] AND [#<_current_pocket> EQ 1]]\n"
|
||||
"G1 Y1 F100\n"
|
||||
"O20 endif\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
tool_pocket_named_parameter_program,
|
||||
sizeof(tool_pocket_named_parameter_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_tool_pocket_before_change = false;
|
||||
bool saw_tool_pocket_after_change = false;
|
||||
for (const auto &event : events) {
|
||||
saw_tool_pocket_before_change = saw_tool_pocket_before_change ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 4 &&
|
||||
near(event.end.x, 1.0));
|
||||
saw_tool_pocket_after_change = saw_tool_pocket_after_change ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 8 &&
|
||||
near(event.end.y, 1.0));
|
||||
}
|
||||
ok &= expect(saw_tool_pocket_before_change && saw_tool_pocket_after_change,
|
||||
"expected LinuxCNC tool pocket named parameters to follow selected/current pocket indexes");
|
||||
|
||||
const char m61_tool_pocket_named_parameter_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"M61 Q1\n"
|
||||
"O10 if [[#<_selected_tool> EQ 0] AND [#<_current_tool> EQ 0] AND [#<_selected_pocket> EQ -1] AND [#<_current_pocket> EQ 1]]\n"
|
||||
"G1 X1 F100\n"
|
||||
"O10 endif\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
m61_tool_pocket_named_parameter_program,
|
||||
sizeof(m61_tool_pocket_named_parameter_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_m61_tool_pocket_named_parameter = false;
|
||||
for (const auto &event : events) {
|
||||
saw_m61_tool_pocket_named_parameter = saw_m61_tool_pocket_named_parameter ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 4 &&
|
||||
near(event.end.x, 1.0));
|
||||
}
|
||||
ok &= expect(saw_m61_tool_pocket_named_parameter,
|
||||
"expected LinuxCNC M61 to publish the current pocket without changing selected/current tool named parameters");
|
||||
|
||||
{
|
||||
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
|
||||
const char m61_unload_spindle_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"M61 Q0\n"
|
||||
"O10 if [#5400 EQ 0]\n"
|
||||
"G1 X1 F100\n"
|
||||
"O10 endif\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
m61_unload_spindle_program,
|
||||
sizeof(m61_unload_spindle_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_m61_unload_spindle = false;
|
||||
for (const auto &event : events) {
|
||||
saw_m61_unload_spindle = saw_m61_unload_spindle ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 4 &&
|
||||
near(event.end.x, 1.0));
|
||||
}
|
||||
ok &= expect(saw_m61_unload_spindle,
|
||||
"expected LinuxCNC M61 Q0 to unload the spindle current tool number");
|
||||
}
|
||||
|
||||
{
|
||||
ScopedEnv spindle_tool_env("CNC_SIM_TOOL_IN_SPINDLE", "1");
|
||||
const char t0_m6_unload_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"T0 M6\n"
|
||||
"O10 if [#5400 EQ 0]\n"
|
||||
"G1 X1 F100\n"
|
||||
"O10 endif\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
t0_m6_unload_program,
|
||||
sizeof(t0_m6_unload_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_t0_m6_unload = false;
|
||||
for (const auto &event : events) {
|
||||
saw_t0_m6_unload = saw_t0_m6_unload ||
|
||||
(event.type == CNC_SIM_EVENT_LINEAR_FEED &&
|
||||
event.line == 4 &&
|
||||
near(event.end.x, 1.0));
|
||||
}
|
||||
ok &= expect(saw_t0_m6_unload,
|
||||
"expected LinuxCNC T0 M6 to unload the spindle current tool number");
|
||||
}
|
||||
|
||||
const char spindle_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"S1200 M3\n"
|
||||
@@ -517,12 +923,12 @@ int main() {
|
||||
saw_g97_mode = saw_g97_mode ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 970 &&
|
||||
event.reserved == kConstantRpmSpindleModeEvent &&
|
||||
event.feed == 0.0);
|
||||
saw_g96_mode = saw_g96_mode ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 960 &&
|
||||
event.reserved == kCssSpindleModeEvent &&
|
||||
event.feed == 2500.0);
|
||||
}
|
||||
ok &= expect(saw_g97_mode, "expected LinuxCNC G97 constant-RPM spindle mode state");
|
||||
@@ -903,12 +1309,12 @@ int main() {
|
||||
saw_tool_length = saw_tool_length ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
near(event.start.z, 12.5));
|
||||
saw_tool_length_clear = saw_tool_length_clear ||
|
||||
(event.type == CNC_SIM_EVENT_COMMENT &&
|
||||
event.line == 3 &&
|
||||
event.reserved == 430 &&
|
||||
event.reserved == kToolLengthOffsetEvent &&
|
||||
event.start.z == 0.0);
|
||||
}
|
||||
ok &= expect(saw_tool_length, "expected LinuxCNC G43 H1 tool length event");
|
||||
@@ -1272,6 +1678,213 @@ int main() {
|
||||
}
|
||||
ok &= expect(saw_block_delete_disabled_line, "expected LinuxCNC disabled block-delete line to execute");
|
||||
|
||||
const char block_delete_rtcp_controls_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"/N10 M428\n"
|
||||
"/N20 G43.4 H7\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_load_config_json(sim, block_delete_on_config, sizeof(block_delete_on_config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
block_delete_rtcp_controls_program,
|
||||
sizeof(block_delete_rtcp_controls_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_block_delete_skipped_m428 = false;
|
||||
bool saw_block_delete_skipped_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_block_delete_skipped_m428 = saw_block_delete_skipped_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 2);
|
||||
saw_block_delete_skipped_g434 = saw_block_delete_skipped_g434 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 3);
|
||||
}
|
||||
ok &= expect(!saw_block_delete_skipped_m428, "expected LinuxCNC block-delete M428 line to be skipped");
|
||||
ok &= expect(!saw_block_delete_skipped_g434, "expected LinuxCNC block-delete G43.4 line to be skipped");
|
||||
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_load_config_json(sim, block_delete_off_config, sizeof(block_delete_off_config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
block_delete_rtcp_controls_program,
|
||||
sizeof(block_delete_rtcp_controls_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_block_delete_disabled_m428 = false;
|
||||
bool saw_block_delete_disabled_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_block_delete_disabled_m428 = saw_block_delete_disabled_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 1);
|
||||
saw_block_delete_disabled_g434 = saw_block_delete_disabled_g434 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 3 &&
|
||||
event.tool == 7);
|
||||
}
|
||||
ok &= expect(saw_block_delete_disabled_m428, "expected LinuxCNC disabled block-delete M428 to execute");
|
||||
ok &= expect(saw_block_delete_disabled_g434, "expected LinuxCNC disabled block-delete G43.4 to execute");
|
||||
|
||||
const char unary_sign_rtcp_controls_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"M++428\n"
|
||||
"G+43.4 H++7\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_load_config_json(sim, config, sizeof(config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
unary_sign_rtcp_controls_program,
|
||||
sizeof(unary_sign_rtcp_controls_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_unary_sign_m428 = false;
|
||||
bool saw_unary_sign_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_unary_sign_m428 = saw_unary_sign_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 1);
|
||||
saw_unary_sign_g434 = saw_unary_sign_g434 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 3 &&
|
||||
event.tool == 7);
|
||||
}
|
||||
ok &= expect(saw_unary_sign_m428, "expected LinuxCNC source M++428 to execute as M428");
|
||||
ok &= expect(saw_unary_sign_g434, "expected LinuxCNC source G+43.4 H++7 to execute as G43.4 H7");
|
||||
|
||||
const char numbered_rtcp_controls_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"N10 M428\n"
|
||||
"N20 G43.4 H7\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
numbered_rtcp_controls_program,
|
||||
sizeof(numbered_rtcp_controls_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_numbered_m428 = false;
|
||||
bool saw_numbered_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_numbered_m428 = saw_numbered_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 1);
|
||||
saw_numbered_g434 = saw_numbered_g434 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 3 &&
|
||||
event.tool == 7);
|
||||
}
|
||||
ok &= expect(saw_numbered_m428, "expected LinuxCNC source N10 M428 to execute as M428");
|
||||
ok &= expect(saw_numbered_g434, "expected LinuxCNC source N20 G43.4 H7 to execute as G43.4 H7");
|
||||
|
||||
const char bracket_rtcp_controls_program[] =
|
||||
"G21 G90 G17\n"
|
||||
"M[428]\n"
|
||||
"G[43.4] H[7]\n"
|
||||
"M30\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
bracket_rtcp_controls_program,
|
||||
sizeof(bracket_rtcp_controls_program) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
bool saw_bracket_m428 = false;
|
||||
bool saw_bracket_g434 = false;
|
||||
for (const auto &event : events) {
|
||||
saw_bracket_m428 = saw_bracket_m428 ||
|
||||
(event.type == CNC_SIM_EVENT_KINEMATICS_SWITCH &&
|
||||
event.line == 2 &&
|
||||
event.reserved == 1);
|
||||
saw_bracket_g434 = saw_bracket_g434 ||
|
||||
(event.type == CNC_SIM_EVENT_RTCP_STATE &&
|
||||
event.line == 3 &&
|
||||
event.tool == 7);
|
||||
}
|
||||
ok &= expect(saw_bracket_m428, "expected LinuxCNC source M[428] to execute as M428");
|
||||
ok &= expect(saw_bracket_g434, "expected LinuxCNC source G[43.4] H[7] to execute as G43.4 H7");
|
||||
|
||||
const char table_dual_config[] =
|
||||
"{\"backend\":\"linuxcnc-rs274\","
|
||||
"\"config\":\"configs/sim/axis/vismach/5axis/table-dual-rotary/xyzab-tdr.ini\"}";
|
||||
ok &= expect(cnc_sim_load_config_json(sim, table_dual_config, sizeof(table_dual_config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
const char mixed_unremapped_m430_program[] =
|
||||
"G21 G90\n"
|
||||
"M428 M430\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
mixed_unremapped_m430_program,
|
||||
sizeof(mixed_unremapped_m430_program) - 1) != 0,
|
||||
"expected LinuxCNC source-backed config without 430remap.ngc to reject mixed M428/M430");
|
||||
ok &= expect(std::string(cnc_sim_last_error(sim)) == "M-code greater than 199: M430",
|
||||
"expected LinuxCNC source-backed mixed M428/M430 error to name unremapped M430");
|
||||
ok &= expect(!saw_any_kinematics_switch(events, 2),
|
||||
"expected LinuxCNC source-backed mixed M428/M430 error to emit no partial switch");
|
||||
ok &= expect(cnc_sim_load_config_json(sim, config, sizeof(config) - 1) == 0,
|
||||
cnc_sim_last_error(sim));
|
||||
|
||||
{
|
||||
struct SourceBackedConfigCase {
|
||||
const char *field;
|
||||
const char *value;
|
||||
int m428_type;
|
||||
int m429_type;
|
||||
int m430_type;
|
||||
};
|
||||
const SourceBackedConfigCase source_cases[] = {
|
||||
#include "linuxcnc_switchkins_remap_config_cases.inc"
|
||||
};
|
||||
for (const SourceBackedConfigCase &source_case : source_cases) {
|
||||
// LinuxCNC rs274ngc_pre.cc ini_load() loads REMAP NGC/Python
|
||||
// dependencies for INI_FILE_NAME. The native API probe above
|
||||
// covers real INI loading; generated switchkins INI aliases stay
|
||||
// covered by the table checker and smoke bridge probes.
|
||||
if (is_ini_file_name_field(source_case.field)) {
|
||||
continue;
|
||||
}
|
||||
const std::string json = std::string("{\"backend\":\"linuxcnc-rs274\",\"") +
|
||||
source_case.field +
|
||||
"\":\"" +
|
||||
source_case.value +
|
||||
"\"}";
|
||||
const std::string message = std::string("expected LinuxCNC source-backed switchkins remap config for ") +
|
||||
source_case.field +
|
||||
"=" +
|
||||
source_case.value;
|
||||
ok &= expect_switchkins_remap_config(json,
|
||||
source_case.m428_type,
|
||||
source_case.m429_type,
|
||||
source_case.m430_type,
|
||||
message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
const char exponent_m428_control_program[] =
|
||||
"G21 G90\n"
|
||||
"M4.28e2\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
exponent_m428_control_program,
|
||||
sizeof(exponent_m428_control_program) - 1) != 0,
|
||||
"expected LinuxCNC source backend to reject exponent M428 control syntax");
|
||||
|
||||
const char exponent_g434_control_program[] =
|
||||
"G21 G90\n"
|
||||
"G4.34e1 H7\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
exponent_g434_control_program,
|
||||
sizeof(exponent_g434_control_program) - 1) != 0,
|
||||
"expected LinuxCNC source backend to reject exponent G43.4 control syntax");
|
||||
|
||||
const char exponent_h_control_program[] =
|
||||
"G21 G90\n"
|
||||
"G43.4 H7e0\n";
|
||||
events.clear();
|
||||
ok &= expect(cnc_sim_parse_program(sim,
|
||||
exponent_h_control_program,
|
||||
sizeof(exponent_h_control_program) - 1) != 0,
|
||||
"expected LinuxCNC source backend to reject exponent H control syntax");
|
||||
|
||||
cnc_sim_destroy(sim);
|
||||
|
||||
int abort_count = 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user