feat: complete working8 pause semantics
This commit is contained in:
@@ -39,6 +39,9 @@ typedef struct {
|
||||
int teleop_mode;
|
||||
int in_position;
|
||||
int paused;
|
||||
int stepping;
|
||||
int id_for_step;
|
||||
int motion_id;
|
||||
int aborted;
|
||||
int switchkins_type;
|
||||
double requested_vel;
|
||||
@@ -187,6 +190,13 @@ static int queue_pop(LcmotCommand *command)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_motion_command(int type)
|
||||
{
|
||||
return type == LCMOT_CMD_LINEAR_MOVE ||
|
||||
type == LCMOT_CMD_CIRCULAR_MOVE ||
|
||||
type == LCMOT_CMD_JOG_INCR;
|
||||
}
|
||||
|
||||
static void sync_hal_pins(void)
|
||||
{
|
||||
int i;
|
||||
@@ -263,19 +273,29 @@ static void apply_command(const LcmotCommand *command)
|
||||
switch (command->type) {
|
||||
case LCMOT_CMD_PAUSE:
|
||||
state->paused = 1;
|
||||
state->stepping = 0;
|
||||
state->id_for_step = state->motion_id;
|
||||
state->motion_type = 0;
|
||||
state->current_vel = 0.0;
|
||||
state->in_position = 0;
|
||||
break;
|
||||
case LCMOT_CMD_STEP:
|
||||
state->paused = 0;
|
||||
state->stepping = 1;
|
||||
state->id_for_step = state->motion_id;
|
||||
state->paused = 1;
|
||||
break;
|
||||
case LCMOT_CMD_RESUME:
|
||||
state->paused = 0;
|
||||
state->stepping = 0;
|
||||
state->id_for_step = state->motion_id;
|
||||
break;
|
||||
case LCMOT_CMD_ABORT:
|
||||
state->aborted = 1;
|
||||
state->paused = 0;
|
||||
state->stepping = 0;
|
||||
state->id_for_step = state->motion_id;
|
||||
state->motion_type = 0;
|
||||
state->current_vel = 0.0;
|
||||
state->in_position = 1;
|
||||
state->queue_head = 0;
|
||||
state->queue_tail = 0;
|
||||
@@ -287,6 +307,7 @@ static void apply_command(const LcmotCommand *command)
|
||||
break;
|
||||
case LCMOT_CMD_LINEAR_MOVE:
|
||||
case LCMOT_CMD_CIRCULAR_MOVE:
|
||||
state->motion_id += 1;
|
||||
state->program_line = command->line;
|
||||
state->motion_type = command->type == LCMOT_CMD_CIRCULAR_MOVE ? 2 : 1;
|
||||
state->coord_mode = 1;
|
||||
@@ -302,8 +323,14 @@ static void apply_command(const LcmotCommand *command)
|
||||
state->current_vel = state->requested_vel;
|
||||
state->in_position = 1;
|
||||
state->motion_type = 0;
|
||||
if (state->stepping) {
|
||||
state->paused = 1;
|
||||
state->stepping = 0;
|
||||
state->current_vel = 0.0;
|
||||
}
|
||||
break;
|
||||
case LCMOT_CMD_JOG_INCR:
|
||||
state->motion_id += 1;
|
||||
i = command->axis_index;
|
||||
if (i < 0 || i >= 9) {
|
||||
i = 0;
|
||||
@@ -320,6 +347,11 @@ static void apply_command(const LcmotCommand *command)
|
||||
state->current_vel = state->requested_vel;
|
||||
state->in_position = 1;
|
||||
state->motion_type = 0;
|
||||
if (state->stepping) {
|
||||
state->paused = 1;
|
||||
state->stepping = 0;
|
||||
state->current_vel = 0.0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -381,6 +413,14 @@ int lcmot_write_command_json(const char *json)
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (command.type == LCMOT_CMD_PAUSE ||
|
||||
command.type == LCMOT_CMD_STEP ||
|
||||
command.type == LCMOT_CMD_RESUME ||
|
||||
command.type == LCMOT_CMD_ABORT) {
|
||||
apply_command(&command);
|
||||
sync_hal_pins();
|
||||
return 0;
|
||||
}
|
||||
return queue_push(command);
|
||||
}
|
||||
|
||||
@@ -396,6 +436,7 @@ int lcmot_step_servo(long period_ns, int cycles)
|
||||
if (!lcmot_state.aborted && lcmot_state.queue_count > 0) {
|
||||
command = lcmot_state.queue[lcmot_state.queue_head];
|
||||
if (!lcmot_state.paused ||
|
||||
(lcmot_state.stepping && is_motion_command(command.type)) ||
|
||||
command.type == LCMOT_CMD_STEP ||
|
||||
command.type == LCMOT_CMD_RESUME ||
|
||||
command.type == LCMOT_CMD_ABORT) {
|
||||
@@ -420,7 +461,9 @@ int lcmot_read_status_json(char *out, int out_len)
|
||||
"\"cycle\":%lld,"
|
||||
"\"motion\":{\"programLine\":%d,\"motionType\":%d,\"coordMode\":%d,"
|
||||
"\"teleopMode\":%d,\"inPosition\":%s,\"paused\":%s,\"aborted\":%s,"
|
||||
"\"switchkinsType\":%d,\"requestedVel\":%.17g,\"currentVel\":%.17g},"
|
||||
"\"stepping\":%s,\"idForStep\":%d,\"motionId\":%d,"
|
||||
"\"switchkinsType\":%d,\"requestedVel\":%.17g,\"currentVel\":%.17g,"
|
||||
"\"commandQueueDepth\":%d},"
|
||||
"\"axis\":{\"x\":%.17g,\"y\":%.17g,\"z\":%.17g,\"a\":%.17g,\"b\":%.17g,\"c\":%.17g},"
|
||||
"\"joint0\":{\"motorPosCmd\":%.17g,\"motorPosFb\":%.17g},"
|
||||
"\"commandQueueDepth\":%d}",
|
||||
@@ -432,9 +475,13 @@ int lcmot_read_status_json(char *out, int out_len)
|
||||
state->in_position ? "true" : "false",
|
||||
state->paused ? "true" : "false",
|
||||
state->aborted ? "true" : "false",
|
||||
state->stepping ? "true" : "false",
|
||||
state->id_for_step,
|
||||
state->motion_id,
|
||||
state->switchkins_type,
|
||||
state->requested_vel,
|
||||
state->current_vel,
|
||||
state->queue_count,
|
||||
state->axis_fb[0],
|
||||
state->axis_fb[1],
|
||||
state->axis_fb[2],
|
||||
|
||||
@@ -31,6 +31,7 @@ struct TaskRuntime {
|
||||
std::string state = "ESTOP";
|
||||
std::string mode = "MANUAL";
|
||||
std::string interp_state = "IDLE";
|
||||
std::string interp_resume_state = "IDLE";
|
||||
std::string exec_state = "DONE";
|
||||
bool task_paused = false;
|
||||
bool single_stepping = false;
|
||||
@@ -394,7 +395,10 @@ void forward_timed_motion_sample(TaskRuntime &state)
|
||||
|
||||
if (state.active_segment_index >= static_cast<int>(state.motion_plan.size())) {
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
state.next_program_line = std::max(state.opened_line_count, state.opened_source_line_count);
|
||||
return;
|
||||
}
|
||||
@@ -416,7 +420,10 @@ void forward_timed_motion_sample(TaskRuntime &state)
|
||||
state.next_program_line = std::min(std::max(segment.line, 1), std::max(max_line, 1));
|
||||
if (state.active_segment_index == static_cast<int>(state.motion_plan.size()) - 1 && progress >= 1.0) {
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
state.next_program_line = std::max(state.opened_line_count, state.opened_source_line_count);
|
||||
state.events.push_back("task_motion_plan_complete");
|
||||
}
|
||||
@@ -479,6 +486,7 @@ std::string status_json()
|
||||
out << ",\"task\":{\"state\":\"" << json_escape(state.state) << "\"";
|
||||
out << ",\"mode\":\"" << json_escape(state.mode) << "\"";
|
||||
out << ",\"interpState\":\"" << json_escape(state.interp_state) << "\"";
|
||||
out << ",\"interpResumeState\":\"" << json_escape(state.interp_resume_state) << "\"";
|
||||
out << ",\"execState\":\"" << json_escape(state.exec_state) << "\"";
|
||||
out << ",\"taskPaused\":" << (state.task_paused ? "true" : "false");
|
||||
out << ",\"singleStepping\":" << (state.single_stepping ? "true" : "false");
|
||||
@@ -527,6 +535,7 @@ int lctask_init_session(const char *session_json)
|
||||
state.state = "ESTOP_RESET";
|
||||
state.mode = "MANUAL";
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.events.push_back("task_session_init");
|
||||
|
||||
@@ -573,6 +582,7 @@ int lctask_open_program(const char *path)
|
||||
state.active_segment_index = 0;
|
||||
state.run_elapsed_seconds = 0.0;
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.events.push_back(std::string("task_open_program:") + path);
|
||||
return 0;
|
||||
@@ -617,6 +627,7 @@ int lctask_send_command_json(const char *command_json)
|
||||
state.active_segment_index = 0;
|
||||
state.run_elapsed_seconds = 0.0;
|
||||
state.interp_state = "READING";
|
||||
state.interp_resume_state = "READING";
|
||||
state.exec_state = "WAITING_FOR_MOTION";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
@@ -624,6 +635,9 @@ int lctask_send_command_json(const char *command_json)
|
||||
return 0;
|
||||
}
|
||||
if (contains_token(command_json, "EMC_TASK_PLAN_PAUSE")) {
|
||||
if (state.interp_state != "PAUSED") {
|
||||
state.interp_resume_state = state.interp_state.empty() ? "READING" : state.interp_state;
|
||||
}
|
||||
state.interp_state = "PAUSED";
|
||||
state.exec_state = "PAUSED";
|
||||
state.task_paused = true;
|
||||
@@ -631,19 +645,24 @@ int lctask_send_command_json(const char *command_json)
|
||||
return forward_motion_command("{\"type\":\"EMC_TRAJ_PAUSE\"}");
|
||||
}
|
||||
if (contains_token(command_json, "EMC_TASK_PLAN_STEP")) {
|
||||
if (state.interp_state != "PAUSED") {
|
||||
state.interp_resume_state = state.interp_state.empty() ? "READING" : state.interp_state;
|
||||
}
|
||||
state.single_stepping = true;
|
||||
state.task_paused = true;
|
||||
if (state.interp_state == "PAUSED") {
|
||||
state.interp_state = "READING";
|
||||
}
|
||||
state.exec_state = "WAITING_FOR_MOTION";
|
||||
state.interp_state = "PAUSED";
|
||||
state.exec_state = "PAUSED";
|
||||
state.events.push_back("task_plan_step");
|
||||
forward_motion_command("{\"type\":\"EMC_TRAJ_STEP\"}");
|
||||
return 0;
|
||||
}
|
||||
if (contains_token(command_json, "EMC_TASK_PLAN_RESUME")) {
|
||||
state.interp_state = "READING";
|
||||
state.exec_state = "WAITING_FOR_MOTION";
|
||||
const std::string resume = state.interp_resume_state == "PAUSED" || state.interp_resume_state.empty()
|
||||
? "READING"
|
||||
: state.interp_resume_state;
|
||||
state.interp_state = resume;
|
||||
state.interp_resume_state = resume;
|
||||
state.exec_state = resume == "IDLE" ? "DONE" : "WAITING_FOR_MOTION";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
state.events.push_back("task_plan_resume");
|
||||
@@ -651,6 +670,7 @@ int lctask_send_command_json(const char *command_json)
|
||||
}
|
||||
if (contains_token(command_json, "EMC_TASK_ABORT")) {
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
@@ -661,6 +681,7 @@ int lctask_send_command_json(const char *command_json)
|
||||
if (contains_token(command_json, "EMC_TASK_PLAN_EXECUTE")) {
|
||||
state.mode = "MDI";
|
||||
state.interp_state = "READING";
|
||||
state.interp_resume_state = "READING";
|
||||
state.exec_state = "WAITING_FOR_MOTION";
|
||||
state.task_paused = false;
|
||||
enqueue_mdi(state, command_json);
|
||||
@@ -669,6 +690,7 @@ int lctask_send_command_json(const char *command_json)
|
||||
if (contains_token(command_json, "EMC_JOG_INCR")) {
|
||||
state.mode = "MANUAL";
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "WAITING_FOR_MOTION";
|
||||
state.task_paused = false;
|
||||
state.events.push_back("task_jog_incr");
|
||||
@@ -677,6 +699,7 @@ int lctask_send_command_json(const char *command_json)
|
||||
if (contains_token(command_json, "EMC_JOINT_HOME")) {
|
||||
state.mode = "MANUAL";
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
@@ -708,7 +731,8 @@ int lctask_run_cycles(long task_period_ns, long servo_period_ns, int task_cycles
|
||||
const bool has_program_work = state.motion_plan_loaded
|
||||
? state.active_segment_index < static_cast<int>(state.motion_plan.size())
|
||||
: state.next_program_line < state.executable_line_count;
|
||||
if (state.interp_state == "READING" && has_program_work) {
|
||||
const bool stepping = state.single_stepping;
|
||||
if ((state.interp_state == "READING" || stepping) && has_program_work) {
|
||||
if (state.motion_plan_loaded) {
|
||||
const double delta_seconds = task_period_ns > 0 ? static_cast<double>(task_period_ns) / 1000000000.0 : 0.01;
|
||||
state.run_elapsed_seconds += delta_seconds;
|
||||
@@ -716,18 +740,24 @@ int lctask_run_cycles(long task_period_ns, long servo_period_ns, int task_cycles
|
||||
} else {
|
||||
enqueue_linear_move_from_line(state, state.program_lines[state.next_program_line]);
|
||||
}
|
||||
if (!state.motion_plan_loaded && state.next_program_line >= state.executable_line_count) {
|
||||
if (stepping) {
|
||||
state.interp_state = "PAUSED";
|
||||
state.exec_state = "PAUSED";
|
||||
state.task_paused = true;
|
||||
state.single_stepping = false;
|
||||
} else if (!state.motion_plan_loaded && state.next_program_line >= state.executable_line_count) {
|
||||
state.interp_state = "IDLE";
|
||||
state.interp_resume_state = "IDLE";
|
||||
state.exec_state = "DONE";
|
||||
state.task_paused = false;
|
||||
state.single_stepping = false;
|
||||
state.events.push_back("task_plan_complete");
|
||||
}
|
||||
if (state.single_stepping) {
|
||||
state.interp_state = "PAUSED";
|
||||
state.exec_state = "PAUSED";
|
||||
state.task_paused = true;
|
||||
}
|
||||
} else if (stepping) {
|
||||
state.interp_state = "PAUSED";
|
||||
state.exec_state = "PAUSED";
|
||||
state.task_paused = true;
|
||||
state.single_stepping = false;
|
||||
}
|
||||
if (lcmot_step_servo(servo_period_ns, servo_per_task) != 0) {
|
||||
return -1;
|
||||
|
||||
@@ -1048,6 +1048,158 @@ static void append_queued_lines_probe(char *out, size_t size, size_t *offset)
|
||||
append(out, size, offset, line);
|
||||
}
|
||||
|
||||
static void append_pause_resume_probe(char *out, size_t size, size_t *offset)
|
||||
{
|
||||
init_motion_state();
|
||||
|
||||
TP_STRUCT tp;
|
||||
EmcPose start;
|
||||
EmcPose end1;
|
||||
EmcPose end2;
|
||||
struct state_tag_t tag;
|
||||
memset(&tp, 0, sizeof(tp));
|
||||
memset(&start, 0, sizeof(start));
|
||||
memset(&end1, 0, sizeof(end1));
|
||||
memset(&end2, 0, sizeof(end2));
|
||||
memset(&tag, 0, sizeof(tag));
|
||||
|
||||
end1.tran.x = 1.0;
|
||||
end2.tran.x = 2.0;
|
||||
|
||||
const int create_rc = tpCreate(&tp, TP_DEFAULT_QUEUE_SIZE, 4);
|
||||
const int set_cycle_rc = tpSetCycleTime(&tp, 0.001);
|
||||
const int set_pos_rc = tpSetPos(&tp, &start);
|
||||
const int set_vmax_rc = tpSetVmax(&tp, 1.0, 1.0);
|
||||
const int set_vlimit_rc = tpSetVlimit(&tp, 1.0);
|
||||
const int set_amax_rc = tpSetAmax(&tp, 10.0);
|
||||
const int set_term_rc = tpSetTermCond(&tp, TC_TERM_COND_STOP, 0.0);
|
||||
const int add_line1_rc = tpAddLine(
|
||||
&tp,
|
||||
end1,
|
||||
EMC_MOTION_TYPE_FEED,
|
||||
1.0,
|
||||
1.0,
|
||||
10.0,
|
||||
100.0,
|
||||
status.enables_new,
|
||||
0,
|
||||
-1,
|
||||
tag);
|
||||
const int add_line2_rc = tpAddLine(
|
||||
&tp,
|
||||
end2,
|
||||
EMC_MOTION_TYPE_FEED,
|
||||
1.0,
|
||||
1.0,
|
||||
10.0,
|
||||
100.0,
|
||||
status.enables_new,
|
||||
0,
|
||||
-1,
|
||||
tag);
|
||||
|
||||
int cycle_rc = 0;
|
||||
int cycles_before_pause = 0;
|
||||
for (; cycles_before_pause < 200 && !tpIsDone(&tp); ++cycles_before_pause) {
|
||||
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||
if (cycle_rc < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int pause_rc = tpPause(&tp);
|
||||
int pause_cycles = 0;
|
||||
for (; pause_cycles < 10000; ++pause_cycles) {
|
||||
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||
if (cycle_rc < 0 || fabs(status.current_vel) < 1e-9) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EmcPose paused_pos;
|
||||
EmcPose hold_pos;
|
||||
EmcPose final_pos;
|
||||
memset(&paused_pos, 0, sizeof(paused_pos));
|
||||
memset(&hold_pos, 0, sizeof(hold_pos));
|
||||
memset(&final_pos, 0, sizeof(final_pos));
|
||||
const int pause_get_pos_rc = tpGetPos(&tp, &paused_pos);
|
||||
for (int hold = 0; hold < 100; ++hold) {
|
||||
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||
if (cycle_rc < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int hold_get_pos_rc = tpGetPos(&tp, &hold_pos);
|
||||
const int paused_velocity_zero = fabs(status.current_vel) < 1e-9 ? 1 : 0;
|
||||
const int paused_position_frozen =
|
||||
fabs(paused_pos.tran.x - hold_pos.tran.x) < 1e-6 &&
|
||||
fabs(paused_pos.tran.y - hold_pos.tran.y) < 1e-6 &&
|
||||
fabs(paused_pos.tran.z - hold_pos.tran.z) < 1e-6;
|
||||
|
||||
const int resume_rc = tpResume(&tp);
|
||||
int resume_cycles = 0;
|
||||
for (; resume_cycles < 30000 && !tpIsDone(&tp); ++resume_cycles) {
|
||||
cycle_rc = tpRunCycle(&tp, 1000000);
|
||||
if (cycle_rc < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int final_get_pos_rc = tpGetPos(&tp, &final_pos);
|
||||
const int near_end = pose_near(&final_pos, &end2);
|
||||
|
||||
char line[1536];
|
||||
snprintf(line, sizeof(line),
|
||||
"tp_pause_create=%d\n"
|
||||
"tp_pause_set_cycle_time=%d\n"
|
||||
"tp_pause_set_pos=%d\n"
|
||||
"tp_pause_set_vmax=%d\n"
|
||||
"tp_pause_set_vlimit=%d\n"
|
||||
"tp_pause_set_amax=%d\n"
|
||||
"tp_pause_set_term_cond=%d\n"
|
||||
"tp_pause_add_line1=%d\n"
|
||||
"tp_pause_add_line2=%d\n"
|
||||
"tp_pause_rc=%d\n"
|
||||
"tp_pause_cycles_before=%d\n"
|
||||
"tp_pause_decel_cycles=%d\n"
|
||||
"tp_pause_get_pos=%d\n"
|
||||
"tp_pause_hold_get_pos=%d\n"
|
||||
"tp_paused_velocity_zero=%d\n"
|
||||
"tp_paused_position_frozen=%d\n"
|
||||
"tp_resume_rc=%d\n"
|
||||
"tp_resume_cycles=%d\n"
|
||||
"tp_resume_get_pos=%d\n"
|
||||
"tp_resume_done=%d\n"
|
||||
"tp_pause_resume_final_depth=%d\n"
|
||||
"tp_pause_resume_final_pos_near_end=%d\n"
|
||||
"tp_pause_resume_final_pos=%.12g,%.12g,%.12g\n",
|
||||
create_rc,
|
||||
set_cycle_rc,
|
||||
set_pos_rc,
|
||||
set_vmax_rc,
|
||||
set_vlimit_rc,
|
||||
set_amax_rc,
|
||||
set_term_rc,
|
||||
add_line1_rc,
|
||||
add_line2_rc,
|
||||
pause_rc,
|
||||
cycles_before_pause,
|
||||
pause_cycles,
|
||||
pause_get_pos_rc,
|
||||
hold_get_pos_rc,
|
||||
paused_velocity_zero,
|
||||
paused_position_frozen,
|
||||
resume_rc,
|
||||
resume_cycles,
|
||||
final_get_pos_rc,
|
||||
tpIsDone(&tp),
|
||||
tpQueueDepth(&tp),
|
||||
near_end,
|
||||
final_pos.tran.x,
|
||||
final_pos.tran.y,
|
||||
final_pos.tran.z);
|
||||
append(out, size, offset, line);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
char *lctp_run_probe(void)
|
||||
{
|
||||
@@ -1091,6 +1243,7 @@ char *lctp_run_probe(void)
|
||||
append_linear_probe(out, 8192, &offset);
|
||||
append_arc_probe(out, 8192, &offset);
|
||||
append_queued_lines_probe(out, 8192, &offset);
|
||||
append_pause_resume_probe(out, 8192, &offset);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,20 @@ function send(command) {
|
||||
);
|
||||
}
|
||||
|
||||
function sendMotion(command) {
|
||||
return withCString(JSON.stringify(command), (commandPtr) =>
|
||||
assert.equal(runtime._lcmot_write_command_json(commandPtr), 0, command.type),
|
||||
);
|
||||
}
|
||||
|
||||
function status() {
|
||||
return readJson((outPtr, outLen) => runtime._lctask_read_status_json(outPtr, outLen));
|
||||
}
|
||||
|
||||
function motionStatus() {
|
||||
return readJson((outPtr, outLen) => runtime._lcmot_read_status_json(outPtr, outLen));
|
||||
}
|
||||
|
||||
function events() {
|
||||
return readJson((outPtr, outLen) => runtime._lctask_read_events_json(outPtr, outLen)).events;
|
||||
}
|
||||
@@ -70,7 +80,12 @@ assert.equal(
|
||||
0,
|
||||
);
|
||||
|
||||
const program = ["G0 X1 Y2 Z-3 A10 C20", "G1 X2 Y3 Z-4 A11 C21"].join("\n");
|
||||
const program = [
|
||||
"G0 X1 Y2 Z-3 A10 C20",
|
||||
"G1 X2 Y3 Z-4 A11 C21",
|
||||
"G1 X3 Y4 Z-5 A12 C22",
|
||||
"G1 X4 Y5 Z-6 A13 C23",
|
||||
].join("\n");
|
||||
assert.equal(
|
||||
withCString("programs/task-hal-smoke.ngc", (pathPtr) =>
|
||||
withCString(program, (textPtr) => runtime._lctask_stage_file(pathPtr, textPtr)),
|
||||
@@ -85,7 +100,7 @@ assert.equal(
|
||||
send({ type: "EMC_TASK_SET_STATE", state: "ON" });
|
||||
send({ type: "EMC_TASK_SET_MODE", mode: "AUTO" });
|
||||
send({ type: "EMC_TASK_PLAN_RUN", line: 0 });
|
||||
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 2), 0);
|
||||
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
|
||||
|
||||
let snapshot = status();
|
||||
assert.equal(snapshot.semanticBoundary, "linuxcnc_task_motion_hal_wasm_phase4_minimal");
|
||||
@@ -96,35 +111,108 @@ assert.equal(snapshot.nativeTaskReady, false);
|
||||
assert.equal(snapshot.nativeHalSyncReady, false);
|
||||
assert.equal(snapshot.task.state, "ON");
|
||||
assert.equal(snapshot.task.mode, "AUTO");
|
||||
assert.equal(snapshot.task.openedLineCount, 2);
|
||||
assert.equal(snapshot.task.nextProgramLine, 2);
|
||||
assert.equal(snapshot.motionStatus.motion.programLine, 2);
|
||||
assert.equal(snapshot.motionStatus.axis.x, 2);
|
||||
assert.equal(snapshot.motionStatus.axis.z, -4);
|
||||
assert.equal(snapshot.halSnapshot.pins["motion.program-line"].value, 2);
|
||||
assert.equal(snapshot.halSnapshot.pins["joint.0.motor-pos-cmd"].value, 2);
|
||||
assert.equal(snapshot.task.openedLineCount, 4);
|
||||
assert.equal(snapshot.task.nextProgramLine, 1);
|
||||
assert.equal(snapshot.task.interpState, "READING");
|
||||
assert.equal(snapshot.task.interpResumeState, "READING");
|
||||
assert.equal(snapshot.motionStatus.motion.programLine, 1);
|
||||
assert.equal(snapshot.motionStatus.axis.x, 1);
|
||||
assert.equal(snapshot.motionStatus.axis.z, -3);
|
||||
assert.equal(snapshot.halSnapshot.pins["motion.program-line"].value, 1);
|
||||
assert.equal(snapshot.halSnapshot.pins["joint.0.motor-pos-cmd"].value, 1);
|
||||
|
||||
send({ type: "EMC_TASK_PLAN_PAUSE" });
|
||||
snapshot = status();
|
||||
assert.equal(snapshot.task.interpState, "PAUSED");
|
||||
assert.equal(snapshot.task.interpResumeState, "READING");
|
||||
assert.equal(snapshot.task.taskPaused, true);
|
||||
assert.equal(snapshot.task.singleStepping, false);
|
||||
assert.equal(snapshot.motionStatus.motion.paused, true);
|
||||
assert.equal(snapshot.motionStatus.motion.currentVel, 0);
|
||||
const pausedTaskLine = snapshot.task.nextProgramLine;
|
||||
const pausedMotionLine = snapshot.motionStatus.motion.programLine;
|
||||
const pausedMotionId = snapshot.motionStatus.motion.motionId;
|
||||
const pausedQueueDepth = snapshot.motionStatus.commandQueueDepth;
|
||||
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(snapshot.task.nextProgramLine, pausedTaskLine);
|
||||
assert.equal(snapshot.motionStatus.motion.paused, true);
|
||||
assert.equal(snapshot.motionStatus.motion.programLine, pausedMotionLine);
|
||||
assert.equal(snapshot.motionStatus.motion.motionId, pausedMotionId);
|
||||
assert.equal(snapshot.motionStatus.commandQueueDepth, pausedQueueDepth);
|
||||
assert.deepEqual(snapshot.motionStatus.axis, pausedAxis);
|
||||
|
||||
send({ type: "EMC_TASK_PLAN_RESUME" });
|
||||
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(snapshot.task.taskPaused, false);
|
||||
assert.equal(snapshot.motionStatus.motion.paused, false);
|
||||
assert.equal(snapshot.motionStatus.motion.programLine, 2);
|
||||
|
||||
send({ type: "EMC_TASK_PLAN_PAUSE" });
|
||||
send({ type: "EMC_TASK_PLAN_STEP" });
|
||||
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(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(snapshot.motionStatus.motion.programLine, 3);
|
||||
assert.equal(snapshot.motionStatus.motion.motionId, pausedMotionId + 2);
|
||||
|
||||
send({ type: "EMC_TASK_PLAN_RESUME" });
|
||||
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
|
||||
snapshot = status();
|
||||
assert.equal(snapshot.motionStatus.motion.paused, false);
|
||||
assert.equal(snapshot.motionStatus.motion.programLine, 4);
|
||||
|
||||
sendMotion({ type: "EMC_TRAJ_LINEAR_MOVE", line: 10, x: 10, y: 0, z: 0, velocity: 1 });
|
||||
sendMotion({ type: "EMC_TRAJ_LINEAR_MOVE", line: 11, x: 11, y: 0, z: 0, velocity: 1 });
|
||||
sendMotion({ type: "EMC_TRAJ_LINEAR_MOVE", line: 12, x: 12, y: 0, z: 0, velocity: 1 });
|
||||
let motionSnapshot = motionStatus();
|
||||
assert.equal(motionSnapshot.commandQueueDepth, 3);
|
||||
const queuedProgramLine = motionSnapshot.motion.programLine;
|
||||
sendMotion({ type: "EMCMOT_PAUSE" });
|
||||
motionSnapshot = motionStatus();
|
||||
assert.equal(motionSnapshot.motion.paused, true);
|
||||
assert.equal(motionSnapshot.commandQueueDepth, 3);
|
||||
assert.equal(runtime._lcmot_step_servo(1000000, 20), 0);
|
||||
motionSnapshot = motionStatus();
|
||||
assert.equal(motionSnapshot.motion.programLine, queuedProgramLine);
|
||||
assert.equal(motionSnapshot.commandQueueDepth, 3);
|
||||
sendMotion({ type: "EMCMOT_STEP" });
|
||||
assert.equal(runtime._lcmot_step_servo(1000000, 1), 0);
|
||||
motionSnapshot = motionStatus();
|
||||
assert.equal(motionSnapshot.motion.programLine, 10);
|
||||
assert.equal(motionSnapshot.commandQueueDepth, 2);
|
||||
assert.equal(motionSnapshot.motion.paused, true);
|
||||
assert.equal(motionSnapshot.motion.stepping, false);
|
||||
sendMotion({ type: "EMCMOT_RESUME" });
|
||||
assert.equal(runtime._lcmot_step_servo(1000000, 2), 0);
|
||||
motionSnapshot = motionStatus();
|
||||
assert.equal(motionSnapshot.motion.paused, false);
|
||||
assert.equal(motionSnapshot.motion.programLine, 12);
|
||||
assert.equal(motionSnapshot.commandQueueDepth, 0);
|
||||
|
||||
send({ type: "EMC_TASK_PLAN_EXECUTE", mdi: "M428" });
|
||||
assert.equal(runtime._lctask_run_cycles(10000000, 1000000, 1), 0);
|
||||
snapshot = status();
|
||||
assert.equal(snapshot.motionStatus.motion.switchkinsType, 1);
|
||||
assert.equal(snapshot.halSnapshot.pins["motion.switchkins-type"].value, 1);
|
||||
const xBeforeJog = snapshot.motionStatus.axis.x;
|
||||
|
||||
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.motionStatus.axis.x, 2.25);
|
||||
assert.equal(snapshot.motionStatus.axis.x, xBeforeJog + 0.25);
|
||||
assert.equal(snapshot.motionStatus.motion.teleopMode, 1);
|
||||
|
||||
send({ type: "EMC_TASK_ABORT" });
|
||||
@@ -146,3 +234,6 @@ console.log("linuxcnc_task_runtime_smoke=ok");
|
||||
console.log("task_status_from_linuxcnc_runtime=ok");
|
||||
console.log("task_commands_drive_motion_runtime=ok");
|
||||
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");
|
||||
|
||||
@@ -74,6 +74,13 @@ try {
|
||||
"tp_queue_final_depth=0",
|
||||
"tp_queue_final_pos_near_end=1",
|
||||
"tp_queue_final_pos=1,1,0",
|
||||
"tp_pause_rc=0",
|
||||
"tp_resume_rc=0",
|
||||
"tp_paused_velocity_zero=1",
|
||||
"tp_paused_position_frozen=1",
|
||||
"tp_resume_done=1",
|
||||
"tp_pause_resume_final_depth=0",
|
||||
"tp_pause_resume_final_pos_near_end=1",
|
||||
].join("\n"),
|
||||
);
|
||||
} finally {
|
||||
@@ -161,3 +168,4 @@ try {
|
||||
}
|
||||
|
||||
console.log("tp_wasm_node_smoke=ok");
|
||||
console.log("tp_pause_resume_smoke=ok");
|
||||
|
||||
Reference in New Issue
Block a user