Complete XYZAC LinuxCNC WASM parity and smooth 3D preview

This commit is contained in:
2026-08-28 06:24:50 +08:00
parent e8fe323aab
commit 1a7995fa9b
181 changed files with 36854 additions and 215 deletions

View File

@@ -9,7 +9,7 @@
/* Keep the public 648-byte object ABI stable; mutable parameter/diagnostic
* state is held in a bounded side table owned by the single Worker writer. */
#define META_SLOTS 4u
#define META_SLOTS 32u
#define NAMED_PARAMETER_CAPACITY 16u
#define NAMED_PARAMETER_LENGTH 32u
#define PENDING_ASSIGNMENTS 32u
@@ -28,11 +28,15 @@ typedef struct interpreter_meta {
int coordinate_system;
int cutter_comp;
int cycle_mode;
int feed_mode;
int coordinate_l20;
int coolant_mode;
int selected_tool;
double tool_length;
sim_posemath_segment last_motion;
int has_motion;
sim_posemath_pose last_output_pose;
int has_output_pose;
uint32_t error_column;
int32_t error_code;
} interpreter_meta;
@@ -92,6 +96,20 @@ static int axis_index(char letter) {
static double *axis_pointer(sim_interpreter_state *state, int index) { return &state->x + index; }
static void machine_pose_for_state(const interpreter_meta *meta, const sim_interpreter_state *state, int machine_coordinates, sim_posemath_pose *pose) {
int coordinate = meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0;
const double *offset = meta->coordinate_offsets[coordinate];
pose->tran.x = state->x + (machine_coordinates ? 0.0 : offset[0]);
pose->tran.y = state->y + (machine_coordinates ? 0.0 : offset[1]);
pose->tran.z = state->z + (machine_coordinates ? 0.0 : offset[2]);
pose->a = state->a + (machine_coordinates ? 0.0 : offset[3]);
pose->b = state->b + (machine_coordinates ? 0.0 : offset[4]);
pose->c = state->c + (machine_coordinates ? 0.0 : offset[5]);
pose->u = state->u + (machine_coordinates ? 0.0 : offset[6]);
pose->v = state->v + (machine_coordinates ? 0.0 : offset[7]);
pose->w = state->w + (machine_coordinates ? 0.0 : offset[8]);
}
static void set_error(sim_interpreter *interpreter, interpreter_meta *meta, int code, uint32_t column) {
if (interpreter != NULL) interpreter->state.status = code;
if (meta != NULL) { meta->error_code = code; meta->error_column = column; }
@@ -166,6 +184,13 @@ static int parameter_lookup(const expression_parser *parser, uint32_t index, dou
static int named_lookup(expression_parser *parser, const char *name, double *value, int create) {
size_t index;
if (name == NULL || name[0] == '\0' || value == NULL) return SIM_INTERP_ERR_PARAMETER;
if (name[0] == '_' && name[2] == '\0') {
int axis = axis_index((char)toupper((unsigned char)name[1]));
if (axis >= 0) {
*value = *axis_pointer((sim_interpreter_state *)&parser->meta->owner->state, axis);
return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
}
}
for (index = 0; index < NAMED_PARAMETER_CAPACITY; ++index) {
if (parser->meta->named[index].used && strcmp(parser->meta->named[index].name, name) == 0) { *value = parser->meta->named[index].value; return SIM_INTERP_OK; }
}
@@ -317,10 +342,12 @@ static int apply_g(sim_interpreter_state *state, interpreter_meta *meta, double
if (code_is(code, 17) || code_is(code, 18) || code_is(code, 19)) { if (++groups[1] > 1) return SIM_INTERP_ERR_STATE; state->plane = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 20) || code_is(code, 21)) { if (++groups[2] > 1) return SIM_INTERP_ERR_STATE; state->units = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 90) || code_is(code, 91)) { if (++groups[3] > 1) return SIM_INTERP_ERR_STATE; state->distance_mode = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 93) || code_is(code, 94)) { if (++groups[6] > 1) return SIM_INTERP_ERR_STATE; if (meta) meta->feed_mode = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 40) || code_is(code, 41) || code_is(code, 42)) { if (++groups[4] > 1) return SIM_INTERP_ERR_STATE; if (meta) meta->cutter_comp = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 43) || code_is(code, 49)) { if (++groups[5] > 1) return SIM_INTERP_ERR_STATE; if (meta && code_is(code, 49)) meta->tool_length = 0.0; return SIM_INTERP_OK; }
if (code_is(code, 80) || (code >= 81.0 && code <= 89.0 && floor(code) == code)) { if (meta) meta->cycle_mode = (int)code; return SIM_INTERP_OK; }
if (code_is(code, 54) || code_is(code, 55) || code_is(code, 56) || code_is(code, 57) || code_is(code, 58) || code_is(code, 59)) { if (meta) meta->coordinate_system = (int)code - 53; return SIM_INTERP_OK; }
if (code_is(code, 53)) return SIM_INTERP_OK;
if (code_is(code, 10)) return SIM_INTERP_OK;
return SIM_INTERP_ERR_UNKNOWN_CODE;
}
@@ -333,6 +360,7 @@ static int apply_m(sim_interpreter_state *state, interpreter_meta *meta, double
if (code_is(code, 8)) { if (meta) meta->coolant_mode = 8; return SIM_INTERP_OK; }
if (code_is(code, 9)) { if (meta) meta->coolant_mode = 0; return SIM_INTERP_OK; }
if (code_is(code, 19)) return SIM_INTERP_OK;
if (code_is(code, 428) || code_is(code, 429) || code_is(code, 430)) return SIM_INTERP_OK;
if (code_is(code, 48) || code_is(code, 49) || code_is(code, 50) || code_is(code, 51) || code_is(code, 52) || code_is(code, 53)) return SIM_INTERP_OK;
if (code >= 62.0 && code <= 68.0 && floor(code) == code) return SIM_INTERP_OK;
if (code_is(code, 70) || code_is(code, 71) || code_is(code, 72) || code_is(code, 73)) return SIM_INTERP_OK;
@@ -358,6 +386,7 @@ static uint64_t state_hash(const sim_interpreter *interpreter) {
parameter_hash ^= fnv1a64((const unsigned char *)&meta->coordinate_system, sizeof(meta->coordinate_system));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->cutter_comp, sizeof(meta->cutter_comp));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->cycle_mode, sizeof(meta->cycle_mode));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->feed_mode, sizeof(meta->feed_mode));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->coolant_mode, sizeof(meta->coolant_mode));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->selected_tool, sizeof(meta->selected_tool));
parameter_hash ^= fnv1a64((const unsigned char *)&meta->tool_length, sizeof(meta->tool_length));
@@ -367,7 +396,7 @@ static uint64_t state_hash(const sim_interpreter *interpreter) {
}
static uint64_t modal_hash(const sim_interpreter *interpreter) {
unsigned char bytes[sizeof(int) * 10 + sizeof(double) * 3]; size_t offset = 0;
unsigned char bytes[sizeof(int) * 11 + sizeof(double) * 3]; size_t offset = 0;
memcpy(bytes + offset, &interpreter->state.units, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &interpreter->state.distance_mode, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &interpreter->state.plane, sizeof(int)); offset += sizeof(int);
@@ -381,6 +410,7 @@ static uint64_t modal_hash(const sim_interpreter *interpreter) {
memcpy(bytes + offset, &meta->coordinate_system, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->cutter_comp, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->cycle_mode, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->feed_mode, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->coolant_mode, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->selected_tool, sizeof(int)); offset += sizeof(int);
memcpy(bytes + offset, &meta->tool_length, sizeof(double)); offset += sizeof(double);
@@ -405,7 +435,7 @@ int sim_interpreter_reset(sim_interpreter *interpreter) {
interpreter_meta *meta;
if (interpreter == NULL) return SIM_INTERP_ERR_ARGUMENT;
memset(interpreter, 0, sizeof(*interpreter)); meta = meta_for(interpreter, 1); if (meta == NULL) return SIM_INTERP_ERR_BUFFER; meta_reset(meta, interpreter);
interpreter->state.units = SIM_INTERP_UNITS_MM; interpreter->state.distance_mode = SIM_INTERP_ABSOLUTE; interpreter->state.plane = 17; interpreter->state.motion_mode = 1; interpreter->state.spindle_mode = 5; interpreter->state.status = SIM_INTERP_OK;
interpreter->state.units = SIM_INTERP_UNITS_MM; interpreter->state.distance_mode = SIM_INTERP_ABSOLUTE; interpreter->state.plane = 17; interpreter->state.motion_mode = 1; interpreter->state.spindle_mode = 5; interpreter->state.status = SIM_INTERP_OK; meta->feed_mode = 94;
return make_canonical(interpreter);
}
@@ -413,9 +443,9 @@ int sim_interpreter_init(sim_interpreter *interpreter) { return sim_interpreter_
int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uint32_t length) {
sim_interpreter_state previous; sim_interpreter_state next; interpreter_meta *meta; expression_parser parser; const char *end;
int groups[6] = {0}, seen_axis[9] = {0}, seen_feed = 0, seen_speed = 0, seen_line = 0, seen_p = 0, seen_r = 0, seen_g10 = 0, result = SIM_INTERP_OK;
int groups[7] = {0}, seen_axis[9] = {0}, seen_feed = 0, seen_speed = 0, seen_line = 0, seen_p = 0, seen_r = 0, seen_l = 0, seen_g10 = 0, seen_g53 = 0, result = SIM_INTERP_OK;
int seen_center[3] = {0};
double axis_values[9] = {0}, center_values[3] = {0}, feed_value = 0.0, speed_value = 0.0, p_value = 0.0, r_value = 0.0;
double axis_values[9] = {0}, center_values[3] = {0}, feed_value = 0.0, speed_value = 0.0, p_value = 0.0, r_value = 0.0, l_value = 0.0;
if (interpreter == NULL || block == NULL || length == 0) return SIM_INTERP_ERR_ARGUMENT;
meta = meta_for(interpreter, 1); if (meta == NULL || !finite_state(&interpreter->state)) return SIM_INTERP_ERR_STATE;
if (interpreter->state.program_end) { set_error(interpreter, meta, SIM_INTERP_ERR_STATE, 1); return SIM_INTERP_ERR_STATE; }
@@ -462,7 +492,8 @@ int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uin
else center_values[center_index] = value;
break;
}
case 'L': case 'Q': case 'D': case 'E': break;
case 'L': if (seen_l++) result = SIM_INTERP_ERR_STATE; else l_value = value; break;
case 'Q': case 'D': case 'E': break;
case 'P': if (seen_p++) result = SIM_INTERP_ERR_STATE; else p_value = value; break;
case 'R': if (seen_r++) result = SIM_INTERP_ERR_STATE; else r_value = value; break;
case 'T': if (value < 0.0 || value > 1001.0 || floor(value) != value) result = SIM_INTERP_ERR_RANGE; else meta->selected_tool = (int)value; break;
@@ -472,6 +503,7 @@ int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uin
break;
}
if (letter == 'G' && code_is(value, 10)) seen_g10 = 1;
if (letter == 'G' && code_is(value, 53)) seen_g53 = 1;
if (result != SIM_INTERP_OK) { set_error(interpreter, meta, result, column); return result; }
}
skip_space(&parser); if (parser.cursor < end && *parser.cursor != ';') { set_error(interpreter, meta, SIM_INTERP_ERR_SYNTAX, (uint32_t)(parser.cursor - block + 1)); return SIM_INTERP_ERR_SYNTAX; }
@@ -482,10 +514,18 @@ int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uin
double axis_value = axis_values[axis]; double *destination = axis_pointer(&next, (int)axis);
if (next.units == SIM_INTERP_UNITS_INCH && axis < 3) axis_value *= 25.4;
if (seen_g10) {
if (!seen_p || p_value < 1.0 || p_value > 9.0 || floor(p_value) != p_value) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, 1); return SIM_INTERP_ERR_PARAMETER; }
meta->coordinate_offsets[(int)p_value - 1][axis] = axis_value;
int coordinate;
if (!seen_p || p_value < 0.0 || p_value > 9.0 || floor(p_value) != p_value || !seen_l || (!code_is(l_value, 2) && !code_is(l_value, 20))) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, 1); return SIM_INTERP_ERR_PARAMETER; }
coordinate = p_value == 0.0 ? (meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0) : (int)p_value - 1;
if (code_is(l_value, 20)) {
meta->coordinate_offsets[coordinate][axis] = *axis_pointer(&previous, (int)axis) - axis_value;
if (p_value == 0.0) meta->coordinate_l20 = 1;
*destination = axis_value;
} else {
meta->coordinate_offsets[coordinate][axis] = axis_value;
}
} else if (next.distance_mode == SIM_INTERP_INCREMENTAL) *destination += axis_value;
else *destination = axis_value + meta->coordinate_offsets[meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0][axis];
else *destination = axis_value + (seen_g53 || meta->coordinate_l20 ? 0.0 : meta->coordinate_offsets[meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0][axis]);
}
}
if (seen_g10 && !seen_axis[0] && !seen_axis[1] && !seen_axis[2]) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, 1); return SIM_INTERP_ERR_PARAMETER; }
@@ -502,25 +542,54 @@ int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uin
int has_axis_motion = 0;
int has_center = seen_center[0] || seen_center[1] || seen_center[2];
for (axis = 0; axis < 9; ++axis) if (seen_axis[axis]) { has_axis_motion = 1; break; }
if ((has_axis_motion || has_center) && next.motion_mode >= 0 && next.motion_mode <= 3) {
if (!seen_g10 && (has_axis_motion || has_center) && next.motion_mode >= 0 && next.motion_mode <= 3) {
sim_posemath_segment *segment = &meta->last_motion;
memset(segment, 0, sizeof(*segment));
segment->start.tran.x = previous.x; segment->start.tran.y = previous.y; segment->start.tran.z = previous.z;
segment->start.a = previous.a; segment->start.b = previous.b; segment->start.c = previous.c;
segment->start.u = previous.u; segment->start.v = previous.v; segment->start.w = previous.w;
segment->end.tran.x = next.x; segment->end.tran.y = next.y; segment->end.tran.z = next.z;
segment->end.a = next.a; segment->end.b = next.b; segment->end.c = next.c;
segment->end.u = next.u; segment->end.v = next.v; segment->end.w = next.w;
segment->velocity = next.feed;
if (meta->has_output_pose) segment->start = meta->last_output_pose;
else machine_pose_for_state(meta, &previous, seen_g53, &segment->start);
machine_pose_for_state(meta, &next, seen_g53, &segment->end);
segment->velocity = next.feed / 60.0;
segment->acceleration = 0.0;
segment->motion_type = next.motion_mode >= 2 ? SIM_POSEMATH_CIRCULAR : SIM_POSEMATH_LINEAR;
segment->turn = next.motion_mode == 2 ? -1 : 1;
segment->center.x = previous.x; segment->center.y = previous.y; segment->center.z = previous.z;
if (next.motion_mode >= 2 && seen_p && (p_value < 1.0 || p_value > 1000000.0 || floor(p_value) != p_value)) { set_error(interpreter, meta, SIM_INTERP_ERR_RANGE, 1); return SIM_INTERP_ERR_RANGE; }
segment->turn = (next.motion_mode == 2 ? -1 : 1) * (next.motion_mode >= 2 && seen_p ? (int)p_value : 1);
segment->center.x = segment->start.tran.x; segment->center.y = segment->start.tran.y; segment->center.z = segment->start.tran.z;
if (next.units == SIM_INTERP_UNITS_INCH) for (axis = 0; axis < 3; ++axis) center_values[axis] *= 25.4;
segment->center.x += center_values[0]; segment->center.y += center_values[1]; segment->center.z += center_values[2];
meta->last_output_pose = segment->end;
meta->has_output_pose = 1;
if (next.plane == 18) segment->normal.y = 1.0;
else if (next.plane == 19) segment->normal.x = 1.0;
else segment->normal.z = 1.0;
if (meta->feed_mode == 93) {
const double dx = segment->end.tran.x - segment->start.tran.x;
const double dy = segment->end.tran.y - segment->start.tran.y;
const double dz = segment->end.tran.z - segment->start.tran.z;
const double da = segment->end.a - segment->start.a;
const double db = segment->end.b - segment->start.b;
const double dc = segment->end.c - segment->start.c;
const double du = segment->end.u - segment->start.u;
const double dv = segment->end.v - segment->start.v;
const double dw = segment->end.w - segment->start.w;
double path_length = sqrt(dx * dx + dy * dy + dz * dz + da * da + db * db + dc * dc + du * du + dv * dv + dw * dw);
if (next.motion_mode >= 2) {
const double sx = segment->start.tran.x - segment->center.x;
const double sy = segment->start.tran.y - segment->center.y;
const double sz = segment->start.tran.z - segment->center.z;
const double ex = segment->end.tran.x - segment->center.x;
const double ey = segment->end.tran.y - segment->center.y;
const double ez = segment->end.tran.z - segment->center.z;
const double radius = sqrt(sx * sx + sy * sy + sz * sz);
const double dot = sx * ex + sy * ey + sz * ez;
const double cross_normal = segment->normal.x * (sy * ez - sz * ey) + segment->normal.y * (sz * ex - sx * ez) + segment->normal.z * (sx * ey - sy * ex);
double angle = fabs(atan2(cross_normal, dot));
if (angle <= 1e-12) angle = 2.0 * 3.14159265358979323846;
angle += 2.0 * 3.14159265358979323846 * (fabs((double)segment->turn) - 1.0);
path_length = sqrt((radius * angle) * (radius * angle) + dz * dz + da * da + db * db + dc * dc + du * du + dv * dv + dw * dw);
}
if (!isfinite(path_length) || path_length <= 0.0 || next.feed <= 0.0) { set_error(interpreter, meta, SIM_INTERP_ERR_RANGE, 1); return SIM_INTERP_ERR_RANGE; }
segment->velocity = path_length * next.feed / 60.0;
}
meta->has_motion = 1;
}
}