解锁L4-TOOL-DB主机运行环境

结论:已识别RIP版LinuxCNC主机运行时,Tool DB native protocol probe可通过,inventory baseline保持28/28/131/0且promotion继续锁定。
This commit is contained in:
2026-06-19 06:28:38 +08:00
parent f101932bf1
commit d9ac3770a7
18 changed files with 3041 additions and 184 deletions

61
wasm-port/tests/native/probe_tool_db_runtime.sh Normal file → Executable file
View File

@@ -14,7 +14,22 @@ required_commands=(python3 linuxcnc milltask halcmd)
missing_requirements=()
command_path() {
command -v "$1" 2>/dev/null || true
local command_name="$1"
local path
path="$(command -v "$command_name" 2>/dev/null || true)"
if [[ -n "$path" ]]; then
printf '%s\n' "$path"
return
fi
case "$command_name" in
linuxcnc)
[[ -x "$LINUXCNC_ROOT/scripts/linuxcnc" ]] && printf '%s\n' "$LINUXCNC_ROOT/scripts/linuxcnc"
;;
milltask|halcmd)
[[ -x "$LINUXCNC_ROOT/bin/$command_name" ]] && printf '%s\n' "$LINUXCNC_ROOT/bin/$command_name"
;;
esac
}
csv_join() {
@@ -108,7 +123,11 @@ import time
db_program, db_demo_dir, python_path, db_savefile, stdout_log, stderr_log = sys.argv[1:]
env = os.environ.copy()
linuxcnc_root = os.path.dirname(os.path.dirname(python_path))
env["PYTHONPATH"] = python_path + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
env["LD_LIBRARY_PATH"] = os.path.join(linuxcnc_root, "lib") + (
os.pathsep + env["LD_LIBRARY_PATH"] if env.get("LD_LIBRARY_PATH") else ""
)
stdout_file = open(stdout_log, "w", encoding="utf-8")
stderr_file = open(stderr_log, "w", encoding="utf-8")
@@ -119,31 +138,41 @@ proc = subprocess.Popen(
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=stderr_file,
text=True,
bufsize=1,
bufsize=0,
)
stdout_buffer = b""
line_queue = []
def emit(name, value):
print(f"{name}={value}")
def read_line(timeout=5.0):
global stdout_buffer
if line_queue:
return line_queue.pop(0)
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
ready, _, _ = select.select([proc.stdout], [], [], 0.1)
if ready:
line = proc.stdout.readline()
if line == "":
chunk = os.read(proc.stdout.fileno(), 4096)
if chunk == b"":
raise RuntimeError("db_program_stdout_closed")
line = line.rstrip("\n")
stdout_file.write(line + "\n")
stdout_file.flush()
return line
stdout_buffer += chunk
while b"\n" in stdout_buffer:
raw_line, stdout_buffer = stdout_buffer.split(b"\n", 1)
line = raw_line.decode("utf-8", errors="replace").rstrip("\r")
stdout_file.write(line + "\n")
stdout_file.flush()
line_queue.append(line)
if line_queue:
return line_queue.pop(0)
if proc.poll() is not None:
raise RuntimeError(f"db_program_exited_{proc.returncode}")
raise RuntimeError("timeout_waiting_for_db_program_reply")
def send(command):
proc.stdin.write(command + "\n")
proc.stdin.write((command + "\n").encode("utf-8"))
proc.stdin.flush()
def read_until_fini(command, timeout=5.0):
@@ -157,6 +186,10 @@ def read_until_fini(command, timeout=5.0):
return lines
raise RuntimeError(f"timeout_waiting_for_fini_{command.split()[0]}")
def read_single_reply(command, timeout=5.0):
send(command)
return read_line(timeout)
def require(condition, message):
if not condition:
raise RuntimeError(message)
@@ -187,14 +220,14 @@ try:
load_reply = read_until_fini("l t14 p0")
emit("tool_db_load_spindle_fini", int(load_reply[-1].startswith("FINI")))
t14_loaded = read_until_fini("t 14")
require(any(line.startswith("T14 ") and "P0" in line for line in t14_loaded), "load_spindle_state_drift")
t14_loaded = read_single_reply("t 14")
require(t14_loaded.startswith("T14 ") and "P0" in t14_loaded, "load_spindle_state_drift")
emit("tool_db_load_spindle_state_ok", 1)
unload_reply = read_until_fini("u t0 p0")
emit("tool_db_unload_spindle_fini", int(unload_reply[-1].startswith("FINI")))
t14_unloaded = read_until_fini("t 14")
require(any(line.startswith("T14 ") and "P114" in line for line in t14_unloaded), "unload_spindle_state_drift")
t14_unloaded = read_single_reply("t 14")
require(t14_unloaded.startswith("T14 ") and "P114" in t14_unloaded, "unload_spindle_state_drift")
emit("tool_db_unload_spindle_state_ok", 1)
require(os.path.exists(db_savefile), "db_savefile_missing")