接入 LinuxCNC TP 运行反馈

This commit is contained in:
2026-06-21 23:29:56 +08:00
parent 626bcfe8e3
commit 3771b9eafe
44 changed files with 7881 additions and 326 deletions

View File

@@ -0,0 +1,161 @@
export const LINUXCNC_TASK_POLICY = {
apiName: "web-rtcp-5axis-linuxcnc-task-policy",
sourceMode: "linuxcnc-task-source-referenced-policy",
semanticBoundary: "linuxcnc_task_state_mode_command_gate",
sourceReferences: [
{
path: "linuxcnc/src/emc/nml_intf/emc.hh",
symbols: ["EMC_TASK_MODE", "EMC_TASK_STATE", "EMC_TASK_INTERP"],
},
{
path: "linuxcnc/src/emc/task/emctaskmain.cc",
symbols: [
"emcTaskPlan",
"EMC_TASK_PLAN_RUN",
"EMC_TASK_PLAN_EXECUTE",
"EMC_TASK_PLAN_PAUSE",
"EMC_TASK_PLAN_RESUME",
"EMC_TASK_ABORT",
"EMC_JOG_INCR",
"EMC_JOINT_HOME",
],
},
{
path: "linuxcnc/src/emc/task/emctask.cc",
symbols: ["emcTaskSetState", "determineState"],
},
],
};
export const LINUXCNC_TASK_MODES = new Set(["manual", "auto", "mdi"]);
export const LINUXCNC_TASK_STATES = new Set(["estop", "estop-reset", "off", "on"]);
export const LINUXCNC_INTERP_STATES = new Set(["idle", "reading", "paused", "waiting"]);
export function normalizeLinuxCncTaskMode(mode) {
if (mode === "jog") return "manual";
return LINUXCNC_TASK_MODES.has(mode) ? mode : "manual";
}
export function normalizeLinuxCncTaskState(machine = {}) {
if (LINUXCNC_TASK_STATES.has(machine.taskState)) return machine.taskState;
if (machine.estopActive) return "estop";
if (machine.powerOn) return "on";
return "estop-reset";
}
export function normalizeLinuxCncInterpState(machine = {}, runState = "idle") {
if (LINUXCNC_INTERP_STATES.has(machine.interpState)) return machine.interpState;
if (runState === "running") return "reading";
if (runState === "paused" || runState === "stepping") return "paused";
return "idle";
}
export function createLinuxCncTaskPolicyStatus(state) {
const taskState = normalizeLinuxCncTaskState(state.machine);
const taskMode = normalizeLinuxCncTaskMode(state.machine.mode);
const interpState = normalizeLinuxCncInterpState(state.machine, state.runState);
const allHomed = Boolean(state.machine.allHomed);
const noForceHoming = Boolean(state.machine.noForceHoming);
return {
...LINUXCNC_TASK_POLICY,
taskState,
taskMode,
interpState,
allHomed,
noForceHoming,
powerOn: taskState === "on",
estopActive: taskState === "estop",
canMove: taskState === "on",
canJog: taskState === "on" && taskMode === "manual",
canHome: taskState === "on" && taskMode === "manual",
canRunAuto: taskState === "on" && taskMode === "auto" && (allHomed || noForceHoming),
canExecuteMdi: taskState === "on" && taskMode === "mdi" && (allHomed || noForceHoming),
canPause: taskState === "on" && (taskMode === "auto" || taskMode === "mdi"),
canResume: taskState === "on" && (taskMode === "auto" || taskMode === "mdi") && interpState === "paused",
canAbort: true,
canLeaveAuto: taskMode !== "auto" || interpState === "idle",
};
}
export function gateLinuxCncTaskAction(state, action) {
const status = createLinuxCncTaskPolicyStatus(state);
const type = typeof action === "string" ? action : action?.type;
const requestedMode = typeof action === "object" ? action.mode : undefined;
switch (type) {
case "TOGGLE_POWER":
if (status.taskState === "estop") {
return block(status, "power on blocked: reset estop first");
}
return allow(status);
case "SET_MODE":
return gateMode(status, requestedMode);
case "JOG":
if (status.taskState !== "on") return block(status, "jog blocked: machine must be on");
if (status.taskMode !== "manual") return block(status, "jog blocked: switch to manual mode first");
return allow(status);
case "HOME":
if (status.taskState !== "on") return block(status, "home blocked: machine must be on");
if (status.taskMode !== "manual") return block(status, "home blocked: switch to manual mode first");
return allow(status);
case "RUN_MDI":
if (status.taskState !== "on") return block(status, "MDI blocked: machine must be on");
if (status.taskMode !== "mdi") return block(status, "MDI blocked: switch to MDI mode first");
if (!status.allHomed && !status.noForceHoming) return block(status, "MDI blocked: home machine first");
return allow(status);
case "RUN":
case "STEP":
case "RUN_FRAME":
if (status.taskState !== "on") return block(status, `${type.toLowerCase()} blocked: machine must be on`);
if (status.taskMode !== "auto") return block(status, `${type.toLowerCase()} blocked: switch to auto mode first`);
if (!status.allHomed && !status.noForceHoming) return block(status, `${type.toLowerCase()} blocked: home machine first`);
if (type === "RUN" && status.interpState === "paused") return block(status, "run blocked: resume paused program first");
return allow(status);
case "PAUSE":
if (status.taskState !== "on") return block(status, "pause blocked: machine must be on");
if (status.taskMode !== "auto" && status.taskMode !== "mdi") {
return block(status, "pause blocked: task mode must be auto or MDI");
}
return allow(status);
case "RESUME":
if (status.taskState !== "on") return block(status, "resume blocked: machine must be on");
if (status.taskMode !== "auto" && status.taskMode !== "mdi") {
return block(status, "resume blocked: task mode must be auto or MDI");
}
if (status.interpState !== "paused") return block(status, "resume blocked: interpreter is not paused");
return allow(status);
case "STOP":
case "ABORT":
return allow(status);
default:
return allow(status);
}
}
function gateMode(status, requestedMode) {
const targetMode = normalizeLinuxCncTaskMode(requestedMode);
if (!LINUXCNC_TASK_MODES.has(targetMode)) {
return block(status, `mode blocked: invalid LinuxCNC task mode ${requestedMode}`);
}
if (status.taskMode === "auto" && status.interpState !== "idle" && targetMode !== "auto") {
return block(status, "mode blocked: AUTO interpreter is not idle");
}
return allow(status);
}
function allow(status) {
return {
allowed: true,
status,
operatorMessage: null,
};
}
function block(status, operatorMessage) {
return {
allowed: false,
status,
operatorMessage,
};
}