Keep G-code matched to imported AC or BC machine type

This commit is contained in:
2026-09-21 19:52:31 +08:00
parent 86cfa2b7f0
commit 0de96bbc72
20 changed files with 315 additions and 4 deletions

View File

@@ -0,0 +1,32 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import createModule from '../../build-wasm/linuxcnc-sim-core.js';
import { loadSimulationCase, toWorkerConfiguration } from '../workspace/sim-case-loader.mjs';
import { SimSession, CONTEXT_ID } from './sim-session.mjs';
import { programMachineMismatch } from '../workspace/program-machine-compatibility.mjs';
for (const [coordinates, forbidden] of [['XYZAC','B'], ['XYZBC','A']]) {
for (const value of ['0','-12','[1+2]','#1',' #<angle>']) assert.match(programMachineMismatch(`G1X2${forbidden}${value}\nM2`,coordinates,'renamed.ngc'),/不匹配/);
for (const source of ['(A10 B20)\nG1X1 ; A30 B40\nM2','#<A1>=2\nG1X#<A1>\nM2','G1X[ABS[-1]+ATAN[1]/[2]]\nM2','O<ABC1> sub\nG1X1\nO<ABC1> endsub']) assert.equal(programMachineMismatch(source,coordinates,'generic.ngc'),'');
}
const fetchImpl=async(url)=>{try{const body=await readFile(new URL(`../../${String(url).replace(/^\//,'')}`,import.meta.url));return{ok:true,text:async()=>body.toString()};}catch{return{ok:false,text:async()=>''};}};
const core=await createModule({wasmBinary:await readFile(new URL('../../build-wasm/linuxcnc-sim-core.wasm',import.meta.url))});
const session=new SimSession(core,{sessionId:'compatibility'});let seq=0;
const send=(kind,payload={})=>session.accept({schema_version:1,context_id:CONTEXT_ID,session_id:session.sessionId,kind,seq:++seq,operation_id:`compat-${seq}`,payload});
send('HELLO');send('SESSION_ATTACH');const rows=[];
for(const coordinates of ['XYZAC','XYZBC']){
const bundle=await loadSimulationCase({path:`linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/${coordinates.toLowerCase()}-trt.ini`,fetchImpl});
assert.equal(send('LOAD_WORKSPACE',{root_path:'/workspace',configuration:toWorkerConfiguration(bundle)}).kind,'COMMAND_RESULT');
const own=coordinates[3],other=own==='A'?'B':'A';
assert.equal(send('PROGRAM_LOAD',{source:`G21 G90\nG1 X1 ${own}5 C3 F120\nM2\n`,path:'compatible.ngc'}).kind,'COMMAND_RESULT');
const previous=session.xyzacProgram.source;
for(const source of [`G1${other}0 F120\nM2\n`,`G1${other}#1 F120\nM2\n`]){
const rejected=send('PROGRAM_LOAD',{source,path:'renamed.ngc'});assert.equal(rejected.kind,'ERROR');assert.match(rejected.payload.gate_reason,/不匹配/);assert.equal(session.xyzacProgram.source,previous);
}
// Simulate a legacy/recovered taskfile bypassing the loading gate.
session.xyzacProgram.source=`G1 ${other}10 F120\nM2\n`;session.xyzacProgram.executionSource=session.xyzacProgram.source;
for(const kind of ['PROGRAM_RUN','PROGRAM_STEP','PROGRAM_RESUME']){const rejected=send(kind);assert.equal(rejected.kind,'ERROR');assert.match(rejected.payload.gate_reason,/不匹配/);}
session.xyzacProgram.source=previous;session.xyzacProgram.executionSource=previous;
assert.equal(send('PROGRAM_LOAD',{source:'(A and B mentioned in comments)\nG21 G90\nG1 X1 F120\nM2\n',path:'generic.ngc'}).kind,'COMMAND_RESULT');
rows.push({coordinates,load_rejected:true,legacy_execution_rejected:true,generic_allowed:true});
}
console.log(JSON.stringify({report_id:'TRT-PROGRAM-COMPAT-WORKER',status:'verified',rows}));