接续上一轮:推进浏览器验证与M428配置收拢
结论:已完成浏览器侧真实加载验证,M428/M429/M430 的配置入口进一步从 LinuxCNC INI/HALFILE/REMAP 来源生成,native 与 source-link 验证通过。
This commit is contained in:
@@ -64,8 +64,8 @@
|
||||
<label class="backend-select">
|
||||
<span>BACKEND</span>
|
||||
<select id="backendSelect">
|
||||
<option value="smoke">SMOKE</option>
|
||||
<option value="linuxcnc-rs274">LINUXCNC</option>
|
||||
<option value="smoke">SMOKE</option>
|
||||
</select>
|
||||
</label>
|
||||
<span id="lineCount">0 LINES</span>
|
||||
|
||||
19
web/public/cnc_sim.js
Normal file
19
web/public/cnc_sim.js
Normal file
File diff suppressed because one or more lines are too long
@@ -48,12 +48,55 @@ export type CncEvent = {
|
||||
reserved: number;
|
||||
};
|
||||
|
||||
export type CncRtcpOptions = {
|
||||
enabled: boolean;
|
||||
toolLength?: number;
|
||||
tool_length?: number;
|
||||
toolLengths?: Record<string, number>;
|
||||
tool_lengths?: Record<string, number>;
|
||||
};
|
||||
|
||||
export type CncXyzbcTrtOptions = {
|
||||
xRotPoint?: number;
|
||||
yRotPoint?: number;
|
||||
zRotPoint?: number;
|
||||
xOffset?: number;
|
||||
yOffset?: number;
|
||||
zOffset?: number;
|
||||
conventionalDirections?: boolean;
|
||||
x_rot_point?: number;
|
||||
y_rot_point?: number;
|
||||
z_rot_point?: number;
|
||||
x_offset?: number;
|
||||
y_offset?: number;
|
||||
z_offset?: number;
|
||||
conventional_directions?: boolean;
|
||||
};
|
||||
|
||||
export type CncParseOptions = {
|
||||
backend?: string;
|
||||
rtcp?: CncRtcpOptions;
|
||||
blockDelete?: boolean;
|
||||
block_delete?: boolean;
|
||||
switchkins?: string;
|
||||
remap?: string;
|
||||
kinematics?: string;
|
||||
trt?: "xyzbc" | "xyzac" | string;
|
||||
pivotLength?: number;
|
||||
pivot_length?: number;
|
||||
kinematicsType?: number;
|
||||
kinematics_type?: number;
|
||||
fiveaxisKinematicsType?: number;
|
||||
fiveaxis_kinematics_type?: number;
|
||||
xyzbcTrt?: CncXyzbcTrtOptions;
|
||||
};
|
||||
|
||||
export type SimulatorCore = {
|
||||
parse(
|
||||
program: string,
|
||||
dialect: CncDialect,
|
||||
options?: { backend?: string; rtcp?: { enabled: boolean; toolLength: number } },
|
||||
): Promise<CncEvent[]>;
|
||||
options?: CncParseOptions,
|
||||
): CncEvent[];
|
||||
};
|
||||
|
||||
export async function createSimulatorCore(): Promise<SimulatorCore> {
|
||||
|
||||
12
web/src/wasm-core.d.ts
vendored
12
web/src/wasm-core.d.ts
vendored
@@ -1,8 +1,14 @@
|
||||
import type { CncDialect, CncEvent } from "./index";
|
||||
import type { CncDialect, CncEvent, CncParseOptions } from "./index";
|
||||
|
||||
export type WasmSimulator = {
|
||||
parse(program: string, dialect?: CncDialect, options?: { backend?: string }): CncEvent[];
|
||||
parse(program: string, dialect?: CncDialect, options?: CncParseOptions): CncEvent[];
|
||||
dispose(): void;
|
||||
};
|
||||
|
||||
export function createWasmSimulator(): Promise<WasmSimulator>;
|
||||
export type WasmModuleOptions = {
|
||||
locateFile?: (file: string) => string;
|
||||
print?: (text: string) => void;
|
||||
printErr?: (text: string) => void;
|
||||
};
|
||||
|
||||
export function createWasmSimulator(moduleOptions?: WasmModuleOptions): Promise<WasmSimulator>;
|
||||
|
||||
@@ -74,17 +74,20 @@ function readEvent(module, ptr) {
|
||||
}
|
||||
|
||||
async function loadModuleFactory() {
|
||||
if (globalThis.createCncSimModule) {
|
||||
return globalThis.createCncSimModule;
|
||||
}
|
||||
const module = await import("/cnc_sim.js");
|
||||
return module.default ?? module.createCncSimModule ?? globalThis.createCncSimModule;
|
||||
}
|
||||
|
||||
export async function createWasmSimulator() {
|
||||
export async function createWasmSimulator(moduleOptions = {}) {
|
||||
const createModule = await loadModuleFactory();
|
||||
if (!createModule) {
|
||||
throw new Error("cnc_sim.js did not export createCncSimModule");
|
||||
}
|
||||
|
||||
const module = await createModule();
|
||||
const module = await createModule(moduleOptions);
|
||||
const create = module.cwrap("cnc_sim_create", "number", []);
|
||||
const destroy = module.cwrap("cnc_sim_destroy", null, ["number"]);
|
||||
const reset = module.cwrap("cnc_sim_reset", null, ["number"]);
|
||||
@@ -104,8 +107,25 @@ export async function createWasmSimulator() {
|
||||
setDialect(handle, DIALECT[dialect] ?? DIALECT.linuxcnc);
|
||||
|
||||
const config = JSON.stringify({
|
||||
backend: options.backend ?? "smoke",
|
||||
backend: options.backend ?? "linuxcnc-rs274",
|
||||
...(options.rtcp ? { rtcp: options.rtcp } : {}),
|
||||
...(options.blockDelete !== undefined ? { blockDelete: options.blockDelete } : {}),
|
||||
...(options.block_delete !== undefined ? { block_delete: options.block_delete } : {}),
|
||||
...(options.switchkins ? { switchkins: options.switchkins } : {}),
|
||||
...(options.remap ? { remap: options.remap } : {}),
|
||||
...(options.kinematics ? { kinematics: options.kinematics } : {}),
|
||||
...(options.trt ? { trt: options.trt } : {}),
|
||||
...(options.pivotLength !== undefined ? { pivotLength: options.pivotLength } : {}),
|
||||
...(options.pivot_length !== undefined ? { pivot_length: options.pivot_length } : {}),
|
||||
...(options.kinematicsType !== undefined ? { kinematicsType: options.kinematicsType } : {}),
|
||||
...(options.kinematics_type !== undefined ? { kinematics_type: options.kinematics_type } : {}),
|
||||
...(options.fiveaxisKinematicsType !== undefined
|
||||
? { fiveaxisKinematicsType: options.fiveaxisKinematicsType }
|
||||
: {}),
|
||||
...(options.fiveaxis_kinematics_type !== undefined
|
||||
? { fiveaxis_kinematics_type: options.fiveaxis_kinematics_type }
|
||||
: {}),
|
||||
...(options.xyzbcTrt ? { xyzbcTrt: options.xyzbcTrt } : {}),
|
||||
});
|
||||
const configBytes = module.lengthBytesUTF8(config) + 1;
|
||||
const configPtr = module._malloc(configBytes);
|
||||
|
||||
56
web/test-browser-wasm-smoke.html
Normal file
56
web/test-browser-wasm-smoke.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>CNC WASM Browser Smoke</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="result">pending</pre>
|
||||
<script src="/public/cnc_sim.js"></script>
|
||||
<script type="module">
|
||||
import { createWasmSimulator } from "/src/wasm-core.js";
|
||||
|
||||
const result = document.querySelector("#result");
|
||||
const near = (actual, expected) => Math.abs(actual - expected) < 1e-6;
|
||||
|
||||
try {
|
||||
const simulator = await createWasmSimulator({
|
||||
locateFile: (file) => `/public/${file}`,
|
||||
print: () => {},
|
||||
printErr: () => {},
|
||||
});
|
||||
try {
|
||||
const events = simulator.parse("G21 G90\nG0 X0\nG1 X5 F100\nM30\n", "linuxcnc", {
|
||||
backend: "linuxcnc-rs274",
|
||||
});
|
||||
const sawFeed = events.some((event) => event.type === "linear-feed" && near(event.end.x, 5));
|
||||
const sawEnd = events.some((event) => event.type === "program-end");
|
||||
if (!sawFeed || !sawEnd) {
|
||||
throw new Error("missing expected LinuxCNC WASM browser events");
|
||||
}
|
||||
const switchEvents = simulator.parse("M428\nM429\nM430\n", "linuxcnc", {
|
||||
backend: "linuxcnc-rs274",
|
||||
switchkins: "scara",
|
||||
});
|
||||
for (const [line, kinstype] of [
|
||||
[1, 0],
|
||||
[2, 1],
|
||||
[3, 2],
|
||||
]) {
|
||||
const sawSwitch = switchEvents.some(
|
||||
(event) => event.type === "kinematics-switch" && event.line === line && event.reserved === kinstype,
|
||||
);
|
||||
if (!sawSwitch) {
|
||||
throw new Error(`missing LinuxCNC WASM browser M${427 + line} switchkins type ${kinstype}`);
|
||||
}
|
||||
}
|
||||
result.textContent = "browser wasm smoke passed";
|
||||
} finally {
|
||||
simulator.dispose();
|
||||
}
|
||||
} catch (error) {
|
||||
result.textContent = `browser wasm smoke failed: ${error && error.stack ? error.stack : error}`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
14
web/tsconfig.json
Normal file
14
web/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"allowJs": false,
|
||||
"checkJs": false,
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/index.ts", "src/**/*.d.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user