Align Web XYZAC command gates with LinuxCNC
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -53,6 +53,47 @@ enum sim_task_program_value {
|
||||
SIM_TASK_PROGRAM_FAULT = 6,
|
||||
};
|
||||
|
||||
/* LinuxCNC emctaskmain command classes used by the Web XYZAC surface. */
|
||||
enum sim_task_gate_command {
|
||||
SIM_TASK_GATE_ESTOP = 1,
|
||||
SIM_TASK_GATE_RESET = 2,
|
||||
SIM_TASK_GATE_POWER = 3,
|
||||
SIM_TASK_GATE_HOME = 4,
|
||||
SIM_TASK_GATE_JOG = 5,
|
||||
SIM_TASK_GATE_MDI = 6,
|
||||
SIM_TASK_GATE_RUN = 7,
|
||||
SIM_TASK_GATE_PAUSE = 8,
|
||||
SIM_TASK_GATE_RESUME = 9,
|
||||
SIM_TASK_GATE_ABORT = 10,
|
||||
SIM_TASK_GATE_RESTART = 11,
|
||||
SIM_TASK_GATE_KINEMATICS = 12,
|
||||
SIM_TASK_GATE_SET_MODE = 13,
|
||||
SIM_TASK_GATE_PROGRAM_LOAD = 14,
|
||||
SIM_TASK_GATE_STEP = 15,
|
||||
};
|
||||
|
||||
enum sim_task_gate_result {
|
||||
SIM_TASK_GATE_ALLOWED = 0,
|
||||
SIM_TASK_GATE_ESTOP_ACTIVE = 1,
|
||||
SIM_TASK_GATE_MACHINE_OFF = 2,
|
||||
SIM_TASK_GATE_MACHINE_ON = 3,
|
||||
SIM_TASK_GATE_INTERP_ACTIVE = 4,
|
||||
SIM_TASK_GATE_TASKFILE_MISSING = 5,
|
||||
SIM_TASK_GATE_ESTOPOFF_REQUIRED = 6,
|
||||
SIM_TASK_GATE_PAUSE_STATE = 7,
|
||||
SIM_TASK_GATE_RESUME_STATE = 8,
|
||||
SIM_TASK_GATE_ABORT_STATE = 9,
|
||||
SIM_TASK_GATE_RESTART_STATE = 10,
|
||||
SIM_TASK_GATE_KINEMATICS_INVALID = 11,
|
||||
SIM_TASK_GATE_MODE_STATE = 12,
|
||||
SIM_TASK_GATE_MODE_AUTO_ACTIVE = 13,
|
||||
SIM_TASK_GATE_JOG_STATE = 14,
|
||||
SIM_TASK_GATE_MDI_STATE = 15,
|
||||
SIM_TASK_GATE_RESET_STATE = 16,
|
||||
SIM_TASK_GATE_UNKNOWN_COMMAND = 17,
|
||||
SIM_TASK_GATE_UNHOMED = 18,
|
||||
};
|
||||
|
||||
typedef struct sim_task_state {
|
||||
char context_id[SIM_TASK_CONTEXT_CAPACITY];
|
||||
char session_id[SIM_TASK_SESSION_CAPACITY];
|
||||
@@ -81,6 +122,11 @@ int32_t sim_task_transition(sim_task *task, uint32_t state);
|
||||
int32_t sim_task_fault(sim_task *task, int32_t error_code);
|
||||
int32_t sim_task_estop(sim_task *task, int32_t error_code);
|
||||
int32_t sim_task_recover(sim_task *task);
|
||||
int32_t sim_task_command_gate(const sim_task *task, uint32_t command,
|
||||
uint32_t requested, uint32_t io_ready,
|
||||
uint32_t io_estop, uint32_t homed,
|
||||
uint32_t queue_depth,
|
||||
uint32_t queue_limit);
|
||||
int32_t sim_task_restore(sim_task *task, uint32_t state, uint32_t mode,
|
||||
uint32_t program_status, uint32_t seq,
|
||||
uint32_t simulation_tick, uint32_t current_line,
|
||||
|
||||
@@ -456,7 +456,6 @@ int sim_io_set_estop(sim_io *io, uint32_t estop) {
|
||||
|
||||
int sim_io_set_power(sim_io *io, uint32_t active) {
|
||||
if (!valid_io(io) || active > 1U) return SIM_IO_ERR_ARGUMENT;
|
||||
if (io->state.estop) { set_last(io, SIM_IO_ERR_ESTOP); return SIM_IO_ERR_ESTOP; }
|
||||
if (!active) {
|
||||
io->state.ready = 0;
|
||||
io->state.tool_prepare = 0;
|
||||
@@ -470,6 +469,7 @@ int sim_io_set_power(sim_io *io, uint32_t active) {
|
||||
io->state.spindles[index].brake = 1;
|
||||
}
|
||||
} else {
|
||||
if (io->state.estop) { set_last(io, SIM_IO_ERR_ESTOP); return SIM_IO_ERR_ESTOP; }
|
||||
if (io->state.fault || io->state.toolchanger_fault) { set_last(io, SIM_IO_ERR_FAULT); return SIM_IO_ERR_FAULT; }
|
||||
if (!spindle_stopped(io)) { set_last(io, SIM_IO_ERR_BUSY); return SIM_IO_ERR_BUSY; }
|
||||
io->state.ready = 1;
|
||||
|
||||
@@ -165,6 +165,90 @@ int32_t sim_task_recover(sim_task *task) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t sim_task_command_gate(const sim_task *task, uint32_t command,
|
||||
uint32_t requested, uint32_t io_ready,
|
||||
uint32_t io_estop, uint32_t homed,
|
||||
uint32_t queue_depth,
|
||||
uint32_t queue_limit) {
|
||||
int machine_on;
|
||||
int active;
|
||||
int idle;
|
||||
if (!valid_task(task) || io_ready > 1U || io_estop > 1U || homed > 1U)
|
||||
return SIM_TASK_GATE_UNKNOWN_COMMAND;
|
||||
machine_on = io_ready != 0U && io_estop == 0U;
|
||||
active = task->state.state == SIM_TASK_RUNNING ||
|
||||
task->state.state == SIM_TASK_PAUSED ||
|
||||
task->state.program_status == SIM_TASK_PROGRAM_RUNNING ||
|
||||
task->state.program_status == SIM_TASK_PROGRAM_PAUSED;
|
||||
idle = !active;
|
||||
switch (command) {
|
||||
case SIM_TASK_GATE_ESTOP:
|
||||
/* LinuxCNC accepts ESTOP from every task state; reset is only the
|
||||
inverse edge while the auxiliary estop input is asserted. */
|
||||
return requested == 1U || io_estop ? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_ESTOPOFF_REQUIRED;
|
||||
case SIM_TASK_GATE_POWER:
|
||||
if (requested == 1U) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : machine_on ? SIM_TASK_GATE_MACHINE_ON : SIM_TASK_GATE_ALLOWED;
|
||||
/* emcTaskSetState(OFF) aborts motion and is accepted while running. */
|
||||
return machine_on ? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_MACHINE_OFF;
|
||||
case SIM_TASK_GATE_PROGRAM_LOAD:
|
||||
/* PLAN_OPEN is an immediate task command and is accepted in the
|
||||
OFF/ESTOP/ESTOP_RESET branches when the interpreter is idle. */
|
||||
return idle ? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_INTERP_ACTIVE;
|
||||
case SIM_TASK_GATE_RUN:
|
||||
if (io_estop || !machine_on) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
if (!idle) return SIM_TASK_GATE_INTERP_ACTIVE;
|
||||
if (!homed) return SIM_TASK_GATE_UNHOMED;
|
||||
return task->state.program_status == SIM_TASK_PROGRAM_IDLE ? SIM_TASK_GATE_TASKFILE_MISSING : SIM_TASK_GATE_ALLOWED;
|
||||
case SIM_TASK_GATE_STEP:
|
||||
if (io_estop || !machine_on) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
if (!homed) return SIM_TASK_GATE_UNHOMED;
|
||||
return task->state.program_status != SIM_TASK_PROGRAM_IDLE &&
|
||||
(idle || task->state.mode == SIM_TASK_MODE_AUTO)
|
||||
? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_RESET_STATE;
|
||||
case SIM_TASK_GATE_PAUSE:
|
||||
return machine_on && task->state.mode == SIM_TASK_MODE_AUTO && task->state.program_status == SIM_TASK_PROGRAM_RUNNING
|
||||
? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_PAUSE_STATE;
|
||||
case SIM_TASK_GATE_RESUME:
|
||||
return machine_on && (task->state.mode == SIM_TASK_MODE_AUTO || task->state.mode == SIM_TASK_MODE_MDI) && task->state.program_status == SIM_TASK_PROGRAM_PAUSED
|
||||
? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_RESUME_STATE;
|
||||
case SIM_TASK_GATE_ABORT:
|
||||
/* EMC_TASK_ABORT_TYPE is an immediate command in every emctaskmain
|
||||
state branch, including OFF/ESTOP and an idle interpreter. */
|
||||
return SIM_TASK_GATE_ALLOWED;
|
||||
case SIM_TASK_GATE_RESTART:
|
||||
if (!idle) return SIM_TASK_GATE_INTERP_ACTIVE;
|
||||
return task->state.program_status == SIM_TASK_PROGRAM_IDLE ? SIM_TASK_GATE_TASKFILE_MISSING : SIM_TASK_GATE_ALLOWED;
|
||||
case SIM_TASK_GATE_HOME:
|
||||
return machine_on && idle ? SIM_TASK_GATE_ALLOWED : machine_on ? SIM_TASK_GATE_INTERP_ACTIVE : io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
case SIM_TASK_GATE_JOG:
|
||||
/* AXIS allows jog commands while idle in all three task modes; the
|
||||
manual tab changes mode before sending the command when required. */
|
||||
return machine_on && idle ? SIM_TASK_GATE_ALLOWED : io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : machine_on ? SIM_TASK_GATE_INTERP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
case SIM_TASK_GATE_MDI:
|
||||
if (io_estop || !machine_on) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
if (!idle) return SIM_TASK_GATE_INTERP_ACTIVE;
|
||||
if (!homed) return SIM_TASK_GATE_UNHOMED;
|
||||
if (queue_limit != 0U && queue_depth >= queue_limit) return SIM_TASK_GATE_MDI_STATE;
|
||||
return SIM_TASK_GATE_ALLOWED;
|
||||
case SIM_TASK_GATE_KINEMATICS:
|
||||
if (requested > 2U) return SIM_TASK_GATE_KINEMATICS_INVALID;
|
||||
if (io_estop || !machine_on) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
if (!homed) return SIM_TASK_GATE_UNHOMED;
|
||||
return idle ? SIM_TASK_GATE_ALLOWED : SIM_TASK_GATE_INTERP_ACTIVE;
|
||||
case SIM_TASK_GATE_SET_MODE:
|
||||
if (requested > SIM_TASK_MODE_AUTO || io_estop || !machine_on) return io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : io_ready ? SIM_TASK_GATE_MODE_STATE : SIM_TASK_GATE_MACHINE_OFF;
|
||||
/* emcTaskSetMode explicitly refuses AUTO -> MANUAL/MDI while the
|
||||
AUTO interpreter is non-idle. */
|
||||
if (active && task->state.mode == SIM_TASK_MODE_AUTO && requested != SIM_TASK_MODE_AUTO)
|
||||
return SIM_TASK_GATE_MODE_AUTO_ACTIVE;
|
||||
return SIM_TASK_GATE_ALLOWED;
|
||||
case SIM_TASK_GATE_RESET:
|
||||
return machine_on && idle ? SIM_TASK_GATE_ALLOWED : io_estop ? SIM_TASK_GATE_ESTOP_ACTIVE : !machine_on ? SIM_TASK_GATE_MACHINE_OFF : SIM_TASK_GATE_RESET_STATE;
|
||||
default:
|
||||
return SIM_TASK_GATE_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t sim_task_restore(sim_task *task, uint32_t state, uint32_t mode,
|
||||
uint32_t program_status, uint32_t seq,
|
||||
uint32_t simulation_tick, uint32_t current_line,
|
||||
|
||||
@@ -17,9 +17,20 @@ int main(void) {
|
||||
assert(sim_task_attach(&task) == SIM_TASK_OK);
|
||||
assert(sim_task_set_command(&task, 3, 0) == SIM_TASK_ERR_SEQUENCE);
|
||||
assert(sim_task_set_command(&task, 2, 0) == SIM_TASK_OK);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_PROGRAM_LOAD, 0, 0, 0, 0, 0, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_RUN, 0, 0, 0, 0, 0, 10) == SIM_TASK_GATE_MACHINE_OFF);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_POWER, 1, 0, 0, 0, 0, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_POWER, 0, 0, 0, 0, 0, 10) == SIM_TASK_GATE_MACHINE_OFF);
|
||||
assert(sim_task_set_program(&task, SIM_TASK_PROGRAM_LOADED, 0) == SIM_TASK_OK);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_RUN, 0, 1, 0, 1, 1, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_transition(&task, SIM_TASK_RUNNING) == SIM_TASK_OK);
|
||||
assert(sim_task_set_program(&task, SIM_TASK_PROGRAM_RUNNING, 1) == SIM_TASK_OK);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_PAUSE, 0, 1, 0, 1, 0, 10) == SIM_TASK_GATE_PAUSE_STATE);
|
||||
assert(sim_task_set_mode(&task, SIM_TASK_MODE_AUTO) == SIM_TASK_OK);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_PAUSE, 0, 1, 0, 1, 0, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_POWER, 0, 1, 0, 1, 0, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_SET_MODE, SIM_TASK_MODE_MANUAL, 1, 0, 1, 0, 10) == SIM_TASK_GATE_MODE_AUTO_ACTIVE);
|
||||
assert(sim_task_command_gate(&task, SIM_TASK_GATE_ESTOP, 1, 1, 0, 1, 0, 10) == SIM_TASK_GATE_ALLOWED);
|
||||
assert(sim_task_set_command(&task, 3, 4) == SIM_TASK_OK);
|
||||
assert(sim_task_transition(&task, SIM_TASK_PAUSED) == SIM_TASK_OK);
|
||||
assert(sim_task_set_command(&task, 4, 3) == SIM_TASK_ERR_TICK);
|
||||
|
||||
Reference in New Issue
Block a user