Make machine configuration authoritative and restore native checkpoints exactly
This commit is contained in:
@@ -22,6 +22,7 @@ struct sim_linuxcnc_tp {
|
||||
double axis_max[9];
|
||||
double velocity_scale;
|
||||
double jog_scale;
|
||||
double scale_minimum;
|
||||
uint32_t tick;
|
||||
uint32_t last_active_id;
|
||||
int just_completed;
|
||||
@@ -31,6 +32,45 @@ struct sim_linuxcnc_tp {
|
||||
|
||||
static sim_linuxcnc_tp *active_planner;
|
||||
|
||||
/* Same-build checkpoint: TP/TC contain the integration and blend state which
|
||||
cannot be reconstructed by re-enqueuing the remaining geometric path.
|
||||
The queue pointer is removed on export and rebound on restore. All other
|
||||
members of these source structs are values, not process addresses. */
|
||||
typedef struct {
|
||||
uint32_t magic, planner_size, tc_size, capacity;
|
||||
sim_linuxcnc_tp planner;
|
||||
TC_STRUCT queue[TP_DEFAULT_QUEUE_SIZE];
|
||||
} tp_checkpoint;
|
||||
|
||||
uint32_t sim_linuxcnc_tp_checkpoint_size(void) { return (uint32_t)sizeof(tp_checkpoint); }
|
||||
|
||||
int32_t sim_linuxcnc_tp_checkpoint_export(const sim_linuxcnc_tp *planner, uint8_t *output, uint32_t capacity) {
|
||||
if (planner == NULL || !planner->initialized || output == NULL || capacity != sizeof(tp_checkpoint) || planner->tp.queue.size != TP_DEFAULT_QUEUE_SIZE) return -1228;
|
||||
tp_checkpoint *saved = (tp_checkpoint *)output;
|
||||
memset(saved, 0, sizeof(*saved));
|
||||
saved->magic = UINT32_C(0x54504331);
|
||||
saved->planner_size = sizeof(sim_linuxcnc_tp); saved->tc_size = sizeof(TC_STRUCT); saved->capacity = TP_DEFAULT_QUEUE_SIZE;
|
||||
saved->planner = *planner;
|
||||
saved->planner.tp.queue.queue = NULL;
|
||||
memcpy(saved->queue, planner->tp.queue.queue, sizeof(saved->queue));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_checkpoint_restore(sim_linuxcnc_tp *planner, const uint8_t *input, uint32_t length) {
|
||||
if (planner == NULL || !planner->initialized || input == NULL || length != sizeof(tp_checkpoint)) return -1228;
|
||||
const tp_checkpoint *saved = (const tp_checkpoint *)input;
|
||||
const TC_QUEUE_STRUCT *queue = &saved->planner.tp.queue;
|
||||
if (saved->magic != UINT32_C(0x54504331) || saved->planner_size != sizeof(sim_linuxcnc_tp) || saved->tc_size != sizeof(TC_STRUCT) || saved->capacity != TP_DEFAULT_QUEUE_SIZE || saved->planner.initialized != 1 || queue->queue != NULL || queue->size != TP_DEFAULT_QUEUE_SIZE || queue->start < 0 || queue->start >= queue->size || queue->end < 0 || queue->end >= queue->size || queue->_len < 0 || queue->_rlen < 0 || queue->_len > queue->size || queue->_rlen > queue->size - queue->_len) return -1228;
|
||||
if (!isfinite(saved->planner.tp.cycleTime) || saved->planner.tp.cycleTime != planner->tp.cycleTime || memcmp(&saved->planner.config, &planner->config, sizeof(planner->config)) != 0 || memcmp(saved->planner.axis_min, planner->axis_min, sizeof(planner->axis_min)) != 0 || memcmp(saved->planner.axis_max, planner->axis_max, sizeof(planner->axis_max)) != 0 || memcmp(saved->planner.axis_velocity, planner->axis_velocity, sizeof(planner->axis_velocity)) != 0 || memcmp(saved->planner.axis_acceleration, planner->axis_acceleration, sizeof(planner->axis_acceleration)) != 0) return -1229;
|
||||
TC_STRUCT *storage = planner->tp.queue.queue;
|
||||
*planner = saved->planner;
|
||||
planner->tp.queue.queue = storage;
|
||||
memcpy(storage, saved->queue, sizeof(saved->queue));
|
||||
active_planner = planner;
|
||||
tpMotData(&planner->status, &planner->config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void noop_dio(int index, char value) { (void)index; (void)value; }
|
||||
static void noop_aio(int index, double value) { (void)index; (void)value; }
|
||||
static void noop_rotary_unlock(int index, int value) { (void)index; (void)value; }
|
||||
@@ -60,7 +100,7 @@ static void xyzac_line_limits(const sim_linuxcnc_tp *planner, const EmcPose *sta
|
||||
const double distance = has_linear ? sqrt(linear_length) : has_angular ? sqrt(angular_length) : 0.0;
|
||||
if (!(distance > 0.0)) return;
|
||||
if (max_velocity_time > 0.0) *velocity = fmin(*velocity, distance / max_velocity_time);
|
||||
if (max_acceleration_time > 0.0) *acceleration = fmax(*acceleration, distance / max_acceleration_time);
|
||||
if (max_acceleration_time > 0.0) *acceleration = fmin(*acceleration, distance / max_acceleration_time);
|
||||
}
|
||||
|
||||
static void xyzac_circle_limits(const sim_linuxcnc_tp *planner, const EmcPose *start, const EmcPose *end, const PmCartesian *center, const PmCartesian *normal, int turn, double *velocity, double *initial_velocity, double *acceleration) {
|
||||
@@ -95,7 +135,7 @@ static void xyzac_circle_limits(const sim_linuxcnc_tp *planner, const EmcPose *s
|
||||
const double max_acceleration = total_xyz_length / fmax(time_motion_acceleration, time_spiral_acceleration);
|
||||
*velocity = fmin(*velocity, max_velocity);
|
||||
*initial_velocity = max_velocity;
|
||||
*acceleration = fmax(*acceleration, max_acceleration);
|
||||
*acceleration = fmin(*acceleration, max_acceleration);
|
||||
}
|
||||
|
||||
static EmcPose to_emc_pose(const sim_posemath_pose *value) {
|
||||
@@ -143,18 +183,17 @@ int32_t sim_linuxcnc_tp_init(sim_linuxcnc_tp *planner, double cycle_time, double
|
||||
planner->config.arcBlendEnable = 1; planner->config.arcBlendFallbackEnable = 0;
|
||||
planner->config.arcBlendOptDepth = 50; planner->config.arcBlendGapCycles = 4;
|
||||
planner->config.arcBlendRampFreq = 100.0; planner->config.arcBlendTangentKinkRatio = 0.1;
|
||||
// Match xyzac-trt.ini joint limits: the trajectory cap is 35 mm/s, but
|
||||
// XYZ joints are limited to 20 and rotary A/C joints to 30 deg/s. The
|
||||
// upstream TP uses these per-axis callbacks when calculating tangent
|
||||
// velocity and acceleration at a corner.
|
||||
// The caller configures each axis from INI before motion is queued.
|
||||
// Standalone planners use their supplied trajectory limits.
|
||||
for (int axis = 0; axis < 9; ++axis) {
|
||||
planner->axis_velocity[axis] = axis < 3 ? fmin(20.0, velocity_limit) : (axis == 3 || axis == 5) ? fmin(30.0, velocity_limit) : velocity_limit;
|
||||
planner->axis_velocity[axis] = velocity_limit;
|
||||
planner->axis_acceleration[axis] = acceleration_limit;
|
||||
planner->axis_min[axis] = -INFINITY;
|
||||
planner->axis_max[axis] = INFINITY;
|
||||
}
|
||||
planner->velocity_scale = 1.0;
|
||||
planner->jog_scale = 1.0;
|
||||
planner->scale_minimum = 0.0;
|
||||
planner->status.feed_scale = 1.0; planner->status.rapid_scale = 1.0; planner->status.net_feed_scale = 1.0;
|
||||
planner->status.enables_new = FS_ENABLED | FH_ENABLED; planner->status.enables_queued = planner->status.enables_new;
|
||||
planner->status.motionFlag = EMCMOT_MOTION_ENABLE_BIT | EMCMOT_MOTION_COORD_BIT | EMCMOT_MOTION_INPOS_BIT;
|
||||
@@ -182,12 +221,12 @@ int32_t sim_linuxcnc_tp_set_profile(sim_linuxcnc_tp *planner, int profile, doubl
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_feed_override(sim_linuxcnc_tp *planner, double scale) {
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale < 0.0 || scale > 2.0) return -1207;
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale < 0.0 || scale > planner->config.maxFeedScale) return -1207;
|
||||
planner->status.net_feed_scale = scale; planner->status.feed_scale = scale; return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_velocity_scale(sim_linuxcnc_tp *planner, double scale) {
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale < 0.06 || scale > 1.0) return -1211;
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale <= 0.0 || scale < planner->scale_minimum || scale > 1.0) return -1211;
|
||||
active_planner = planner;
|
||||
if (tpSetVlimit(&planner->tp, planner->config.limitVel * scale) != TP_ERR_OK) return -1212;
|
||||
planner->velocity_scale = scale;
|
||||
@@ -195,7 +234,7 @@ int32_t sim_linuxcnc_tp_set_velocity_scale(sim_linuxcnc_tp *planner, double scal
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_jog_scale(sim_linuxcnc_tp *planner, double scale) {
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale < 0.06 || scale > 1.0) return -1213;
|
||||
if (planner == NULL || !planner->initialized || !isfinite(scale) || scale <= 0.0 || scale < planner->scale_minimum || scale > 1.0) return -1213;
|
||||
planner->jog_scale = scale;
|
||||
return 0;
|
||||
}
|
||||
@@ -207,6 +246,36 @@ int32_t sim_linuxcnc_tp_set_axis_limit(sim_linuxcnc_tp *planner, int axis, doubl
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_axis_dynamics(sim_linuxcnc_tp *planner, int axis, double velocity, double acceleration) {
|
||||
if (planner == NULL || !planner->initialized || axis < 0 || axis >= 9 || !isfinite(velocity) || velocity <= 0.0 || !isfinite(acceleration) || acceleration <= 0.0) return -1214;
|
||||
planner->axis_velocity[axis] = velocity;
|
||||
planner->axis_acceleration[axis] = acceleration;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_feed_limit(sim_linuxcnc_tp *planner, double maximum) {
|
||||
if (planner == NULL || !planner->initialized || !isfinite(maximum) || maximum < 1.0) return -1207;
|
||||
planner->config.maxFeedScale = maximum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_scale_minimum(sim_linuxcnc_tp *planner, double minimum) {
|
||||
if (planner == NULL || !planner->initialized || !isfinite(minimum) || minimum <= 0.0 || minimum > 1.0) return -1211;
|
||||
planner->scale_minimum = minimum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_set_blend(sim_linuxcnc_tp *planner, int enable, int fallback, int depth, int gap, double ramp, double kink) {
|
||||
if (planner == NULL || !planner->initialized || (enable != 0 && enable != 1) || (fallback != 0 && fallback != 1) || depth < 1 || gap < 0 || !isfinite(ramp) || ramp <= 0.0 || !isfinite(kink) || kink <= 0.0) return -1205;
|
||||
planner->config.arcBlendEnable = enable;
|
||||
planner->config.arcBlendFallbackEnable = fallback;
|
||||
planner->config.arcBlendOptDepth = depth;
|
||||
planner->config.arcBlendGapCycles = gap;
|
||||
planner->config.arcBlendRampFreq = ramp;
|
||||
planner->config.arcBlendTangentKinkRatio = kink;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sim_linuxcnc_tp_jog(sim_linuxcnc_tp *planner, int axis, int direction, double increment, uint32_t tag) {
|
||||
EmcPose end;
|
||||
double *value;
|
||||
|
||||
Reference in New Issue
Block a user