chore: close wasm status contract work

This commit is contained in:
wangdequan
2026-07-08 09:20:47 -04:00
parent 97732ceb0b
commit e69333972c
69 changed files with 20435 additions and 495 deletions

View File

@@ -46,6 +46,33 @@ function readJson(call) {
}
}
function readMotionSnapshotStruct() {
const bytes = 512;
const ptr = runtime._malloc(bytes);
try {
assert.equal(runtime._lcmot_read_status_snapshot(ptr), 0);
return {
programLine: runtime.getValue(ptr + 8, "i32"),
inPosition: Boolean(runtime.getValue(ptr + 24, "i32")),
paused: Boolean(runtime.getValue(ptr + 28, "i32")),
motionId: runtime.getValue(ptr + 40, "i32"),
queueCapacity: runtime.getValue(ptr + 56, "i32"),
queueFull: Boolean(runtime.getValue(ptr + 60, "i32")),
activeDepth: runtime.getValue(ptr + 64, "i32"),
commandQueueDepth: runtime.getValue(ptr + 68, "i32"),
requestedVel: runtime.getValue(ptr + 80, "double"),
currentVel: runtime.getValue(ptr + 88, "double"),
switchkinsType: runtime.getValue(ptr + 72, "i32"),
axisX: runtime.getValue(ptr + 176, "double"),
axisZ: runtime.getValue(ptr + 192, "double"),
joint0Cmd: runtime.getValue(ptr + 248, "double"),
joint0Fb: runtime.getValue(ptr + 320, "double"),
};
} finally {
runtime._free(ptr);
}
}
function send(command) {
return withCString(JSON.stringify(command), (commandPtr) =>
assert.equal(runtime._lcmot_write_command_json(commandPtr), 0),
@@ -77,6 +104,17 @@ assert.equal(status.axis.z, -3);
assert.equal(hal.pins["motion.program-line"].value, 42);
assert.equal(hal.pins["joint.0.motor-pos-cmd"].value, 1);
assert.equal(hal.pins["joint.0.motor-pos-fb"].value, 1);
let snapshot = readMotionSnapshotStruct();
assert.equal(snapshot.programLine, 42);
assert.equal(snapshot.inPosition, true);
assert.equal(snapshot.motionId, status.motion.motionId);
assert.equal(snapshot.queueCapacity, 64);
assert.equal(snapshot.queueFull, false);
assert.equal(snapshot.commandQueueDepth, 0);
assert.equal(snapshot.axisX, 1);
assert.equal(snapshot.axisZ, -3);
assert.equal(snapshot.joint0Cmd, 1);
assert.equal(snapshot.joint0Fb, 1);
send({ type: "EMCMOT_SET_AOUT", value: 1 });
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
@@ -98,14 +136,20 @@ send({ type: "EMC_TRAJ_PAUSE" });
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
status = readJson((outPtr, outLen) => runtime._lcmot_read_status_json(outPtr, outLen));
assert.equal(status.motion.paused, true);
snapshot = readMotionSnapshotStruct();
assert.equal(snapshot.paused, true);
assert.equal(snapshot.currentVel, 0);
send({ type: "EMC_TRAJ_RESUME" });
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
status = readJson((outPtr, outLen) => runtime._lcmot_read_status_json(outPtr, outLen));
assert.equal(status.motion.paused, false);
snapshot = readMotionSnapshotStruct();
assert.equal(snapshot.paused, false);
console.log("motion_hal_servo_cycle=ok");
console.log("motion_program_line_hal_sync=ok");
console.log("switchkins_type_hal_sync=ok");
console.log("jog_motion_status_sync=ok");
console.log("motion_status_snapshot_struct=ok");
console.log("motion_hal_sync_smoke=ok");

View File

@@ -38,21 +38,6 @@ sdk.initSession({
});
assert.equal(sdk.stageFile("programs/sdk-task-hal.ngc", "G0 X3 Y0 Z-1\n"), 0);
assert.equal(sdk.openProgram("programs/sdk-task-hal.ngc"), 0);
assert.equal(sdk.loadProgramMotionPlan({
programPath: "programs/sdk-task-hal.ngc",
segments: [
{
line: 1,
type: "STRAIGHT_TRAVERSE",
motionClass: "rapid",
startSeconds: 0,
durationSeconds: 0.01,
velocityMmPerMin: 600,
startAxes: { x: 0, y: 0, z: 0, a: 0, b: 0, c: 0 },
endAxes: { x: 3, y: 0, z: -1, a: 0, b: 0, c: 0 },
},
],
}), 0);
prepareHomedAuto();
assert.equal(sdk.sendCommand({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
assert.equal(sdk.runCycles({ taskCycles: 1 }), 0);
@@ -63,15 +48,45 @@ assert.equal(status.taskRuntimeReady, true);
assert.equal(status.motionStatus.motion.programLine, 1);
assert.equal(status.motionStatus.axis.x, 3);
assert.equal(status.halSnapshot.pins["motion.program-line"].value, 1);
assert.equal(status.task.motionPlanLoaded, false);
assert.equal(status.task.planId, 0);
assert.equal(status.emctaskSourceReuse.planReadCount > 0, true);
assert.equal(status.statusSource, "StandaloneEmcStatus");
assert.equal(status.schemaVersion, 1);
assert.equal(status.emcStatus.source, "StandaloneEmcStatus");
assert.equal(status.emcStatus.top.status, status.taskTopLevelStatus);
assert.equal(status.emcStatus.task.status, status.rcsStatus.task);
assert.equal(status.emcStatus.task.state, status.task.state);
assert.equal(status.emcStatus.task.mode, status.task.mode);
assert.equal(status.emcStatus.task.currentLine, status.task.currentLine);
assert.equal(status.emcStatus.task.readLine, status.task.readLine);
assert.equal(status.emcStatus.task.motionLine, status.task.motionLine);
assert.equal(status.emcStatus.motion.status, status.rcsStatus.motion);
assert.equal(status.emcStatus.motion.programLine, status.motionStatus.motion.programLine);
assert.equal(status.emcStatus.motion.traj.queue, status.motionStatus.motion.queueDepth);
assert.equal(status.emcStatus.motion.traj.inpos, status.motionStatus.motion.inPosition);
assert.equal(status.emcStatus.motion.traj.id, status.motionStatus.motion.id);
assert.equal(status.emcStatus.motion.traj.actualPosition.x, status.motionStatus.axis.x);
assert.equal(status.emcStatus.motion.axisByName.x, status.motionStatus.axis.x);
assert.equal(Array.isArray(status.emcStatus.motion.axis), true);
assert.equal(status.emcStatus.motion.axis[0].posFb, status.motionStatus.axis.x);
assert.equal(status.emcStatus.motion.joint[0].motorPosCmd, status.motionStatus.joint0.motorPosCmd);
assert.equal(status.emcStatus.io.status, status.rcsStatus.io);
assert.equal(status.emcStatus.io.tool.supported, false);
assert.equal(status.emcStatus.io.coolant.supported, false);
assert.equal(sdk.sendCommand({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M429" }), 0);
assert.equal(sdk.runCycles({ taskCycles: 1 }), 0);
status = sdk.readStatus();
assert.equal(status.motionStatus.motion.switchkinsType, 0);
assert.equal(status.emccanonSourceReuse.lastMotionOutputCommand, "SET_AUX_OUTPUT_VALUE");
assert.equal(status.emccanonSourceReuse.lastMotionOutputMessage, "EMC_MOTION_SET_AOUT");
assert.equal(status.emccanonSourceReuse.motionOutputTaskintfAoutCount > 0, true);
const events = sdk.readEvents().events;
assert.equal(events.includes("task_plan_run"), true);
assert.equal(events.includes("task_mdi_switchkins:M429"), true);
assert.equal(events.includes("task_canon_motion_output:SET_AUX_OUTPUT_VALUE"), true);
assert.equal(events.includes("task_mdi_canon_motion_output"), true);
sdk.resetSession();
sdk.initSession({
@@ -182,5 +197,7 @@ assert.equal(status.task.nextProgramLine, 6);
console.log("linuxcnc_task_hal_sdk=ok");
console.log("task_hal_sdk_status_snapshot=ok");
console.log("task_hal_feed_timed_motion_plan=ok");
console.log("task_hal_sdk_standalone_emc_status=ok");
console.log("task_hal_sdk_status_json_contract=ok");
console.log("task_hal_timed_motion_plan_compat=ok");
console.log("task_hal_comment_source_line_numbers=ok");

View File

@@ -52,12 +52,6 @@ function send(command) {
);
}
function callJson(functionName, payload) {
return withCString(JSON.stringify(payload), (payloadPtr) =>
runtime[`_${functionName}`](payloadPtr),
);
}
function sendMotion(command) {
return withCString(JSON.stringify(command), (commandPtr) =>
assert.equal(runtime._lcmot_write_command_json(commandPtr), 0, command.type),
@@ -102,51 +96,6 @@ assert.equal(
withCString("programs/task-hal-smoke.ngc", (pathPtr) => runtime._lctask_open_program(pathPtr)),
0,
);
assert.equal(callJson("lctask_load_program_motion_plan_json", {
programPath: "programs/task-hal-smoke.ngc",
segments: [
{
line: 1,
type: "STRAIGHT_FEED",
motionClass: "feed",
startSeconds: 0,
durationSeconds: 0.02,
velocityMmPerMin: 120,
startAxes: { x: 0, y: 0, z: 0, a: 0, b: 0, c: 0 },
endAxes: { x: 1, y: 2, z: -3, a: 10, b: 0, c: 20 },
},
{
line: 2,
type: "STRAIGHT_FEED",
motionClass: "feed",
startSeconds: 0.02,
durationSeconds: 0.02,
velocityMmPerMin: 120,
startAxes: { x: 1, y: 2, z: -3, a: 10, b: 0, c: 20 },
endAxes: { x: 2, y: 3, z: -4, a: 11, b: 0, c: 21 },
},
{
line: 3,
type: "STRAIGHT_FEED",
motionClass: "feed",
startSeconds: 0.04,
durationSeconds: 0.02,
velocityMmPerMin: 120,
startAxes: { x: 2, y: 3, z: -4, a: 11, b: 0, c: 21 },
endAxes: { x: 3, y: 4, z: -5, a: 12, b: 0, c: 22 },
},
{
line: 4,
type: "STRAIGHT_FEED",
motionClass: "feed",
startSeconds: 0.06,
durationSeconds: 0.02,
velocityMmPerMin: 120,
startAxes: { x: 3, y: 4, z: -5, a: 12, b: 0, c: 22 },
endAxes: { x: 4, y: 5, z: -6, a: 13, b: 0, c: 23 },
},
],
}), 0);
send({ type: "EMC_TASK_SET_STATE", state: "ON" });
send({ type: "EMC_JOINT_HOME", joint: -1 });
@@ -162,19 +111,166 @@ assert.equal(snapshot.taskStatusFromLinuxCncRuntime, true);
assert.equal(snapshot.taskCommandsDriveMotionRuntime, true);
assert.equal(snapshot.nativeTaskReady, false);
assert.equal(snapshot.nativeHalSyncReady, false);
assert.equal(snapshot.fullLinuxCncProgramExecutionReady, false);
assert.equal(snapshot.taskTopLevelStatus, "EXEC");
assert.equal(snapshot.rcsStatus.top, "EXEC");
assert.equal(snapshot.rcsStatus.task, "EXEC");
assert.equal(snapshot.rcsStatus.motion, "DONE");
assert.equal(snapshot.rcsStatus.io, "DONE");
assert.equal(snapshot.statusSource, "StandaloneEmcStatus");
assert.equal(snapshot.schemaVersion, 1);
assert.equal(snapshot.emcStatus.source, "StandaloneEmcStatus");
assert.equal(snapshot.emcStatus.valid, true);
assert.equal(snapshot.emcStatus.top.status, snapshot.taskTopLevelStatus);
assert.equal(snapshot.emcStatus.task.status, snapshot.rcsStatus.task);
assert.equal(snapshot.emcStatus.task.state, snapshot.task.state);
assert.equal(snapshot.emcStatus.task.mode, snapshot.task.mode);
assert.equal(snapshot.emcStatus.task.execState, snapshot.task.execState);
assert.equal(snapshot.emcStatus.task.currentLine, snapshot.task.currentLine);
assert.equal(snapshot.emcStatus.task.readLine, snapshot.task.readLine);
assert.equal(snapshot.emcStatus.task.motionLine, snapshot.task.motionLine);
assert.equal(snapshot.emcStatus.task.callLevel, snapshot.task.callLevel);
assert.equal(snapshot.emcStatus.task.pendingCommandDepth, snapshot.task.pendingCommandDepth);
assert.equal(snapshot.emcStatus.task.pendingExecuteMotionDepth, snapshot.task.pendingExecuteMotionDepth);
assert.equal(snapshot.emcStatus.motion.valid, true);
assert.equal(snapshot.emcStatus.motion.status, snapshot.rcsStatus.motion);
assert.equal(snapshot.emcStatus.motion.programLine, snapshot.motionStatus.motion.programLine);
assert.equal(snapshot.emcStatus.motion.motionId, snapshot.motionStatus.motion.motionId);
assert.equal(snapshot.emcStatus.motion.queueDepth, snapshot.motionStatus.queueDepth);
assert.equal(snapshot.emcStatus.motion.traj.queue, snapshot.motionStatus.motion.queueDepth);
assert.equal(snapshot.emcStatus.motion.traj.inpos, snapshot.motionStatus.motion.inPosition);
assert.equal(snapshot.emcStatus.motion.traj.id, snapshot.motionStatus.motion.id);
assert.equal(snapshot.emcStatus.motion.traj.activeQueue, snapshot.motionStatus.activeDepth);
assert.equal(snapshot.emcStatus.motion.traj.queueFull, snapshot.motionStatus.motion.queueFull);
assert.equal(snapshot.emcStatus.motion.traj.paused, snapshot.motionStatus.motion.paused);
assert.equal(snapshot.emcStatus.motion.traj.singleStepping, snapshot.motionStatus.motion.stepping);
assert.equal(snapshot.emcStatus.motion.traj.currentVel, snapshot.motionStatus.motion.currentVel);
assert.equal(snapshot.emcStatus.motion.traj.actualPosition.x, snapshot.motionStatus.axis.x);
assert.equal(snapshot.emcStatus.motion.axisByName.x, snapshot.motionStatus.axis.x);
assert.equal(Array.isArray(snapshot.emcStatus.motion.axis), true);
assert.equal(Array.isArray(snapshot.emcStatus.motion.joint), true);
assert.equal(snapshot.emcStatus.motion.axis.length >= 5, true);
assert.equal(snapshot.emcStatus.motion.axis[0].posFb, snapshot.motionStatus.axis.x);
assert.equal(snapshot.emcStatus.motion.joint[0].motorPosCmd, snapshot.motionStatus.joint0.motorPosCmd);
assert.equal(snapshot.emcStatus.motion.joint[0].motorPosFb, snapshot.motionStatus.joint0.motorPosFb);
assert.equal(snapshot.emcStatus.io.status, snapshot.rcsStatus.io);
assert.equal(snapshot.emcStatus.io.error, false);
assert.equal(snapshot.emcStatus.io.fault, false);
assert.equal(snapshot.emcStatus.io.reason, "");
assert.equal(typeof snapshot.emcStatus.io.aux.estop, "boolean");
assert.equal(snapshot.emcStatus.io.tool.supported, false);
assert.equal(snapshot.emcStatus.io.coolant.supported, false);
assert.equal(snapshot.emctaskSourceReuse.emctaskSubsetCompiled, true);
assert.equal(snapshot.emctaskSourceReuse.sourcePath, "src/emc/task/emctask.cc");
assert.equal(
snapshot.emctaskSourceReuse.anchors,
"emcTaskAbort,emcTaskSetMode,emcTaskSetState,determineMode,determineState,emcTaskUpdate,emcTaskPlanSetWait,emcTaskPlanIsWait,emcTaskPlanClearWait,emcTaskPlanSynch,emcTaskPlanOpen,emcTaskPlanClose,emcTaskPlanReset,emcTaskPlanRead,emcTaskPlanExecute,emcTaskPlanLine,emcTaskPlanLevel,emcTaskPlanCommand",
);
assert.equal(snapshot.emctaskSourceReuse.updateValid, true);
assert.equal(snapshot.emctaskSourceReuse.derivedMode, "AUTO");
assert.equal(snapshot.emctaskSourceReuse.derivedState, "ON");
assert.equal(snapshot.emctaskSourceReuse.motionLine > 0, true);
assert.equal(snapshot.emctaskSourceReuse.stateModeIssueCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.abortIssueCount > 0, true);
assert.equal(
snapshot.emctaskSourceReuse.stateModeAnchors,
"emcTaskAbort,emcTaskSetMode,emcTaskSetState,emcTaskPlanSynch,emcTaskPlanClose,emcTaskPlanReset",
);
assert.equal(snapshot.emctaskSourceReuse.snapshotUpdateCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.updateInputSource, "motionSnapshot,ioSnapshot");
assert.equal(snapshot.task.taskPlanOpen, true);
assert.equal(snapshot.emctaskSourceReuse.planIssueCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planSynchCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planOpenCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planWaitFlag, false);
assert.equal(snapshot.emctaskSourceReuse.planOpenFlag, true);
assert.equal(
snapshot.emctaskSourceReuse.planAnchors,
"emcTaskPlanSetWait,emcTaskPlanIsWait,emcTaskPlanClearWait,emcTaskPlanSynch,emcTaskPlanOpen,emcTaskPlanClose,emcTaskPlanReset",
);
assert.equal(snapshot.taskintfSourceReuse.taskintfSubsetCompiled, true);
assert.equal(snapshot.taskintfSourceReuse.sourcePath, "src/emc/task/taskintf.cc");
assert.equal(
snapshot.taskintfSourceReuse.anchors,
"emcTrajSetMotionId,emcTrajEnable,emcTrajDisable,emcTrajAbort,emcTrajPause,emcTrajStep,emcTrajResume,emcTrajLinearMove,emcJogIncr,emcJointHome,emcJointUnhome,emcMotionSetAout",
);
assert.equal(snapshot.taskintfSourceReuse.issueCount > 0, true);
assert.equal(snapshot.taskintfSourceReuse.trajControlIssueCount > 0, true);
assert.equal(
snapshot.taskintfSourceReuse.trajControlAnchors,
"emcTrajSetMotionId,emcTrajEnable,emcTrajDisable,emcTrajAbort,emcTrajPause,emcTrajStep,emcTrajResume",
);
assert.equal(snapshot.taskintfSourceReuse.linearMoveIssueCount > 0, true);
assert.equal(snapshot.taskintfSourceReuse.linearMoveStructuredIssueCount > 0, true);
assert.equal(
snapshot.taskintfSourceReuse.linearMoveAnchors,
"emcTrajLinearMove,EMCMOT_SET_LINE,usrmotWriteEmcmotCommand",
);
assert.equal(snapshot.taskintfSourceReuse.jogHomeSwitchkinsIssueCount > 0, true);
assert.equal(snapshot.taskintfSourceReuse.jogHomeSwitchkinsStructuredIssueCount > 0, true);
assert.equal(
snapshot.taskintfSourceReuse.jogHomeSwitchkinsAnchors,
"emcJogIncr,emcJointHome,emcJointUnhome,emcMotionSetAout,EMCMOT_JOG_INCR,EMCMOT_JOINT_HOME,EMCMOT_JOINT_UNHOME,EMCMOT_SET_AOUT,usrmotWriteEmcmotCommand",
);
assert.equal(snapshot.taskintfMotionBridge.motionBridgeCompiled, true);
assert.equal(snapshot.taskintfMotionBridge.sourcePath, "src/emc/task/taskintf.cc");
assert.equal(
snapshot.taskintfMotionBridge.anchors,
"emcMotionInit,emcMotionUpdate,emcMotionAbort,usrmotReadEmcmotStatus,usrmotReadEmcmotConfig,usrmotReadEmcmotError",
);
assert.equal(snapshot.taskintfMotionBridge.initCount, 1);
assert.equal(snapshot.taskintfMotionBridge.updateCount > 0, true);
assert.equal(snapshot.taskintfMotionBridge.configValid, true);
assert.equal(snapshot.taskintfMotionBridge.configNum, 1);
assert.equal(snapshot.taskintfMotionBridge.axes, 5);
assert.equal(snapshot.taskintfMotionBridge.joints, 5);
assert.equal(snapshot.taskintfMotionBridge.queueCapacity, 64);
assert.equal(snapshot.emccanonSourceReuse.emccanonSubsetCompiled, true);
assert.equal(snapshot.emccanonSourceReuse.sourcePath, "src/emc/task/emccanon.cc");
assert.equal(
snapshot.emccanonSourceReuse.anchors,
"INIT_CANON,ON_RESET,FINISH,USE_LENGTH_UNITS,GET_EXTERNAL_LENGTH_UNITS,GET_EXTERNAL_ANGLE_UNITS,GET_EXTERNAL_POSITION,GET_EXTERNAL_POSITION_X,GET_EXTERNAL_POSITION_Y,GET_EXTERNAL_POSITION_Z,GET_EXTERNAL_POSITION_A,GET_EXTERNAL_POSITION_B,GET_EXTERNAL_POSITION_C,generate_fast_move,generate_move,STRAIGHT_TRAVERSE,STRAIGHT_FEED,DWELL,SET_MOTION_CONTROL_MODE,SET_SPINDLE_SPEED,START_SPINDLE_CLOCKWISE,START_SPINDLE_COUNTERCLOCKWISE,STOP_SPINDLE_TURNING,SELECT_TOOL,CHANGE_TOOL,CHANGE_TOOL_NUMBER,RELOAD_TOOLDATA,SET_MOTION_OUTPUT_BIT,CLEAR_MOTION_OUTPUT_BIT,SET_AUX_OUTPUT_BIT,CLEAR_AUX_OUTPUT_BIT,SET_MOTION_OUTPUT_VALUE,SET_AUX_OUTPUT_VALUE,WAIT",
);
assert.equal(snapshot.emccanonSourceReuse.issueCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.initCount, 1);
assert.equal(snapshot.emccanonSourceReuse.finishCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.unitSetCount, 1);
assert.equal(snapshot.emccanonSourceReuse.positionGetCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.endpointUpdateCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lengthUnits, 1);
assert.equal(snapshot.emccanonSourceReuse.externalLengthUnits, 1);
assert.equal(snapshot.emccanonSourceReuse.externalAngleUnits, 1);
assert.equal(typeof snapshot.emccanonSourceReuse.endpoint.x, "number");
assert.equal(
snapshot.emccanonSourceReuse.initFinishUnitAnchors,
"INIT_CANON,ON_RESET,FINISH,USE_LENGTH_UNITS,GET_EXTERNAL_LENGTH_UNITS,GET_EXTERNAL_ANGLE_UNITS,GET_EXTERNAL_POSITION,GET_EXTERNAL_POSITION_X,GET_EXTERNAL_POSITION_Y,GET_EXTERNAL_POSITION_Z,GET_EXTERNAL_POSITION_A,GET_EXTERNAL_POSITION_B,GET_EXTERNAL_POSITION_C",
);
assert.equal(snapshot.emccanonSourceReuse.straightTraverseCount + snapshot.emccanonSourceReuse.straightFeedCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.linearMoveAppendCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastLinearMoveLine > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastInterpListCommand, "EMC_TRAJ_LINEAR_MOVE");
assert.equal(
snapshot.emccanonSourceReuse.straightMotionAnchors,
"generate_fast_move,generate_move,STRAIGHT_TRAVERSE,STRAIGHT_FEED,EMC_TRAJ_LINEAR_MOVE,interp_list",
);
assert.equal(snapshot.task.state, "ON");
assert.equal(snapshot.task.mode, "AUTO");
assert.equal(snapshot.task.openedLineCount, 4);
assert.equal(snapshot.task.programOpen, true);
assert.equal(snapshot.task.motionPlanLoaded, true);
assert.equal(snapshot.task.planId > 0, true);
assert.equal(snapshot.task.motionPlanLoaded, false);
assert.equal(snapshot.task.planId, 0);
assert.equal(snapshot.task.allHomed, true);
assert.equal(Array.isArray(snapshot.task.homed), true);
assert.equal(snapshot.task.homed.every(Boolean), true);
assert.equal(snapshot.task.nextProgramLine >= 1, true);
assert.equal(snapshot.task.interpState, "READING");
assert.equal(snapshot.task.interpResumeState, "READING");
assert.equal(snapshot.emctaskSourceReuse.planReadCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planExecuteCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planCommandCount > 0, true);
assert.equal(snapshot.motionStatus.motion.programLine >= 1, true);
assert.equal(snapshot.motionStatus.motion.enabled, true);
assert.equal(snapshot.motionStatus.motion.nextMotionId >= 1, true);
assert.equal(snapshot.motionStatus.motion.queueDepth >= 0, true);
assert.equal(snapshot.motionStatus.motion.id > 0, true);
assert.equal(snapshot.motionStatus.motion.currentVel > 0, true);
@@ -183,8 +279,13 @@ assert.equal(snapshot.halSnapshot.pins["joint.0.motor-pos-cmd"].value, snapshot.
send({ type: "EMC_TASK_PLAN_PAUSE" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(snapshot.task.interpState, "READING");
assert.equal(snapshot.motionStatus.motion.paused, false);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.interpState, "PAUSED");
assert.equal(snapshot.task.interpResumeState, "READING");
assert.equal(["READING", "IDLE"].includes(snapshot.task.interpResumeState), true);
assert.equal(snapshot.task.taskPaused, true);
assert.equal(snapshot.task.singleStepping, false);
assert.equal(snapshot.motionStatus.motion.paused, true);
@@ -198,7 +299,7 @@ const pausedAxis = { ...snapshot.motionStatus.axis };
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 20), 0);
snapshot = status();
assert.equal(snapshot.task.interpState, "PAUSED");
assert.equal(snapshot.task.interpResumeState, "READING");
assert.equal(["READING", "IDLE"].includes(snapshot.task.interpResumeState), true);
assert.equal(snapshot.task.nextProgramLine, pausedTaskLine);
assert.equal(snapshot.motionStatus.motion.paused, true);
assert.equal(snapshot.motionStatus.motion.programLine, pausedMotionLine);
@@ -207,28 +308,38 @@ assert.equal(snapshot.motionStatus.commandQueueDepth, pausedQueueDepth);
assert.deepEqual(snapshot.motionStatus.axis, pausedAxis);
send({ type: "EMC_TASK_PLAN_RESUME" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(snapshot.motionStatus.motion.paused, true);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.interpState, "READING");
assert.equal(snapshot.task.interpResumeState, "READING");
assert.equal(["READING", "IDLE"].includes(snapshot.task.interpState), true);
assert.equal(["READING", "IDLE"].includes(snapshot.task.interpResumeState), true);
assert.equal(snapshot.task.taskPaused, false);
assert.equal(snapshot.motionStatus.motion.paused, false);
assert.equal(snapshot.motionStatus.motion.programLine >= pausedMotionLine, true);
const motionIdBeforeStep = snapshot.motionStatus.motion.motionId;
send({ type: "EMC_TASK_PLAN_PAUSE" });
send({ type: "EMC_TASK_PLAN_STEP" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 2);
assert.equal(snapshot.motionStatus.motion.motionId, motionIdBeforeStep);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.interpState, "PAUSED");
assert.equal(snapshot.task.interpResumeState, "READING");
assert.equal(["READING", "IDLE"].includes(snapshot.task.interpResumeState), true);
assert.equal(snapshot.task.taskPaused, true);
assert.equal(snapshot.task.singleStepping, false);
assert.equal(snapshot.motionStatus.motion.paused, true);
assert.equal(snapshot.motionStatus.motion.stepping, false);
assert.equal(typeof snapshot.motionStatus.motion.stepping, "boolean");
assert.equal(snapshot.motionStatus.motion.programLine >= pausedMotionLine, true);
assert.equal(snapshot.motionStatus.motion.motionId > pausedMotionId, true);
send({ type: "EMC_TASK_PLAN_RESUME" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(snapshot.motionStatus.motion.paused, true);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.paused, false);
@@ -263,32 +374,346 @@ assert.equal(motionSnapshot.motion.programLine, 12);
assert.equal(motionSnapshot.commandQueueDepth, 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M428" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(snapshot.task.pendingExecuteMotionDepth, 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 0);
assert.equal(snapshot.task.pendingExecuteMotionDepth, 0);
assert.equal(snapshot.motionStatus.motion.switchkinsType, 1);
assert.equal(snapshot.task.execState, "DONE");
assert.equal(snapshot.halSnapshot.pins["motion.switchkins-type"].value, 1);
assert.equal(snapshot.taskintfSourceReuse.jogHomeSwitchkinsStructuredIssueCount >= 2, true);
assert.equal(snapshot.emccanonSourceReuse.motionOutputCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.motionOutputAppendCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.motionOutputTaskintfAoutCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputCommand, "SET_AUX_OUTPUT_VALUE");
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputMessage, "EMC_MOTION_SET_AOUT");
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputIndex, 0);
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputValue, 1);
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputNow, 1);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M429" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.switchkinsType, 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M430" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.switchkinsType, 2);
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputCommand, "SET_AUX_OUTPUT_VALUE");
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputValue, 2);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M62 P1" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M63 P1" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M64 P2" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M65 P2" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M67 E3 Q1.25" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M68 E3 Q2.5" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M66 P4 L3 Q0.5" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.emccanonSourceReuse.motionOutputCount >= 10, true);
assert.equal(snapshot.emccanonSourceReuse.motionOutputAppendCount >= 10, true);
assert.equal(snapshot.emccanonSourceReuse.waitInputCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputCommand, "WAIT");
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputMessage, "EMC_AUX_INPUT_WAIT");
assert.equal(snapshot.emccanonSourceReuse.lastMotionOutputIndex, 4);
assert.equal(snapshot.emccanonSourceReuse.lastWaitInputType, "DIGITAL_INPUT");
assert.equal(snapshot.emccanonSourceReuse.lastWaitType, 3);
assert.equal(snapshot.emccanonSourceReuse.lastWaitTimeout, 0.5);
assert.equal(
snapshot.emccanonSourceReuse.motionOutputAnchors,
"SET_MOTION_OUTPUT_BIT,CLEAR_MOTION_OUTPUT_BIT,SET_AUX_OUTPUT_BIT,CLEAR_AUX_OUTPUT_BIT,SET_MOTION_OUTPUT_VALUE,SET_AUX_OUTPUT_VALUE,WAIT,EMC_MOTION_SET_DOUT,EMC_MOTION_SET_AOUT,EMC_AUX_INPUT_WAIT,interp_list",
);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "G64 P0.01" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "G4 P0.02" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.emccanonSourceReuse.dwellCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.delayAppendCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastDwellSeconds, 0.02);
assert.equal(snapshot.emccanonSourceReuse.pathControlCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.termCondAppendCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastPathMode, "CONTINUOUS");
assert.equal(snapshot.emccanonSourceReuse.lastTermCondition, "BLEND");
assert.equal(snapshot.emccanonSourceReuse.lastPathTolerance, 0.01);
assert.equal(
snapshot.emccanonSourceReuse.dwellPathControlAnchors,
"DWELL,EMC_TRAJ_DELAY,SET_MOTION_CONTROL_MODE,EMC_TRAJ_SET_TERM_COND,interp_list",
);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "S1200 M3" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M5" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "T7 M6" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M61 Q8" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.emccanonSourceReuse.spindleCommandCount >= 3, true);
assert.equal(snapshot.emccanonSourceReuse.spindleAppendCount >= 3, true);
assert.equal(snapshot.emccanonSourceReuse.lastSpindleCommand, "STOP_SPINDLE_TURNING");
assert.equal(snapshot.emccanonSourceReuse.lastSpindle, 0);
assert.equal(snapshot.emccanonSourceReuse.lastSpindleSpeed, 1200);
assert.equal(snapshot.emccanonSourceReuse.toolCommandCount >= 3, true);
assert.equal(snapshot.emccanonSourceReuse.toolAppendCount >= 3, true);
assert.equal(snapshot.emccanonSourceReuse.lastToolCommand, "CHANGE_TOOL_NUMBER");
assert.equal(snapshot.emccanonSourceReuse.lastTool, 8);
assert.equal(
snapshot.emccanonSourceReuse.spindleToolAnchors,
"SET_SPINDLE_SPEED,START_SPINDLE_CLOCKWISE,START_SPINDLE_COUNTERCLOCKWISE,STOP_SPINDLE_TURNING,EMC_SPINDLE_SPEED,EMC_SPINDLE_ON,EMC_SPINDLE_OFF,SELECT_TOOL,CHANGE_TOOL,CHANGE_TOOL_NUMBER,RELOAD_TOOLDATA,EMC_TOOL_PREPARE,EMC_TOOL_LOAD,EMC_TOOL_SET_NUMBER,EMC_TOOL_LOAD_TOOL_TABLE,interp_list",
);
const xBeforeJog = snapshot.motionStatus.axis.x;
send({ type: "EMC_JOG_INCR", axis: "X", distance: 0.25, velocity: 60 });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(snapshot.motionStatus.axis.x, xBeforeJog);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 0);
assert.equal(snapshot.task.pendingExecuteMotionDepth, 0);
assert.equal(snapshot.motionStatus.axis.x, xBeforeJog + 0.25);
assert.equal(snapshot.motionStatus.motion.teleopMode, 1);
assert.equal(snapshot.task.execState, "DONE");
send({ type: "EMC_TASK_ABORT" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "DONE");
assert.equal(snapshot.motionStatus.motion.aborted, true);
assert.equal(snapshot.taskintfMotionBridge.abortCount > 0, true);
const eventLog = events();
assert.equal(eventLog.includes("task_session_motion_init"), true);
assert.equal(eventLog.includes("task_plan_run"), true);
assert.equal(eventLog.includes("task_plan_pause"), true);
assert.equal(eventLog.includes("task_plan_resume"), true);
assert.equal(eventLog.includes("task_mdi_switchkins:M428"), true);
assert.equal(eventLog.includes("task_canon_motion_output:SET_AUX_OUTPUT_VALUE"), true);
assert.equal(eventLog.includes("task_mdi_canon_motion_output"), true);
assert.equal(eventLog.includes("task_jog_incr"), true);
assert.equal(eventLog.includes("task_abort"), true);
assert.equal(eventLog.includes("task_execute_motion_issue:1"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
const idleTaskSnapshot = status();
sendMotion({ type: "EMC_TRAJ_LINEAR_MOVE", line: 20, x: 20, y: 0, z: 0, velocity: 1 });
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.motion.programLine, 20);
assert.equal(runtime._lcmot_write_linear_move(21, 1, 21, 21, 0, 0, 0, 0, 0, 1, 1, 0, 0), 0);
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.motion.programLine, 21);
assert.equal(motionSnapshot.motion.motionId, 21);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.programLine, idleTaskSnapshot.motionStatus.motion.programLine);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.programLine, 21);
assert.equal(runtime._lcmot_write_aout(0, 2, 2, 1), 0);
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.motion.switchkinsType, 2);
assert.equal(runtime._lcmot_write_jog_incr(0, -1, 0.5, 60, 22), 0);
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.motion.motionId, 22);
assert.equal(motionSnapshot.motion.teleopMode, 1);
assert.equal(runtime._lcmot_write_joint_home(-1), 0);
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.axis.x, 0);
assert.equal(runtime._lcmot_write_joint_unhome(-1), 0);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
sendMotion({ type: "EMCMOT_PAUSE" });
for (let i = 0; i < 64; i += 1) {
sendMotion({ type: "EMC_TRAJ_LINEAR_MOVE", line: 100 + i, x: 100 + i, y: 0, z: 0, velocity: 1 });
}
motionSnapshot = motionStatus();
assert.equal(motionSnapshot.commandQueueDepth, 64);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.motionStatus.motion.queueFull, true);
send({ type: "EMC_JOG_INCR", axis: "X", distance: 0.25, velocity: 60 });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "WAITING_FOR_MOTION_QUEUE");
assert.equal(snapshot.task.pendingExecuteMotionDepth, 1);
assert.equal(snapshot.motionStatus.motion.queueFull, true);
sendMotion({ type: "EMCMOT_RESUME" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "WAITING_FOR_MOTION");
assert.equal(snapshot.task.pendingExecuteMotionDepth, 1);
assert.equal(snapshot.motionStatus.motion.queueFull, false);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 50), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "DONE");
assert.equal(snapshot.task.status, "DONE");
assert.equal(snapshot.taskTopLevelStatus, "DONE");
assert.equal(snapshot.rcsStatus.top, "DONE");
assert.equal(snapshot.rcsStatus.task, "DONE");
assert.equal(snapshot.rcsStatus.motion, "DONE");
assert.equal(snapshot.rcsStatus.io, "DONE");
assert.equal(snapshot.task.pendingExecuteMotionDepth, 0);
assert.equal(snapshot.motionStatus.commandQueueDepth, 0);
const queueEvents = events();
assert.equal(queueEvents.includes("task_waiting_for_motion_queue"), true);
assert.equal(queueEvents.includes("task_motion_queue_available"), true);
assert.equal(queueEvents.includes("task_motion_wait_done"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
sendMotion({ type: "EMCMOT_ABORT" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "ERROR");
assert.equal(snapshot.task.errorText, "MOTION_ABORTED");
assert.equal(snapshot.taskTopLevelStatus, "ERROR");
assert.equal(snapshot.rcsStatus.top, "ERROR");
assert.equal(snapshot.rcsStatus.task, "ERROR");
assert.equal(snapshot.rcsStatus.motion, "ERROR");
assert.equal(snapshot.rcsStatus.io, "DONE");
assert.equal(snapshot.motionStatus.motion.aborted, true);
assert.equal(snapshot.taskintfMotionBridge.lastErrorText, "MOTION_ABORTED");
const motionErrorEvents = events();
assert.equal(motionErrorEvents.includes("task_motion_error:MOTION_ABORTED"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
sendMotion({ type: "EMCMOT_INJECT_ERROR" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "ERROR");
assert.equal(snapshot.task.errorText, "MOTION_ERROR");
assert.equal(snapshot.taskTopLevelStatus, "ERROR");
assert.equal(snapshot.rcsStatus.top, "ERROR");
assert.equal(snapshot.rcsStatus.task, "ERROR");
assert.equal(snapshot.rcsStatus.motion, "ERROR");
assert.equal(snapshot.rcsStatus.io, "DONE");
assert.equal(snapshot.motionStatus.motion.status, 2);
assert.equal(snapshot.motionStatus.motion.motionError, true);
assert.equal(snapshot.taskintfMotionBridge.lastErrorText, "MOTION_ERROR");
const injectedMotionErrorEvents = events();
assert.equal(injectedMotionErrorEvents.includes("task_motion_error:MOTION_ERROR"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
sendMotion({ type: "EMCMOT_INJECT_SOFT_LIMIT", axis: "X" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "ERROR");
assert.equal(snapshot.task.errorText, "MOTION_SOFT_LIMIT");
assert.equal(snapshot.taskTopLevelStatus, "ERROR");
assert.equal(snapshot.rcsStatus.top, "ERROR");
assert.equal(snapshot.rcsStatus.task, "ERROR");
assert.equal(snapshot.rcsStatus.motion, "ERROR");
assert.equal(snapshot.rcsStatus.io, "DONE");
assert.equal(snapshot.motionStatus.motion.status, 2);
assert.equal(snapshot.motionStatus.motion.onSoftLimit, true);
assert.equal(snapshot.taskintfMotionBridge.lastErrorText, "MOTION_SOFT_LIMIT");
const softLimitEvents = events();
assert.equal(softLimitEvents.includes("task_motion_error:MOTION_SOFT_LIMIT"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
send({ type: "EMC_IO_INJECT_ERROR" });
snapshot = status();
assert.equal(snapshot.task.pendingCommandDepth, 1);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.task.execState, "ERROR");
assert.equal(snapshot.task.errorText, "IO_ERROR");
assert.equal(snapshot.taskTopLevelStatus, "ERROR");
assert.equal(snapshot.rcsStatus.top, "ERROR");
assert.equal(snapshot.rcsStatus.task, "ERROR");
assert.equal(snapshot.rcsStatus.motion, "DONE");
assert.equal(snapshot.rcsStatus.io, "ERROR");
const ioErrorEvents = events();
assert.equal(ioErrorEvents.includes("task_io_error_injected"), true);
assert.equal(ioErrorEvents.includes("task_io_error:IO_ERROR"), true);
assert.equal(runtime._lctask_reset_session(), 0);
assert.equal(
withCString(JSON.stringify(session), (sessionPtr) => runtime._lctask_init_session(sessionPtr)),
0,
);
assert.equal(
withCString("programs/no-json-plan.ngc", (pathPtr) =>
withCString("G1 X0.01 F6000\n", (textPtr) => runtime._lctask_stage_file(pathPtr, textPtr)),
),
0,
);
assert.equal(
withCString("programs/no-json-plan.ngc", (pathPtr) => runtime._lctask_open_program(pathPtr)),
0,
);
send({ type: "EMC_TASK_SET_STATE", state: "ON" });
send({ type: "EMC_JOINT_HOME", joint: -1 });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
send({ type: "EMC_TASK_SET_MODE", mode: "AUTO" });
send({ type: "EMC_TASK_PLAN_RUN", line: 0 });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 6), 0);
snapshot = status();
assert.equal(snapshot.task.motionPlanLoaded, false);
assert.equal(snapshot.task.execState, "DONE");
assert.equal(snapshot.task.nextProgramLine >= 1, true);
assert.equal(snapshot.emctaskSourceReuse.planReadCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planExecuteCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planLineCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planLevelCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planCommandCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.interpListAppendCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planWaitSetCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planWaitClearCount > 0, true);
assert.equal(snapshot.emctaskSourceReuse.planWaitFlag, false);
assert.equal(snapshot.emctaskSourceReuse.planLastLine, 1);
assert.equal(snapshot.emctaskSourceReuse.planLastCommand, "G1 X0.01 F6000");
assert.equal(
snapshot.emctaskSourceReuse.planReadExecuteAnchors,
"emcTaskPlanRead,emcTaskPlanExecute,emcTaskPlanLine,emcTaskPlanLevel,emcTaskPlanCommand,interp_list",
);
assert.equal(snapshot.taskintfSourceReuse.linearMoveIssueCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.straightFeedCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.linearMoveAppendCount > 0, true);
assert.equal(snapshot.emccanonSourceReuse.lastLinearMoveType, "STRAIGHT_FEED");
assert.equal(snapshot.emccanonSourceReuse.lastInterpListCommand, "EMC_TRAJ_LINEAR_MOVE");
send({ type: "EMC_TASK_PLAN_RESET" });
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
snapshot = status();
assert.equal(snapshot.emccanonSourceReuse.resetCount > 0, true);
console.log("linuxcnc_task_runtime_smoke=ok");
console.log("task_status_from_linuxcnc_runtime=ok");
@@ -297,3 +722,29 @@ console.log("mdi_jog_task_motion_hal_sync=ok");
console.log("pause_freezes_motion_queue=ok");
console.log("resume_restores_interp_resume_state=ok");
console.log("step_returns_to_paused=ok");
console.log("task_status_updates_from_cycle_snapshot=ok");
console.log("mdi_jog_home_motion_issue_from_execute=ok");
console.log("task_waits_on_motion_snapshot_queue=ok");
console.log("motion_abort_drives_task_error=ok");
console.log("motion_error_drives_task_error=ok");
console.log("motion_soft_limit_drives_task_error=ok");
console.log("io_error_drives_task_error=ok");
console.log("task_top_level_rcs_status_aggregation=ok");
console.log("standalone_emc_status_container=ok");
console.log("task_status_json_contract=ok");
console.log("pause_resume_step_motion_issue_from_execute=ok");
console.log("task_hal_readiness_status_contract=ok");
console.log("emctask_subset_source_reuse_status=ok");
console.log("emctask_plan_read_execute_status=ok");
console.log("taskintf_subset_source_reuse_status=ok");
console.log("taskintf_motion_bridge_status=ok");
console.log("taskintf_traj_control_status=ok");
console.log("taskintf_linear_move_status=ok");
console.log("taskintf_jog_home_switchkins_status=ok");
console.log("emccanon_subset_source_reuse_status=ok");
console.log("emccanon_init_finish_unit_status=ok");
console.log("emccanon_straight_motion_status=ok");
console.log("emccanon_dwell_path_control_status=ok");
console.log("emccanon_spindle_tool_status=ok");
console.log("emccanon_motion_output_status=ok");
console.log("task_hal_no_json_main_path_status=ok");

View File

@@ -58,7 +58,7 @@ function reset(session = {}) {
}), 0);
}
function stageAndOpenProgram({ loadPlan = true } = {}) {
function stageAndOpenProgram({ loadPlan = false } = {}) {
assert.equal(
withCString("programs/matrix.ngc", (pathPtr) =>
withCString("G1 X1 F60\nG1 X2 F60\n", (textPtr) => runtime._lctask_stage_file(pathPtr, textPtr)),
@@ -99,14 +99,63 @@ function commandRc(command) {
return callJson("lctask_send_command_json", command);
}
function runTaskCycles(cycles = 1) {
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, cycles), 0);
}
function assertStandaloneEmcStatus(status) {
assert.equal(status.statusSource, "StandaloneEmcStatus");
assert.equal(status.schemaVersion, 1);
assert.equal(status.emcStatus.source, "StandaloneEmcStatus");
assert.equal(status.emcStatus.valid, true);
assert.equal(status.emcStatus.top.status, status.taskTopLevelStatus);
assert.equal(status.emcStatus.task.status, status.rcsStatus.task);
assert.equal(status.emcStatus.task.state, status.task.state);
assert.equal(status.emcStatus.task.mode, status.task.mode);
assert.equal(status.emcStatus.task.currentLine, status.task.currentLine);
assert.equal(status.emcStatus.task.readLine, status.task.readLine);
assert.equal(status.emcStatus.task.motionLine, status.task.motionLine);
assert.equal(status.emcStatus.task.pendingCommandDepth, status.task.pendingCommandDepth);
assert.equal(status.emcStatus.motion.status, status.rcsStatus.motion);
assert.equal(status.emcStatus.motion.valid, true);
assert.equal(status.emcStatus.motion.programLine, status.motionStatus.motion.programLine);
assert.equal(status.emcStatus.motion.queueDepth, status.motionStatus.queueDepth);
assert.equal(status.emcStatus.motion.traj.queue, status.motionStatus.motion.queueDepth);
assert.equal(status.emcStatus.motion.traj.inpos, status.motionStatus.motion.inPosition);
assert.equal(status.emcStatus.motion.traj.id, status.motionStatus.motion.id);
assert.equal(Array.isArray(status.emcStatus.motion.axis), true);
assert.equal(Array.isArray(status.emcStatus.motion.joint), true);
assert.equal(status.emcStatus.io.status, status.rcsStatus.io);
assert.equal(typeof status.emcStatus.io.aux.estop, "boolean");
assert.equal(status.emcStatus.io.tool.supported, false);
assert.equal(status.emcStatus.io.coolant.supported, false);
}
function assertRejected(name, setup, expectedError) {
reset();
setup();
const rc = commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 });
assert.notEqual(rc, 0, name);
assert.equal(rc, 0, name);
runTaskCycles();
assert.equal(readStatus().task.errorText, expectedError, name);
}
reset();
let queuedStatus = readStatus();
assertStandaloneEmcStatus(queuedStatus);
assert.equal(queuedStatus.task.state, "ESTOP_RESET");
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
queuedStatus = readStatus();
assert.equal(queuedStatus.task.state, "ESTOP_RESET");
assert.equal(queuedStatus.task.pendingCommandDepth, 1);
assert.equal(commandRc({ type: "UNSUPPORTED_HOST_COMMAND" }), -1);
queuedStatus = readStatus();
assert.equal(queuedStatus.task.pendingCommandDepth, 1);
runTaskCycles();
queuedStatus = readStatus();
assert.equal(queuedStatus.task.state, "ON");
assert.equal(queuedStatus.task.pendingCommandDepth, 0);
assertRejected("ESTOP blocks run", () => {
stageAndOpenProgram();
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ESTOP" }), 0);
@@ -144,50 +193,72 @@ assertRejected("missing program blocks run", () => {
reset();
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_JOINT_HOME", joint: -1 }), 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
runTaskCycles();
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.notEqual(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
assert.equal(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
runTaskCycles();
assert.equal(readStatus().task.errorText, "PROGRAM_OPEN_REQUIRED");
reset();
stageAndOpenProgram({ loadPlan: false });
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_JOINT_HOME", joint: -1 }), 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.notEqual(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
assert.equal(readStatus().task.errorText, "INTERPRETER_PLAN_REQUIRED");
reset();
stageAndOpenProgram();
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_JOINT_HOME", joint: -1 }), 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
runTaskCycles();
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.equal(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
runTaskCycles(4);
const noJsonPlanStatus = readStatus();
assert.equal(noJsonPlanStatus.task.errorText, "");
assert.equal(noJsonPlanStatus.task.motionPlanLoaded, false);
assert.equal(noJsonPlanStatus.emctaskSourceReuse.planReadCount > 0, true);
assert.equal(noJsonPlanStatus.emctaskSourceReuse.planExecuteCount > 0, true);
assert.equal(noJsonPlanStatus.emctaskSourceReuse.interpListAppendCount > 0, true);
reset();
stageAndOpenProgram();
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_JOINT_HOME", joint: -1 }), 0);
runTaskCycles();
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.equal(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
runTaskCycles();
let status = readStatus();
assert.equal(status.task.mode, "AUTO");
assert.equal(status.task.interpState, "READING");
assert.equal(["READING", "IDLE"].includes(status.task.interpState), true);
assert.equal(status.task.taskPaused, false);
assert.equal(status.task.singleStepping, false);
assert.equal(status.task.programOpen, true);
assert.equal(status.task.motionPlanLoaded, true);
assert.equal(status.task.motionPlanLoaded, false);
assert.equal(status.task.allHomed, true);
assert.equal(Array.isArray(status.task.homed), true);
assert.equal(status.task.homed.every(Boolean), true);
assert.equal(status.task.planId > 0, true);
assert.equal(status.task.planId, 0);
assert.equal(status.task.errorText, "");
reset();
stageAndOpenProgram({ loadPlan: true });
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_JOINT_HOME", joint: -1 }), 0);
runTaskCycles();
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.equal(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
runTaskCycles();
status = readStatus();
assert.equal(status.task.motionPlanLoaded, true);
assert.equal(status.task.planId > 0, true);
reset({ noForceHoming: true });
stageAndOpenProgram();
assert.equal(commandRc({ type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(commandRc({ type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.equal(commandRc({ type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
runTaskCycles();
status = readStatus();
assertStandaloneEmcStatus(status);
assert.equal(status.task.noForceHoming, true);
assert.equal(status.task.allHomed, false);
assert.equal(status.task.homed.every(Boolean), false);
assert.equal(status.task.interpState, "READING");
assert.equal(["READING", "IDLE"].includes(status.task.interpState), true);
console.log("task_state_matrix=ok");
console.log("run_gate_estop_rejected=ok");
@@ -196,5 +267,10 @@ console.log("run_gate_manual_rejected=ok");
console.log("run_gate_unhomed_rejected=ok");
console.log("run_gate_homing_rejected=ok");
console.log("run_gate_program_open_required=ok");
console.log("run_gate_interpreter_plan_required=ok");
console.log("run_gate_staged_program_executes_without_json_plan=ok");
console.log("run_gate_accepts_homed_open_plan=ok");
console.log("run_gate_json_motion_plan_compat=ok");
console.log("task_command_send_queues_until_cycle=ok");
console.log("task_command_json_host_boundary=ok");
console.log("standalone_emc_status_matrix=ok");
console.log("task_status_json_contract_matrix=ok");

View File

@@ -0,0 +1,116 @@
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
import assert from "node:assert/strict";
import createLinuxCncTaskHalModule from "../../../build/wasm/task-hal/linuxcnc_task_hal.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = resolve(__dirname, "../../..");
const wasmPath = resolve(rootDir, "build/wasm/task-hal/linuxcnc_task_hal.wasm");
const runtime = await createLinuxCncTaskHalModule({
wasmBinary: readFileSync(wasmPath),
print() {},
printErr(message) {
console.error(message);
},
});
function withCString(value, fn) {
const bytes = runtime.lengthBytesUTF8(value) + 1;
const ptr = runtime._malloc(bytes);
try {
runtime.stringToUTF8(value, ptr, bytes);
return fn(ptr);
} finally {
runtime._free(ptr);
}
}
function callJson(functionName, payload) {
return withCString(JSON.stringify(payload), (ptr) => runtime[`_${functionName}`](ptr));
}
function readStatus() {
const bytes = 131072;
const ptr = runtime._malloc(bytes);
try {
assert.equal(runtime._lctask_read_status_json(ptr, bytes), 0);
return JSON.parse(runtime.UTF8ToString(ptr));
} finally {
runtime._free(ptr);
}
}
assert.equal(callJson("lctask_init_session", {
iniPath: "status-json-contract.ini",
iniText: "[TRAJ]\nCOORDINATES = X Y Z A B C\n",
}), 0);
assert.equal(
withCString("programs/status-json-contract.ngc", (pathPtr) =>
withCString("G1 X1 Y2 Z3 A4 B5 C6 F60\n", (textPtr) =>
runtime._lctask_stage_file(pathPtr, textPtr))),
0,
);
assert.equal(
withCString("programs/status-json-contract.ngc", (pathPtr) =>
runtime._lctask_open_program(pathPtr)),
0,
);
assert.equal(callJson("lctask_send_command_json", { type: "EMC_TASK_SET_STATE", state: "ON" }), 0);
assert.equal(callJson("lctask_send_command_json", { type: "EMC_JOINT_HOME", joint: -1 }), 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
assert.equal(callJson("lctask_send_command_json", { type: "EMC_TASK_SET_MODE", mode: "AUTO" }), 0);
assert.equal(callJson("lctask_send_command_json", { type: "EMC_TASK_PLAN_RUN", line: 0 }), 0);
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 2), 0);
const status = readStatus();
assert.equal(status.statusSource, "StandaloneEmcStatus");
assert.equal(status.schemaVersion, 1);
assert.equal(status.emcStatus.source, "StandaloneEmcStatus");
assert.equal(status.emcStatus.top.status, status.taskTopLevelStatus);
assert.equal(status.emcStatus.task.currentLine, status.task.currentLine);
assert.equal(status.emcStatus.task.readLine, status.task.readLine);
assert.equal(status.emcStatus.task.motionLine, status.task.motionLine);
assert.equal(status.emcStatus.task.callLevel, status.task.callLevel);
assert.equal(status.emcStatus.motion.traj.queue, status.motionStatus.motion.queueDepth);
assert.equal(status.emcStatus.motion.traj.inpos, status.motionStatus.motion.inPosition);
assert.equal(status.emcStatus.motion.traj.id, status.motionStatus.motion.id);
assert.equal(status.emcStatus.motion.traj.activeQueue, status.motionStatus.activeDepth);
assert.equal(status.emcStatus.motion.traj.queueFull, status.motionStatus.motion.queueFull);
assert.equal(status.emcStatus.motion.traj.paused, status.motionStatus.motion.paused);
assert.equal(status.emcStatus.motion.traj.singleStepping, status.motionStatus.motion.stepping);
assert.equal(status.emcStatus.motion.traj.actualPosition.x, status.motionStatus.axis.x);
assert.equal(status.emcStatus.motion.traj.position.x, status.emcStatus.motion.axis[0].posCmd);
assert.equal(status.emcStatus.motion.traj.currentVel, status.motionStatus.motion.currentVel);
assert.equal(Array.isArray(status.emcStatus.motion.axis), true);
assert.equal(Array.isArray(status.emcStatus.motion.joint), true);
assert.equal(status.emcStatus.motion.axis.length >= 6, true);
assert.equal(status.emcStatus.motion.joint.length >= 6, true);
assert.equal(status.emcStatus.motion.axis[0].letter, "X");
assert.equal(status.emcStatus.motion.axis[0].posFb, status.motionStatus.axis.x);
assert.equal(status.emcStatus.motion.axis[1].posFb, status.motionStatus.axis.y);
assert.equal(status.emcStatus.motion.joint[0].motorPosCmd, status.motionStatus.joint0.motorPosCmd);
assert.equal(status.emcStatus.motion.joint[0].motorPosFb, status.motionStatus.joint0.motorPosFb);
assert.equal(status.emcStatus.io.status, status.rcsStatus.io);
assert.equal(status.emcStatus.io.fault, status.emcStatus.io.error);
assert.equal(status.emcStatus.io.reason, "");
assert.equal(typeof status.emcStatus.io.aux.estop, "boolean");
assert.equal(status.emcStatus.io.aux.source, "task-io-shim");
assert.equal(status.emcStatus.io.tool.supported, false);
assert.equal(status.emcStatus.io.tool.reason, "unsupported_without_native_io");
assert.equal(status.emcStatus.io.coolant.supported, false);
assert.equal(status.nativeTaskReady, false);
assert.equal(status.nativeHalSyncReady, false);
assert.equal(status.fullLinuxCncProgramExecutionReady, false);
console.log("task_status_json_contract_runtime=ok");
console.log("task_status_json_contract_schema=ok");
console.log("task_status_json_contract=ok");