*/
/*
- * This code is a loose implementation of Kramer, Proctor and Messina's canonical
+ * This code is a loose implementation of Kramer, Proctor and Messina's canonical
* machining functions as described in the NIST RS274/NGC v3
*
* The canonical machine is the layer between the Gcode parser and the motion control
* cm_set_motion_state() - adjusts active model pointer as well
*/
uint8_t cm_get_combined_state() {
- if (cm.cycle_state == CYCLE_OFF) { cm.combined_state = cm.machine_state;}
- else if (cm.cycle_state == CYCLE_PROBE) { cm.combined_state = COMBINED_PROBE;}
- else if (cm.cycle_state == CYCLE_HOMING) { cm.combined_state = COMBINED_HOMING;}
- else if (cm.cycle_state == CYCLE_JOG) { cm.combined_state = COMBINED_JOG;}
+ if (cm.cycle_state == CYCLE_OFF) cm.combined_state = cm.machine_state;
+ else if (cm.cycle_state == CYCLE_PROBE) cm.combined_state = COMBINED_PROBE;
+ else if (cm.cycle_state == CYCLE_HOMING) cm.combined_state = COMBINED_HOMING;
+ else if (cm.cycle_state == CYCLE_JOG) cm.combined_state = COMBINED_JOG;
else {
if (cm.motion_state == MOTION_RUN) cm.combined_state = COMBINED_RUN;
if (cm.motion_state == MOTION_HOLD) cm.combined_state = COMBINED_HOLD;
}
- if (cm.machine_state == MACHINE_SHUTDOWN) { cm.combined_state = COMBINED_SHUTDOWN;}
+
+ if (cm.machine_state == MACHINE_SHUTDOWN) cm.combined_state = COMBINED_SHUTDOWN;
return cm.combined_state;
}
uint8_t cm_get_hold_state() {return cm.hold_state;}
uint8_t cm_get_homing_state() {return cm.homing_state;}
+
void cm_set_motion_state(uint8_t motion_state) {
cm.motion_state = motion_state;
switch (motion_state) {
- case (MOTION_STOP): { ACTIVE_MODEL = MODEL; break; }
- case (MOTION_RUN): { ACTIVE_MODEL = RUNTIME; break; }
- case (MOTION_HOLD): { ACTIVE_MODEL = RUNTIME; break; }
+ case (MOTION_STOP): ACTIVE_MODEL = MODEL; break;
+ case (MOTION_RUN): ACTIVE_MODEL = RUNTIME; break;
+ case (MOTION_HOLD): ACTIVE_MODEL = RUNTIME; break;
}
}
-/* These getters and setters will work on any gm model with inputs:
- * MODEL (GCodeState_t *)&cm.gm // absolute pointer from canonical machine gm model
- * PLANNER (GCodeState_t *)&bf->gm // relative to buffer *bf is currently pointing to
- * RUNTIME (GCodeState_t *)&mr.gm // absolute pointer from runtime mm struct
- * ACTIVE_MODEL cm.am // active model pointer is maintained by state management
+
+/* These getters and setters will work on any gm model with inputs:
+ * MODEL (GCodeState_t *)&cm.gm // absolute pointer from canonical machine gm model
+ * PLANNER (GCodeState_t *)&bf->gm // relative to buffer *bf is currently pointing to
+ * RUNTIME (GCodeState_t *)&mr.gm // absolute pointer from runtime mm struct
+ * ACTIVE_MODEL cm.am // active model pointer is maintained by state management
*/
-uint32_t cm_get_linenum(GCodeState_t *gcode_state) { return gcode_state->linenum;}
-uint8_t cm_get_motion_mode(GCodeState_t *gcode_state) { return gcode_state->motion_mode;}
-uint8_t cm_get_coord_system(GCodeState_t *gcode_state) { return gcode_state->coord_system;}
-uint8_t cm_get_units_mode(GCodeState_t *gcode_state) { return gcode_state->units_mode;}
-uint8_t cm_get_select_plane(GCodeState_t *gcode_state) { return gcode_state->select_plane;}
-uint8_t cm_get_path_control(GCodeState_t *gcode_state) { return gcode_state->path_control;}
-uint8_t cm_get_distance_mode(GCodeState_t *gcode_state) { return gcode_state->distance_mode;}
-uint8_t cm_get_feed_rate_mode(GCodeState_t *gcode_state) { return gcode_state->feed_rate_mode;}
-uint8_t cm_get_tool(GCodeState_t *gcode_state) { return gcode_state->tool;}
-uint8_t cm_get_spindle_mode(GCodeState_t *gcode_state) { return gcode_state->spindle_mode;}
-uint8_t cm_get_block_delete_switch() { return cm.gmx.block_delete_switch;}
-uint8_t cm_get_runtime_busy() { return mp_get_runtime_busy();}
-
-float cm_get_feed_rate(GCodeState_t *gcode_state) { return gcode_state->feed_rate;}
-
-void cm_set_motion_mode(GCodeState_t *gcode_state, uint8_t motion_mode) { gcode_state->motion_mode = motion_mode;}
-void cm_set_spindle_mode(GCodeState_t *gcode_state, uint8_t spindle_mode) { gcode_state->spindle_mode = spindle_mode;}
-void cm_set_spindle_speed_parameter(GCodeState_t *gcode_state, float speed) { gcode_state->spindle_speed = speed;}
-void cm_set_tool_number(GCodeState_t *gcode_state, uint8_t tool) { gcode_state->tool = tool;}
+uint32_t cm_get_linenum(GCodeState_t *gcode_state) {return gcode_state->linenum;}
+uint8_t cm_get_motion_mode(GCodeState_t *gcode_state) {return gcode_state->motion_mode;}
+uint8_t cm_get_coord_system(GCodeState_t *gcode_state) {return gcode_state->coord_system;}
+uint8_t cm_get_units_mode(GCodeState_t *gcode_state) {return gcode_state->units_mode;}
+uint8_t cm_get_select_plane(GCodeState_t *gcode_state) {return gcode_state->select_plane;}
+uint8_t cm_get_path_control(GCodeState_t *gcode_state) {return gcode_state->path_control;}
+uint8_t cm_get_distance_mode(GCodeState_t *gcode_state) {return gcode_state->distance_mode;}
+uint8_t cm_get_feed_rate_mode(GCodeState_t *gcode_state) {return gcode_state->feed_rate_mode;}
+uint8_t cm_get_tool(GCodeState_t *gcode_state) {return gcode_state->tool;}
+uint8_t cm_get_spindle_mode(GCodeState_t *gcode_state) {return gcode_state->spindle_mode;}
+uint8_t cm_get_block_delete_switch() {return cm.gmx.block_delete_switch;}
+uint8_t cm_get_runtime_busy() {return mp_get_runtime_busy();}
+
+float cm_get_feed_rate(GCodeState_t *gcode_state) {return gcode_state->feed_rate;}
+
+void cm_set_motion_mode(GCodeState_t *gcode_state, uint8_t motion_mode) {gcode_state->motion_mode = motion_mode;}
+void cm_set_spindle_mode(GCodeState_t *gcode_state, uint8_t spindle_mode) {gcode_state->spindle_mode = spindle_mode;}
+void cm_set_spindle_speed_parameter(GCodeState_t *gcode_state, float speed) {gcode_state->spindle_speed = speed;}
+void cm_set_tool_number(GCodeState_t *gcode_state, uint8_t tool) {gcode_state->tool = tool;}
void cm_set_absolute_override(GCodeState_t *gcode_state, uint8_t absolute_override) {
gcode_state->absolute_override = absolute_override;
*/
stat_t cm_deferred_write_callback() {
if ((cm.cycle_state == CYCLE_OFF) && (cm.deferred_write_flag == true)) {
- if (!usart_rx_empty()) return STAT_OK; // don't write back if serial RX is not empty
+ if (!usart_rx_empty()) return STAT_OK; // don't write back if serial RX is not empty
cm.deferred_write_flag = false;
nvObj_t nv;
for (uint8_t i=1; i<=COORDS; i++)
sprintf((char *)nv.token, "g%2d%c", 53+i, ("xyzabc")[j]);
nv.index = nv_get_index((const char_t *)"", nv.token);
nv.value = cm.offset[i][j];
- nv_persist(&nv); // Note: only writes values that have changed
+ nv_persist(&nv); // Note: only writes values that have changed
}
}
* - computation and application of axis modes as so:
*
* DISABLED - Incoming value is ignored. Target value is not changed
- * ENABLED - Convert axis values to canonical format and store as target
+ * ENABLED - Convert axis values to canonical format and store as target
* INHIBITED - Same processing as ENABLED, but axis will not actually be run
- * RADIUS - ABC axis value is provided in Gcode block in linear units
+ * RADIUS - ABC axis value is provided in Gcode block in linear units
* - Target is set to degrees based on axis' Radius value
* - Radius mode is only processed for ABC axes. Application to XYZ is ignored.
*
// ALDEN: This shows up in avr-gcc 4.7.0 and avr-libc 1.8.0
static float _calc_ABC(uint8_t axis, float target[], float flag[]) {
if ((cm.a[axis].axis_mode == AXIS_STANDARD) || (cm.a[axis].axis_mode == AXIS_INHIBITED))
- return(target[axis]); // no mm conversion - it's in degrees
+ return target[axis]; // no mm conversion - it's in degrees
return _to_millimeters(target[axis]) * 360 / (2 * M_PI * cm.a[axis].radius);
}
/// canonical_machine_init() - Config init cfg_init() must have been run beforehand
void canonical_machine_init() {
// If you can assume all memory has been zeroed by a hard reset you don't need this code:
- // memset(&cm, 0, sizeof(cm)); // do not reset canonicalMachineSingleton once it's been initialized
- memset(&cm.gm, 0, sizeof(GCodeState_t)); // clear all values, pointers and status
+ memset(&cm.gm, 0, sizeof(GCodeState_t)); // clear all values, pointers and status
memset(&cm.gn, 0, sizeof(GCodeInput_t));
memset(&cm.gf, 0, sizeof(GCodeInput_t));
- canonical_machine_init_assertions(); // establish assertions
- ACTIVE_MODEL = MODEL; // setup initial Gcode model pointer
+ canonical_machine_init_assertions(); // establish assertions
+ ACTIVE_MODEL = MODEL; // setup initial Gcode model pointer
// set gcode defaults
cm_set_units_mode(cm.units_mode);
cm_select_plane(cm.select_plane);
cm_set_path_control(cm.path_control);
cm_set_distance_mode(cm.distance_mode);
- cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE);// always the default
+ cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // always the default
cm.gmx.block_delete_switch = true;
* canonical_machine_init_assertions()
* canonical_machine_test_assertions() - test assertions, return error code if violation exists
*/
-
void canonical_machine_init_assertions() {
cm.magic_start = MAGICNUM;
cm.magic_end = MAGICNUM;
/*
* cm_soft_alarm() - alarm state; send an exception report and stop processing input
- * cm_clear() - clear soft alarm
+ * cm_clear() - clear soft alarm
* cm_hard_alarm() - alarm state; send an exception report and shut down machine
*/
stat_t cm_soft_alarm(stat_t status) {
- rpt_exception(status); // send alarm message
+ rpt_exception(status); // send alarm message
cm.machine_state = MACHINE_ALARM;
return status; // NB: More efficient than inlining rpt_exception() call.
}
stat_t cm_hard_alarm(stat_t status) {
// stop the motors and the spindle
- stepper_init(); // hard stop
+ stepper_init(); // hard stop
cm_spindle_control(SPINDLE_OFF);
rpt_exception(status); // send shutdown message
cm.machine_state = MACHINE_SHUTDOWN;
stat_t cm_set_units_mode(uint8_t mode) {
cm.gm.units_mode = mode; // 0 = inches, 1 = mm.
- return(STAT_OK);
+ return STAT_OK;
}
stat_t cm_set_distance_mode(uint8_t mode) {
- cm.gm.distance_mode = mode; // 0 = absolute mode, 1 = incremental
+ cm.gm.distance_mode = mode; // 0 = absolute mode, 1 = incremental
return STAT_OK;
}
cm.gm.coord_system = coord_system;
float value[AXES] = { (float)coord_system,0,0,0,0,0 }; // pass coordinate system in value[0] element
- mp_queue_command(_exec_offset, value, value); // second vector (flags) is not used, so fake it
+ mp_queue_command(_exec_offset, value, value); // second vector (flags) is not used, so fake it
return STAT_OK;
}
static void _exec_offset(float *value, float *flag) {
- uint8_t coord_system = ((uint8_t)value[0]); // coordinate system is passed in value[0] element
+ uint8_t coord_system = ((uint8_t)value[0]); // coordinate system is passed in value[0] element
float offsets[AXES];
for (uint8_t axis = AXIS_X; axis < AXES; axis++)
offsets[axis] = cm.offset[coord_system][axis] + (cm.gmx.origin_offset[axis] * cm.gmx.origin_offset_enable);
mp_set_runtime_work_offset(offsets);
- cm_set_work_offsets(MODEL); // set work offsets in the Gcode model
+ cm_set_work_offsets(MODEL); // set work offsets in the Gcode model
}
* This is useful for setting origins for homing, probing, and other operations.
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!!
+ * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* More specifically, do not call this function if there are any moves in the planner or
for (uint8_t axis = AXIS_X; axis < AXES; axis++)
if (fp_TRUE(flag[axis])) {
value[axis] = _to_millimeters(origin[axis]);
- cm.gmx.position[axis] = value[axis]; // set model position
+ cm.gmx.position[axis] = value[axis]; // set model position
cm.gm.target[axis] = value[axis]; // reset model target
- mp_set_planner_position(axis, value[axis]); // set mm position
+ mp_set_planner_position(axis, value[axis]); // set mm position
}
mp_queue_command(_exec_absolute_origin, value, flag);
/*
- * cm_set_origin_offsets() - G92
- * cm_reset_origin_offsets() - G92.1
- * cm_suspend_origin_offsets() - G92.2
+ * cm_set_origin_offsets() - G92
+ * cm_reset_origin_offsets() - G92.1
+ * cm_suspend_origin_offsets() - G92.2
* cm_resume_origin_offsets() - G92.3
*
* G92's behave according to NIST 3.5.18 & LinuxCNC G92
// now pass the offset to the callback - setting the coordinate system also applies the offsets
float value[AXES] = { (float)cm.gm.coord_system,0,0,0,0,0 }; // pass coordinate system in value[0] element
- mp_queue_command(_exec_offset, value, value); // second vector is not used
+ mp_queue_command(_exec_offset, value, value); // second vector is not used
return STAT_OK;
}
/*****************************
* Free Space Motion (4.3.4) *
*****************************/
-/*
- * cm_straight_traverse() - G0 linear rapid
- */
+/// G0 linear rapid
stat_t cm_straight_traverse(float target[], float flags[]) {
cm.gm.motion_mode = MOTION_MODE_STRAIGHT_TRAVERSE;
cm_set_model_target(target, flags);
// prep and plan the move
cm_set_work_offsets(&cm.gm); // capture the fully resolved offsets to the state
- cm_cycle_start(); // required for homing & other cycles
- mp_aline(&cm.gm); // send the move to the planner
+ cm_cycle_start(); // required for homing & other cycles
+ mp_aline(&cm.gm); // send the move to the planner
cm_finalize_move();
return STAT_OK;
}
stat_t cm_goto_g28_position(float target[], float flags[]) {
cm_set_absolute_override(MODEL, true);
- cm_straight_traverse(target, flags); // move through intermediate point, or skip
- while (mp_get_planner_buffers_available() == 0); // make sure you have an available buffer
- float f[] = {1,1,1,1,1,1};
- return cm_straight_traverse(cm.gmx.g28_position, f);// execute actual stored move
+ cm_straight_traverse(target, flags); // move through intermediate point, or skip
+ while (mp_get_planner_buffers_available() == 0); // make sure you have an available buffer
+ float f[] = {1, 1, 1, 1, 1, 1};
+ return cm_straight_traverse(cm.gmx.g28_position, f); // execute actual stored move
}
stat_t cm_goto_g30_position(float target[], float flags[]) {
cm_set_absolute_override(MODEL, true);
- cm_straight_traverse(target, flags); // move through intermediate point, or skip
- while (mp_get_planner_buffers_available() == 0); // make sure you have an available buffer
- float f[] = {1,1,1,1,1,1};
- return cm_straight_traverse(cm.gmx.g30_position, f);// execute actual stored move
+ cm_straight_traverse(target, flags); // move through intermediate point, or skip
+ while (mp_get_planner_buffers_available() == 0); // make sure you have an available buffer
+ float f[] = {1, 1, 1, 1, 1, 1};
+ return cm_straight_traverse(cm.gmx.g30_position, f); // execute actual stored move
}
/*
* cm_set_feed_rate_mode() - G93, G94 (affects MODEL only)
*
- * INVERSE_TIME_MODE = 0, // G93
- * UNITS_PER_MINUTE_MODE, // G94
+ * INVERSE_TIME_MODE = 0, // G93
+ * UNITS_PER_MINUTE_MODE, // G94
* UNITS_PER_REVOLUTION_MODE // G95 (unimplemented)
*/
stat_t cm_set_feed_rate_mode(uint8_t mode) {
}
-/*
- * cm_set_path_control() - G61, G61.1, G64 (affects MODEL only)
- */
+/// G61, G61.1, G64 (affects MODEL only)
stat_t cm_set_path_control(uint8_t mode) {
cm.gm.path_control = mode;
return STAT_OK;
* cm_arc_feed() - SEE plan_arc.c(pp)
*/
-/*
- * cm_dwell() - G4, P parameter (seconds)
- */
+
+/// G4, P parameter (seconds)
stat_t cm_dwell(float seconds) {
cm.gm.parameter = seconds;
mp_dwell(seconds);
}
-/*
- * cm_straight_feed() - G1
- */
+/// G1
stat_t cm_straight_feed(float target[], float flags[]) {
// trap zero feed rate condition
if ((cm.gm.feed_rate_mode != INVERSE_TIME_MODE) && (fp_ZERO(cm.gm.feed_rate)))
// prep and plan the move
cm_set_work_offsets(&cm.gm); // capture the fully resolved offsets to the state
- cm_cycle_start(); // required for homing & other cycles
- status = mp_aline(&cm.gm); // send the move to the planner
+ cm_cycle_start(); // required for homing & other cycles
+ status = mp_aline(&cm.gm); // send the move to the planner
cm_finalize_move();
return status;
}
**************************/
/*
* cm_select_tool() - T parameter
- * _exec_select_tool() - execution callback
+ * _exec_select_tool() - execution callback
*
* cm_change_tool() - M6 (This might become a complete tool change cycle)
- * _exec_change_tool() - execution callback
+ * _exec_change_tool() - execution callback
*
* Note: These functions don't actually do anything for now, and there's a bug
* where T and M in different blocks don;t work correctly
*/
stat_t cm_select_tool(uint8_t tool_select) {
- float value[AXES] = { (float)tool_select,0,0,0,0,0 };
+ float value[AXES] = {(float)tool_select, 0, 0, 0, 0, 0};
mp_queue_command(_exec_select_tool, value, value);
return STAT_OK;
}
stat_t cm_change_tool(uint8_t tool_change) {
- float value[AXES] = { (float)cm.gm.tool_select,0,0,0,0,0 };
+ float value[AXES] = {(float)cm.gm.tool_select, 0, 0, 0, 0, 0};
mp_queue_command(_exec_change_tool, value, value);
return STAT_OK;
}
* cm_flood_coolant_control() - M8, M9
*/
stat_t cm_mist_coolant_control(uint8_t mist_coolant) {
- float value[AXES] = { (float)mist_coolant,0,0,0,0,0 };
+ float value[AXES] = {(float)mist_coolant, 0, 0, 0, 0, 0};
mp_queue_command(_exec_mist_coolant_control, value, value);
return STAT_OK;
}
static void _exec_mist_coolant_control(float *value, float *flag) {
cm.gm.mist_coolant = (uint8_t)value[0];
- if (cm.gm.mist_coolant == true)
- gpio_set_bit_on(MIST_COOLANT_BIT); // if
- gpio_set_bit_off(MIST_COOLANT_BIT); // else
+ if (cm.gm.mist_coolant == true) gpio_set_bit_on(MIST_COOLANT_BIT);
+ else gpio_set_bit_off(MIST_COOLANT_BIT);
}
stat_t cm_flood_coolant_control(uint8_t flood_coolant) {
- float value[AXES] = { (float)flood_coolant,0,0,0,0,0 };
+ float value[AXES] = {(float)flood_coolant, 0, 0, 0, 0, 0};
mp_queue_command(_exec_flood_coolant_control, value, value);
return STAT_OK;
}
* Override enables are kind of a mess in Gcode. This is an attempt to sort them out.
* See http://www.linuxcnc.org/docs/2.4/html/gcode_main.html#sec:M50:-Feed-Override
*/
-stat_t cm_override_enables(uint8_t flag) { // M48, M49
+stat_t cm_override_enables(uint8_t flag) { // M48, M49
cm.gmx.feed_rate_override_enable = flag;
cm.gmx.traverse_override_enable = flag;
cm.gmx.spindle_override_enable = flag;
}
-stat_t cm_feed_rate_override_enable(uint8_t flag) { // M50
+stat_t cm_feed_rate_override_enable(uint8_t flag) { // M50
if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter))
cm.gmx.feed_rate_override_enable = false;
else cm.gmx.feed_rate_override_enable = true;
}
-stat_t cm_feed_rate_override_factor(uint8_t flag) { // M50.1
+stat_t cm_feed_rate_override_factor(uint8_t flag) { // M50.1
cm.gmx.feed_rate_override_enable = flag;
cm.gmx.feed_rate_override_factor = cm.gn.parameter;
return STAT_OK;
}
-stat_t cm_traverse_override_enable(uint8_t flag) { // M50.2
+stat_t cm_traverse_override_enable(uint8_t flag) { // M50.2
if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter))
cm.gmx.traverse_override_enable = false;
else cm.gmx.traverse_override_enable = true;
}
-stat_t cm_traverse_override_factor(uint8_t flag) { // M51
+stat_t cm_traverse_override_factor(uint8_t flag) { // M51
cm.gmx.traverse_override_enable = flag;
cm.gmx.traverse_override_factor = cm.gn.parameter;
return STAT_OK;
* It is extended beyond the NIST spec to handle various situations.
*
* _exec_program_finalize()
- * cm_cycle_start() (no Gcode) Do a cycle start right now
- * cm_cycle_end() (no Gcode) Do a cycle end right now
- * cm_feedhold() (no Gcode) Initiate a feedhold right now
- * cm_program_stop() (M0, M60) Queue a program stop
- * cm_optional_program_stop() (M1)
- * cm_program_end() (M2, M30)
+ * cm_cycle_start() (no Gcode) Do a cycle start right now
+ * cm_cycle_end() (no Gcode) Do a cycle end right now
+ * cm_feedhold() (no Gcode) Initiate a feedhold right now
+ * cm_program_stop() (M0, M60) Queue a program stop
+ * cm_optional_program_stop() (M1)
+ * cm_program_end() (M2, M30)
* cm_machine_ready() puts machine into a READY state
*
* cm_program_stop and cm_optional_program_stop are synchronous Gcode
*
* A queue flush request received during motion should be ignored but not reset
* A queue flush request received during a feedhold should be deferred until
- * the feedhold enters a HOLD state (i.e. until deceleration is complete)
+ * the feedhold enters a HOLD state (i.e. until deceleration is complete)
* A queue flush request received during a motion stop should be honored
*
* A cycle start request received during motion should be ignored and reset
* A cycle start request received during a feedhold should be deferred until
- * the feedhold enters a HOLD state (i.e. until deceleration is complete)
- * If a queue flush request is also present the queue flush should be done first
+ * the feedhold enters a HOLD state (i.e. until deceleration is complete)
+ * If a queue flush request is also present the queue flush should be done first
* A cycle start request received during a motion stop should be honored and
- * should start to run anything in the planner queue
+ * should start to run anything in the planner queue
*/
void cm_request_feedhold() {cm.feedhold_requested = true;}
if (cm.feedhold_requested == true) {
if ((cm.motion_state == MOTION_RUN) && (cm.hold_state == FEEDHOLD_OFF)) {
cm_set_motion_state(MOTION_HOLD);
- cm.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution
+ cm.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution
}
+
cm.feedhold_requested = false;
}
}
}
- bool feedhold_processing = // added feedhold processing lockout from omco fork
+ bool feedhold_processing = // added feedhold processing lockout from omco fork
cm.hold_state == FEEDHOLD_SYNC ||
cm.hold_state == FEEDHOLD_PLAN ||
cm.hold_state == FEEDHOLD_DECEL;
rx_request_rx_report();
// Note: The following uses low-level mp calls for absolute position.
- // It could also use cm_get_absolute_position(RUNTIME, axis);
+ // It could also use cm_get_absolute_position(RUNTIME, axis);
for (uint8_t axis = AXIS_X; axis < AXES; axis++)
cm_set_position(axis, mp_get_runtime_absolute_position(axis)); // set mm from mr
- float value[AXES] = { (float)MACHINE_PROGRAM_STOP, 0,0,0,0,0 };
+ float value[AXES] = {(float)MACHINE_PROGRAM_STOP, 0,0,0,0,0};
_exec_program_finalize(value, value); // finalize now, not later
return STAT_OK;
* cm_cycle_start()
* cm_cycle_end()
* cm_program_stop() - M0
- * cm_optional_program_stop() - M1
- * cm_program_end() - M2, M30
+ * cm_optional_program_stop() - M1
+ * cm_program_end() - M2, M30
*
* cm_program_end() implements M2 and M30
* The END behaviors are defined by NIST 3.6.1 are:
* 2. Selected plane is set to default plane ($gpl) (instead of setting it to G54)
* 3. Distance mode is set to MODE_ABSOLUTE (like G90)
* 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94)
- * 5. Not implemented
+ * 5. Not implemented
* 6. Not implemented
* 7. The spindle is stopped (like M5)
* 8. Motion mode is canceled like G80 (not set to G1)
cm.machine_state = (uint8_t)value[0];
cm_set_motion_state(MOTION_STOP);
if (cm.cycle_state == CYCLE_MACHINING)
- cm.cycle_state = CYCLE_OFF; // don't end cycle if homing, probing, etc.
+ cm.cycle_state = CYCLE_OFF; // don't end cycle if homing, probing, etc.
- cm.hold_state = FEEDHOLD_OFF; // end feedhold (if in feed hold)
- cm.cycle_start_requested = false; // cancel any pending cycle start request
- mp_zero_segment_velocity(); // for reporting purposes
+ cm.hold_state = FEEDHOLD_OFF; // end feedhold (if in feed hold)
+ cm.cycle_start_requested = false; // cancel any pending cycle start request
+ mp_zero_segment_velocity(); // for reporting purposes
// perform the following resets if it's a program END
if (cm.machine_state == MACHINE_PROGRAM_END) {
- cm_reset_origin_offsets(); // G92.1 - we do G91.1 instead of G92.2
+ cm_reset_origin_offsets(); // G92.1 - we do G91.1 instead of G92.2
cm_set_coord_system(cm.coord_system); // reset to default coordinate system
cm_select_plane(cm.select_plane); // reset to default arc plane
cm_set_distance_mode(cm.distance_mode);
- cm_spindle_control(SPINDLE_OFF); // M5
- cm_flood_coolant_control(false); // M9
+ cm_spindle_control(SPINDLE_OFF); // M5
+ cm_flood_coolant_control(false); // M9
cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // G94
cm_set_motion_mode(MODEL, MOTION_MODE_CANCEL_MOTION_MODE);
}
- sr_request_status_report(SR_IMMEDIATE_REQUEST); // request a final status report (not unfiltered)
+ sr_request_status_report(SR_IMMEDIATE_REQUEST); // request a final status report (not unfiltered)
}
void cm_cycle_start() {
cm.machine_state = MACHINE_CYCLE;
- if (cm.cycle_state == CYCLE_OFF) { // don't (re)start homing, probe or other canned cycles
+ if (cm.cycle_state == CYCLE_OFF) { // don't (re)start homing, probe or other canned cycles
cm.cycle_state = CYCLE_MACHINING;
- qr_init_queue_report(); // clear queue reporting buffer counts
+ qr_init_queue_report(); // clear queue reporting buffer counts
}
}
static const char msg_units0[] PROGMEM = " in"; // used by generic print functions
static const char msg_units1[] PROGMEM = " mm";
static const char msg_units2[] PROGMEM = " deg";
-static const char *const msg_units[] PROGMEM = { msg_units0, msg_units1, msg_units2 };
+static const char *const msg_units[] PROGMEM = {msg_units0, msg_units1, msg_units2};
#define DEGREE_INDEX 2
static const char msg_am00[] PROGMEM = "[disabled]";
static const char msg_am01[] PROGMEM = "[standard]";
static const char msg_am02[] PROGMEM = "[inhibited]";
static const char msg_am03[] PROGMEM = "[radius]";
-static const char *const msg_am[] PROGMEM = { msg_am00, msg_am01, msg_am02, msg_am03};
+static const char *const msg_am[] PROGMEM = {msg_am00, msg_am01, msg_am02, msg_am03};
static const char msg_g20[] PROGMEM = "G20 - inches mode";
static const char msg_g21[] PROGMEM = "G21 - millimeter mode";
-static const char *const msg_unit[] PROGMEM = { msg_g20, msg_g21 };
+static const char *const msg_unit[] PROGMEM = {msg_g20, msg_g21};
static const char msg_stat0[] PROGMEM = "Initializing"; // combined state (stat) uses this array
static const char msg_stat1[] PROGMEM = "Ready";
static const char msg_stat9[] PROGMEM = "Homing";
static const char msg_stat10[] PROGMEM = "Jog";
static const char msg_stat11[] PROGMEM = "Shutdown";
-static const char *const msg_stat[] PROGMEM = { msg_stat0, msg_stat1, msg_stat2, msg_stat3,
- msg_stat4, msg_stat5, msg_stat6, msg_stat7,
- msg_stat8, msg_stat9, msg_stat10, msg_stat11 };
+static const char *const msg_stat[] PROGMEM = {
+ msg_stat0, msg_stat1, msg_stat2, msg_stat3,
+ msg_stat4, msg_stat5, msg_stat6, msg_stat7,
+ msg_stat8, msg_stat9, msg_stat10, msg_stat11
+};
static const char msg_macs0[] PROGMEM = "Initializing";
static const char msg_macs1[] PROGMEM = "Ready";
static const char msg_macs4[] PROGMEM = "End";
static const char msg_macs5[] PROGMEM = "Cycle";
static const char msg_macs6[] PROGMEM = "Shutdown";
-static const char *const msg_macs[] PROGMEM = { msg_macs0, msg_macs1, msg_macs2, msg_macs3,
- msg_macs4, msg_macs5, msg_macs6 };
+static const char *const msg_macs[] PROGMEM = {
+ msg_macs0, msg_macs1, msg_macs2, msg_macs3,
+ msg_macs4, msg_macs5, msg_macs6
+};
static const char msg_cycs0[] PROGMEM = "Off";
static const char msg_cycs1[] PROGMEM = "Machining";
static const char msg_cycs2[] PROGMEM = "Probe";
static const char msg_cycs3[] PROGMEM = "Homing";
static const char msg_cycs4[] PROGMEM = "Jog";
-static const char *const msg_cycs[] PROGMEM = { msg_cycs0, msg_cycs1, msg_cycs2, msg_cycs3, msg_cycs4 };
+static const char *const msg_cycs[] PROGMEM = {msg_cycs0, msg_cycs1, msg_cycs2, msg_cycs3, msg_cycs4};
static const char msg_mots0[] PROGMEM = "Stop";
static const char msg_mots1[] PROGMEM = "Run";
static const char msg_mots2[] PROGMEM = "Hold";
-static const char *const msg_mots[] PROGMEM = { msg_mots0, msg_mots1, msg_mots2 };
+static const char *const msg_mots[] PROGMEM = {msg_mots0, msg_mots1, msg_mots2};
static const char msg_hold0[] PROGMEM = "Off";
static const char msg_hold1[] PROGMEM = "Sync";
static const char msg_hold3[] PROGMEM = "Decel";
static const char msg_hold4[] PROGMEM = "Hold";
static const char msg_hold5[] PROGMEM = "End Hold";
-static const char *const msg_hold[] PROGMEM = { msg_hold0, msg_hold1, msg_hold2, msg_hold3,
- msg_hold4, msg_hold5 };
+static const char *const msg_hold[] PROGMEM = {msg_hold0, msg_hold1, msg_hold2, msg_hold3, msg_hold4, msg_hold5};
static const char msg_home0[] PROGMEM = "Not Homed";
static const char msg_home1[] PROGMEM = "Homed";
static const char msg_home2[] PROGMEM = "Homing";
-static const char *const msg_home[] PROGMEM = { msg_home0, msg_home1, msg_home2 };
+static const char *const msg_home[] PROGMEM = {msg_home0, msg_home1, msg_home2};
static const char msg_g53[] PROGMEM = "G53 - machine coordinate system";
static const char msg_g54[] PROGMEM = "G54 - coordinate system 1";
static const char msg_g57[] PROGMEM = "G57 - coordinate system 4";
static const char msg_g58[] PROGMEM = "G58 - coordinate system 5";
static const char msg_g59[] PROGMEM = "G59 - coordinate system 6";
-static const char *const msg_coor[] PROGMEM = { msg_g53, msg_g54, msg_g55, msg_g56, msg_g57, msg_g58, msg_g59 };
+static const char *const msg_coor[] PROGMEM = {msg_g53, msg_g54, msg_g55, msg_g56, msg_g57, msg_g58, msg_g59};
static const char msg_g00[] PROGMEM = "G0 - linear traverse (seek)";
static const char msg_g01[] PROGMEM = "G1 - linear feed";
static const char msg_g02[] PROGMEM = "G2 - clockwise arc feed";
static const char msg_g03[] PROGMEM = "G3 - counter clockwise arc feed";
static const char msg_g80[] PROGMEM = "G80 - cancel motion mode (none active)";
-static const char *const msg_momo[] PROGMEM = { msg_g00, msg_g01, msg_g02, msg_g03, msg_g80 };
+static const char *const msg_momo[] PROGMEM = {msg_g00, msg_g01, msg_g02, msg_g03, msg_g80};
static const char msg_g17[] PROGMEM = "G17 - XY plane";
static const char msg_g18[] PROGMEM = "G18 - XZ plane";
static const char msg_g19[] PROGMEM = "G19 - YZ plane";
-static const char *const msg_plan[] PROGMEM = { msg_g17, msg_g18, msg_g19 };
+static const char *const msg_plan[] PROGMEM = {msg_g17, msg_g18, msg_g19};
static const char msg_g61[] PROGMEM = "G61 - exact path mode";
static const char msg_g6a[] PROGMEM = "G61.1 - exact stop mode";
static const char msg_g64[] PROGMEM = "G64 - continuous mode";
-static const char *const msg_path[] PROGMEM = { msg_g61, msg_g6a, msg_g64 };
+static const char *const msg_path[] PROGMEM = {msg_g61, msg_g6a, msg_g64};
static const char msg_g90[] PROGMEM = "G90 - absolute distance mode";
static const char msg_g91[] PROGMEM = "G91 - incremental distance mode";
-static const char *const msg_dist[] PROGMEM = { msg_g90, msg_g91 };
+static const char *const msg_dist[] PROGMEM = {msg_g90, msg_g91};
static const char msg_g93[] PROGMEM = "G93 - inverse time mode";
static const char msg_g94[] PROGMEM = "G94 - units-per-minute mode (i.e. feedrate mode)";
static const char msg_g95[] PROGMEM = "G95 - units-per-revolution mode";
-static const char *const msg_frmo[] PROGMEM = { msg_g93, msg_g94, msg_g95 };
+static const char *const msg_frmo[] PROGMEM = {msg_g93, msg_g94, msg_g95};
#else
#endif // __TEXT_MODE
-/***** AXIS HELPERS *****************************************************************
- * cm_get_axis_char() - return ASCII char for axis given the axis number
- * _get_axis() - return axis number or -1 if NA
- * _get_axis_type() - return 0 -f axis is linear, 1 if rotary, -1 if NA
- */
-
+/// return ASCII char for axis given the axis number
char_t cm_get_axis_char(const int8_t axis) {
char_t axis_char[] = "XYZABC";
if ((axis < 0) || (axis > AXES)) return ' ';
}
+/// return axis number or -1 if NA
static int8_t _get_axis(const index_t index) {
char_t *ptr;
char_t tmp[TOKEN_LEN+1];
char_t axes[] = {"xyzabc"};
- strncpy_P(tmp, cfgArray[index].token, TOKEN_LEN); // kind of a hack. Looks for an axis
+ strncpy_P(tmp, cfgArray[index].token, TOKEN_LEN); // kind of a hack. Looks for an axis
if ((ptr = strchr(axes, tmp[0])) == 0) { // character in the 0 and 3 positions
- if ((ptr = strchr(axes, tmp[3])) == 0) // to accommodate 'xam' and 'g54x' styles
+ if ((ptr = strchr(axes, tmp[3])) == 0) // to accommodate 'xam' and 'g54x' styles
return -1;
}
}
+/// return 0 -f axis is linear, 1 if rotary, -1 if NA
static int8_t _get_axis_type(const index_t index) {
int8_t axis = _get_axis(index);
if (axis >= AXIS_A) return 1;
stat_t _get_msg_helper(nvObj_t *nv, const char *const msg_array[], uint8_t value) {
nv->value = (float)value;
nv->valuetype = TYPE_INTEGER;
- return(nv_copy_string(nv, (const char_t *)GET_TEXT_ITEM(msg_array, value)));
+ return nv_copy_string(nv, (const char_t *)GET_TEXT_ITEM(msg_array, value));
}
-stat_t cm_get_stat(nvObj_t *nv) {return(_get_msg_helper(nv, msg_stat, cm_get_combined_state()));}
-stat_t cm_get_macs(nvObj_t *nv) {return(_get_msg_helper(nv, msg_macs, cm_get_machine_state()));}
-stat_t cm_get_cycs(nvObj_t *nv) {return(_get_msg_helper(nv, msg_cycs, cm_get_cycle_state()));}
-stat_t cm_get_mots(nvObj_t *nv) {return(_get_msg_helper(nv, msg_mots, cm_get_motion_state()));}
-stat_t cm_get_hold(nvObj_t *nv) {return(_get_msg_helper(nv, msg_hold, cm_get_hold_state()));}
-stat_t cm_get_home(nvObj_t *nv) {return(_get_msg_helper(nv, msg_home, cm_get_homing_state()));}
+stat_t cm_get_stat(nvObj_t *nv) {return _get_msg_helper(nv, msg_stat, cm_get_combined_state());}
+stat_t cm_get_macs(nvObj_t *nv) {return _get_msg_helper(nv, msg_macs, cm_get_machine_state());}
+stat_t cm_get_cycs(nvObj_t *nv) {return _get_msg_helper(nv, msg_cycs, cm_get_cycle_state());}
+stat_t cm_get_mots(nvObj_t *nv) {return _get_msg_helper(nv, msg_mots, cm_get_motion_state());}
+stat_t cm_get_hold(nvObj_t *nv) {return _get_msg_helper(nv, msg_hold, cm_get_hold_state());}
+stat_t cm_get_home(nvObj_t *nv) {return _get_msg_helper(nv, msg_home, cm_get_homing_state());}
-stat_t cm_get_unit(nvObj_t *nv) {return(_get_msg_helper(nv, msg_unit, cm_get_units_mode(ACTIVE_MODEL)));}
-stat_t cm_get_coor(nvObj_t *nv) {return(_get_msg_helper(nv, msg_coor, cm_get_coord_system(ACTIVE_MODEL)));}
-stat_t cm_get_momo(nvObj_t *nv) {return(_get_msg_helper(nv, msg_momo, cm_get_motion_mode(ACTIVE_MODEL)));}
-stat_t cm_get_plan(nvObj_t *nv) {return(_get_msg_helper(nv, msg_plan, cm_get_select_plane(ACTIVE_MODEL)));}
-stat_t cm_get_path(nvObj_t *nv) {return(_get_msg_helper(nv, msg_path, cm_get_path_control(ACTIVE_MODEL)));}
-stat_t cm_get_dist(nvObj_t *nv) {return(_get_msg_helper(nv, msg_dist, cm_get_distance_mode(ACTIVE_MODEL)));}
-stat_t cm_get_frmo(nvObj_t *nv) {return(_get_msg_helper(nv, msg_frmo, cm_get_feed_rate_mode(ACTIVE_MODEL)));}
+stat_t cm_get_unit(nvObj_t *nv) {return _get_msg_helper(nv, msg_unit, cm_get_units_mode(ACTIVE_MODEL));}
+stat_t cm_get_coor(nvObj_t *nv) {return _get_msg_helper(nv, msg_coor, cm_get_coord_system(ACTIVE_MODEL));}
+stat_t cm_get_momo(nvObj_t *nv) {return _get_msg_helper(nv, msg_momo, cm_get_motion_mode(ACTIVE_MODEL));}
+stat_t cm_get_plan(nvObj_t *nv) {return _get_msg_helper(nv, msg_plan, cm_get_select_plane(ACTIVE_MODEL));}
+stat_t cm_get_path(nvObj_t *nv) {return _get_msg_helper(nv, msg_path, cm_get_path_control(ACTIVE_MODEL));}
+stat_t cm_get_dist(nvObj_t *nv) {return _get_msg_helper(nv, msg_dist, cm_get_distance_mode(ACTIVE_MODEL));}
+stat_t cm_get_frmo(nvObj_t *nv) {return _get_msg_helper(nv, msg_frmo, cm_get_feed_rate_mode(ACTIVE_MODEL));}
stat_t cm_get_toolv(nvObj_t *nv) {
*/
stat_t cm_get_am(nvObj_t *nv) {
get_ui8(nv);
- return(_get_msg_helper(nv, msg_am, nv->value));
+ return _get_msg_helper(nv, msg_am, nv->value);
}
} else if (nv->value > AXIS_MODE_MAX_ROTARY) return STAT_INPUT_EXCEEDS_MAX_VALUE;
set_ui8(nv);
- return(STAT_OK);
+ return STAT_OK;
}
/**** Jerk functions
if (nv->value > JERK_MULTIPLIER) nv->value /= JERK_MULTIPLIER;
set_flu(nv);
cm_set_axis_jerk(_get_axis(nv->index), nv->value);
- return(STAT_OK);
+ return STAT_OK;
}
stat_t cm_set_xjh(nvObj_t *nv) {
if (nv->value > JERK_MULTIPLIER) nv->value /= JERK_MULTIPLIER;
set_flu(nv);
- return(STAT_OK);
+ return STAT_OK;
}
/*
return STAT_OK;
}
-/***********************************************************************************
- * TEXT MODE SUPPORT
- * Functions to print variables from the cfgArray table
- ***********************************************************************************/
-
#ifdef __TEXT_MODE
-/* model state print functions */
-
+// model state print functions
const char fmt_vel[] PROGMEM = "Velocity:%17.3f%s/min\n";
const char fmt_feed[] PROGMEM = "Feed rate:%16.3f%s/min\n";
const char fmt_line[] PROGMEM = "Line number:%10.0f\n";
void cm_print_ma(nvObj_t *nv) {text_print_flt_units(nv, fmt_ma, GET_UNITS(ACTIVE_MODEL));}
void cm_print_ms(nvObj_t *nv) {text_print_flt_units(nv, fmt_ms, GET_UNITS(ACTIVE_MODEL));}
-/*
- * axis print functions
- *
- * _print_axis_ui8() - helper to print an integer value with no units
- * _print_axis_flt() - helper to print a floating point linear value in prevailing units
- * _print_pos_helper()
- *
- * cm_print_am()
- * cm_print_fr()
- * cm_print_vm()
- * cm_print_tm()
- * cm_print_tn()
- * cm_print_jm()
- * cm_print_jh()
- * cm_print_jd()
- * cm_print_ra()
- * cm_print_sn()
- * cm_print_sx()
- * cm_print_lv()
- * cm_print_lb()
- * cm_print_zb()
- *
- * cm_print_pos() - print position with unit displays for MM or Inches
- * cm_print_mpo() - print position with fixed unit display - always in Degrees or MM
- */
-
+// axis print functions
static const char fmt_Xam[] PROGMEM = "[%s%s] %s axis mode%18d %s\n";
static const char fmt_Xfr[] PROGMEM = "[%s%s] %s feedrate maximum%11.0f%s/min\n";
static const char fmt_Xvm[] PROGMEM = "[%s%s] %s velocity maximum%11.0f%s/min\n";
static const char fmt_cpos[] PROGMEM = "[%s%s] %s %s position%18.3f%s\n";
+/// helper to print an integer value with no units
static void _print_axis_ui8(nvObj_t *nv, const char *format) {
fprintf_P(stderr, format, nv->group, nv->token, nv->group, (uint8_t)nv->value);
}
+/// helper to print a floating point linear value in prevailing units
static void _print_axis_flt(nvObj_t *nv, const char *format) {
char *units;
if (_get_axis_type(nv->index) == 0) // linear
}
+/// print position with unit displays for MM or Inches
static void _print_pos(nvObj_t *nv, const char *format, uint8_t units) {
char axes[] = {"XYZABC"};
uint8_t axis = _get_axis(nv->index);
void cm_print_cpos(nvObj_t *nv) {_print_axis_coord_flt(nv, fmt_cpos);}
void cm_print_pos(nvObj_t *nv) {_print_pos(nv, fmt_pos, cm_get_units_mode(MODEL));}
+/// print position with fixed unit display - always in Degrees or MM
void cm_print_mpo(nvObj_t *nv) {_print_pos(nv, fmt_mpo, MILLIMETERS);}
void cm_print_ofs(nvObj_t *nv) {_print_pos(nv, fmt_ofs, MILLIMETERS);}
#include "config.h"
-/* Defines, Macros, and Assorted Parameters */
-
-#define MODEL (GCodeState_t *)&cm.gm // absolute pointer from canonical machine gm model
-#define PLANNER (GCodeState_t *)&bf->gm // relative to buffer *bf is currently pointing to
+#define MODEL (GCodeState_t *)&cm.gm // absolute pointer from canonical machine gm model
+#define PLANNER (GCodeState_t *)&bf->gm // relative to buffer *bf is currently pointing to
#define RUNTIME (GCodeState_t *)&mr.gm // absolute pointer from runtime mm struct
#define ACTIVE_MODEL cm.am // active model pointer is maintained by state management
#define JOGGING_START_VELOCITY ((float)10.0)
#define DISABLE_SOFT_LIMIT (-1000000)
+
/*****************************************************************************
* GCODE MODEL - The following GCodeModel/GCodeInput structs are used:
*
* machine and do not need to be passed further down.
*
* - gn is used by the gcode interpreter and is re-initialized for each
- * gcode block.It accepts data in the new gcode block in the formats
+ * gcode block.It accepts data in the new gcode block in the formats
* present in the block (pre-normalized forms). During initialization
* some state elements are necessarily restored from gm.
*
* G92 offsets. cfg has the power-on / reset gcode default values, but gm has
* the operating state for the values (which may have changed).
*/
-typedef struct GCodeState { // Gcode model state - used by model, planning and runtime
- uint32_t linenum; // Gcode block line number
- uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81,
- // G82, G83 G84, G85, G86, G87, G88, G89
- float target[AXES]; // XYZABC where the move should go
- float work_offset[AXES]; // offset from the work coordinate system (for reporting only)
-
- float move_time; // optimal time for move given axis constraints
- float minimum_time; // minimum time possible for move given axis constraints
- float feed_rate; // F - normalized to millimeters/minute or in inverse time mode
-
- float spindle_speed; // in RPM
- float parameter; // P - parameter used for dwell time in seconds, G10 coord select...
-
- uint8_t feed_rate_mode; // See cmFeedRateMode for settings
- uint8_t select_plane; // G17,G18,G19 - values to set plane to
- uint8_t units_mode; // G20,G21 - 0=inches (G20), 1 = mm (G21)
- uint8_t coord_system; // G54-G59 - select coordinate system 1-9
- uint8_t absolute_override; // G53 TRUE = move using machine coordinates - this block only (G53)
- uint8_t path_control; // G61... EXACT_PATH, EXACT_STOP, CONTINUOUS
- uint8_t distance_mode; // G91 0=use absolute coords(G90), 1=incremental movement
- uint8_t arc_distance_mode; // G91.1 0=use absolute coords(G90), 1=incremental movement
- uint8_t tool; // M6 tool change - moves "tool_select" to "tool"
- uint8_t tool_select; // T value - T sets this value
- uint8_t mist_coolant; // TRUE = mist on (M7), FALSE = off (M9)
- uint8_t flood_coolant; // TRUE = flood on (M8), FALSE = off (M9)
- uint8_t spindle_mode; // 0=OFF (M5), 1=CW (M3), 2=CCW (M4)
-
+typedef struct GCodeState { // Gcode model state - used by model, planning and runtime
+ uint32_t linenum; // Gcode block line number
+ uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81,
+ // G82, G83 G84, G85, G86, G87, G88, G89
+ float target[AXES]; // XYZABC where the move should go
+ float work_offset[AXES]; // offset from the work coordinate system (for reporting only)
+
+ float move_time; // optimal time for move given axis constraints
+ float minimum_time; // minimum time possible for move given axis constraints
+ float feed_rate; // F - normalized to millimeters/minute or in inverse time mode
+
+ float spindle_speed; // in RPM
+ float parameter; // P - parameter used for dwell time in seconds, G10 coord select...
+
+ uint8_t feed_rate_mode; // See cmFeedRateMode for settings
+ uint8_t select_plane; // G17,G18,G19 - values to set plane to
+ uint8_t units_mode; // G20,G21 - 0=inches (G20), 1 = mm (G21)
+ uint8_t coord_system; // G54-G59 - select coordinate system 1-9
+ uint8_t absolute_override; // G53 TRUE = move using machine coordinates - this block only (G53)
+ uint8_t path_control; // G61... EXACT_PATH, EXACT_STOP, CONTINUOUS
+ uint8_t distance_mode; // G91 0=use absolute coords(G90), 1=incremental movement
+ uint8_t arc_distance_mode; // G91.1 0=use absolute coords(G90), 1=incremental movement
+ uint8_t tool; // M6 tool change - moves "tool_select" to "tool"
+ uint8_t tool_select; // T value - T sets this value
+ uint8_t mist_coolant; // TRUE = mist on (M7), FALSE = off (M9)
+ uint8_t flood_coolant; // TRUE = flood on (M8), FALSE = off (M9)
+ uint8_t spindle_mode; // 0=OFF (M5), 1=CW (M3), 2=CCW (M4)
} GCodeState_t;
-typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used by model and arcs
- uint16_t magic_start; // magic number to test memory integrity
- uint8_t next_action; // handles G modal group 1 moves & non-modals
- uint8_t program_flow; // used only by the gcode_parser
- float position[AXES]; // XYZABC model position (Note: not used in gn or gf)
- float origin_offset[AXES]; // XYZABC G92 offsets (Note: not used in gn or gf)
- float g28_position[AXES]; // XYZABC stored machine position for G28
- float g30_position[AXES]; // XYZABC stored machine position for G30
+typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used by model and arcs
+ uint16_t magic_start; // magic number to test memory integrity
+ uint8_t next_action; // handles G modal group 1 moves & non-modals
+ uint8_t program_flow; // used only by the gcode_parser
- float feed_rate_override_factor; // 1.0000 x F feed rate. Go up or down from there
- float traverse_override_factor; // 1.0000 x traverse rate. Go down from there
- uint8_t feed_rate_override_enable; // TRUE = overrides enabled (M48), F=(M49)
- uint8_t traverse_override_enable; // TRUE = traverse override enabled
- uint8_t l_word; // L word - used by G10s
+ float position[AXES]; // XYZABC model position (Note: not used in gn or gf)
+ float origin_offset[AXES]; // XYZABC G92 offsets (Note: not used in gn or gf)
+ float g28_position[AXES]; // XYZABC stored machine position for G28
+ float g30_position[AXES]; // XYZABC stored machine position for G30
- uint8_t origin_offset_enable; // G92 offsets enabled/disabled. 0=disabled, 1=enabled
- uint8_t block_delete_switch; // set true to enable block deletes (true is default)
+ float feed_rate_override_factor; // 1.0000 x F feed rate. Go up or down from there
+ float traverse_override_factor; // 1.0000 x traverse rate. Go down from there
+ uint8_t feed_rate_override_enable; // TRUE = overrides enabled (M48), F=(M49)
+ uint8_t traverse_override_enable; // TRUE = traverse override enabled
+ uint8_t l_word; // L word - used by G10s
- float spindle_override_factor; // 1.0000 x S spindle speed. Go up or down from there
- uint8_t spindle_override_enable; // TRUE = override enabled
+ uint8_t origin_offset_enable; // G92 offsets enabled/disabled. 0=disabled, 1=enabled
+ uint8_t block_delete_switch; // set true to enable block deletes (true is default)
-// unimplemented gcode parameters
-// float cutter_radius; // D - cutter radius compensation (0 is off)
-// float cutter_length; // H - cutter length compensation (0 is off)
+ float spindle_override_factor; // 1.0000 x S spindle speed. Go up or down from there
+ uint8_t spindle_override_enable; // TRUE = override enabled
- uint16_t magic_end;
+ // unimplemented gcode parameters
+ // float cutter_radius; // D - cutter radius compensation (0 is off)
+ // float cutter_length; // H - cutter length compensation (0 is off)
+ uint16_t magic_end;
} GCodeStateX_t;
-typedef struct GCodeInput { // Gcode model inputs - meaning depends on context
- uint8_t next_action; // handles G modal group 1 moves & non-modals
- uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81,
- // G82, G83 G84, G85, G86, G87, G88, G89
- uint8_t program_flow; // used only by the gcode_parser
- uint32_t linenum; // N word or autoincrement in the model
-
- float target[AXES]; // XYZABC where the move should go
-
- float feed_rate; // F - normalized to millimeters/minute
- float feed_rate_override_factor; // 1.0000 x F feed rate. Go up or down from there
- float traverse_override_factor; // 1.0000 x traverse rate. Go down from there
- uint8_t feed_rate_mode; // See cmFeedRateMode for settings
- uint8_t feed_rate_override_enable; // TRUE = overrides enabled (M48), F=(M49)
- uint8_t traverse_override_enable; // TRUE = traverse override enabled
- uint8_t override_enables; // enables for feed and spoindle (GN/GF only)
- uint8_t l_word; // L word - used by G10s
-
- uint8_t select_plane; // G17,G18,G19 - values to set plane to
- uint8_t units_mode; // G20,G21 - 0=inches (G20), 1 = mm (G21)
- uint8_t coord_system; // G54-G59 - select coordinate system 1-9
- uint8_t absolute_override; // G53 TRUE = move using machine coordinates - this block only (G53)
- uint8_t origin_offset_mode; // G92...TRUE=in origin offset mode
- uint8_t path_control; // G61... EXACT_PATH, EXACT_STOP, CONTINUOUS
- uint8_t distance_mode; // G91 0=use absolute coords(G90), 1=incremental movement
- uint8_t arc_distance_mode; // G91.1 0=use absolute coords(G90), 1=incremental movement
-
- uint8_t tool; // Tool after T and M6 (tool_select and tool_change)
- uint8_t tool_select; // T value - T sets this value
- uint8_t tool_change; // M6 tool change flag - moves "tool_select" to "tool"
- uint8_t mist_coolant; // TRUE = mist on (M7), FALSE = off (M9)
- uint8_t flood_coolant; // TRUE = flood on (M8), FALSE = off (M9)
-
- uint8_t spindle_mode; // 0=OFF (M5), 1=CW (M3), 2=CCW (M4)
- float spindle_speed; // in RPM
- float spindle_override_factor; // 1.0000 x S spindle speed. Go up or down from there
- uint8_t spindle_override_enable; // TRUE = override enabled
-
- float parameter; // P - parameter used for dwell time in seconds, G10 coord select...
- float arc_radius; // R - radius value in arc radius mode
- float arc_offset[3]; // IJK - used by arc commands
-
-// unimplemented gcode parameters
-// float cutter_radius; // D - cutter radius compensation (0 is off)
-// float cutter_length; // H - cutter length compensation (0 is off)
+typedef struct GCodeInput { // Gcode model inputs - meaning depends on context
+ uint8_t next_action; // handles G modal group 1 moves & non-modals
+ uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81,
+ // G82, G83 G84, G85, G86, G87, G88, G89
+ uint8_t program_flow; // used only by the gcode_parser
+ uint32_t linenum; // N word or autoincrement in the model
+
+ float target[AXES]; // XYZABC where the move should go
+
+ float feed_rate; // F - normalized to millimeters/minute
+ float feed_rate_override_factor; // 1.0000 x F feed rate. Go up or down from there
+ float traverse_override_factor; // 1.0000 x traverse rate. Go down from there
+ uint8_t feed_rate_mode; // See cmFeedRateMode for settings
+ uint8_t feed_rate_override_enable; // TRUE = overrides enabled (M48), F=(M49)
+ uint8_t traverse_override_enable; // TRUE = traverse override enabled
+ uint8_t override_enables; // enables for feed and spoindle (GN/GF only)
+ uint8_t l_word; // L word - used by G10s
+
+ uint8_t select_plane; // G17,G18,G19 - values to set plane to
+ uint8_t units_mode; // G20,G21 - 0=inches (G20), 1 = mm (G21)
+ uint8_t coord_system; // G54-G59 - select coordinate system 1-9
+ uint8_t absolute_override; // G53 TRUE = move using machine coordinates - this block only (G53)
+ uint8_t origin_offset_mode; // G92...TRUE=in origin offset mode
+ uint8_t path_control; // G61... EXACT_PATH, EXACT_STOP, CONTINUOUS
+ uint8_t distance_mode; // G91 0=use absolute coords(G90), 1=incremental movement
+ uint8_t arc_distance_mode; // G91.1 0=use absolute coords(G90), 1=incremental movement
+
+ uint8_t tool; // Tool after T and M6 (tool_select and tool_change)
+ uint8_t tool_select; // T value - T sets this value
+ uint8_t tool_change; // M6 tool change flag - moves "tool_select" to "tool"
+ uint8_t mist_coolant; // TRUE = mist on (M7), FALSE = off (M9)
+ uint8_t flood_coolant; // TRUE = flood on (M8), FALSE = off (M9)
+
+ uint8_t spindle_mode; // 0=OFF (M5), 1=CW (M3), 2=CCW (M4)
+ float spindle_speed; // in RPM
+ float spindle_override_factor; // 1.0000 x S spindle speed. Go up or down from there
+ uint8_t spindle_override_enable; // TRUE = override enabled
+
+ float parameter; // P - parameter used for dwell time in seconds, G10 coord select...
+ float arc_radius; // R - radius value in arc radius mode
+ float arc_offset[3]; // IJK - used by arc commands
+
+ // unimplemented gcode parameters
+ // float cutter_radius; // D - cutter radius compensation (0 is off)
+ // float cutter_length; // H - cutter length compensation (0 is off)
} GCodeInput_t;
-/*****************************************************************************
- * CANONICAL MACHINE STRUCTURES
- */
typedef struct cmAxis {
- uint8_t axis_mode; // see tgAxisMode in gcode.h
- float feedrate_max; // max velocity in mm/min or deg/min
- float velocity_max; // max velocity in mm/min or deg/min
- float travel_max; // max work envelope for soft limits
- float travel_min; // min work envelope for soft limits
- float jerk_max; // max jerk (Jm) in mm/min^3 divided by 1 million
- float jerk_homing; // homing jerk (Jh) in mm/min^3 divided by 1 million
- float recip_jerk; // stored reciprocal of current jerk value - has the million in it
- float junction_dev; // aka cornering delta
- float radius; // radius in mm for rotary axis modes
- float search_velocity; // homing search velocity
- float latch_velocity; // homing latch velocity
- float latch_backoff; // backoff from switches prior to homing latch movement
- float zero_backoff; // backoff from switches for machine zero
+ uint8_t axis_mode; // see tgAxisMode in gcode.h
+ float feedrate_max; // max velocity in mm/min or deg/min
+ float velocity_max; // max velocity in mm/min or deg/min
+ float travel_max; // max work envelope for soft limits
+ float travel_min; // min work envelope for soft limits
+ float jerk_max; // max jerk (Jm) in mm/min^3 divided by 1 million
+ float jerk_homing; // homing jerk (Jh) in mm/min^3 divided by 1 million
+ float recip_jerk; // stored reciprocal of current jerk value - has the million in it
+ float junction_dev; // aka cornering delta
+ float radius; // radius in mm for rotary axis modes
+ float search_velocity; // homing search velocity
+ float latch_velocity; // homing latch velocity
+ float latch_backoff; // backoff from switches prior to homing latch movement
+ float zero_backoff; // backoff from switches for machine zero
} cfgAxis_t;
-typedef struct cmSingleton { // struct to manage cm globals and cycles
- magic_t magic_start; // magic number to test memory integrity
-
- /**** Config variables (PUBLIC) ****/
-
- // system group settings
- float junction_acceleration; // centripetal acceleration max for cornering
- float chordal_tolerance; // arc chordal accuracy setting in mm
- uint8_t soft_limit_enable;
-
- // hidden system settings
- float min_segment_len; // line drawing resolution in mm
- float arc_segment_len; // arc drawing resolution in mm
- float estd_segment_usec; // approximate segment time in microseconds
-
- // gcode power-on default settings - defaults are not the same as the gm state
- uint8_t coord_system; // G10 active coordinate system default
- uint8_t select_plane; // G17,G18,G19 reset default
- uint8_t units_mode; // G20,G21 reset default
- uint8_t path_control; // G61,G61.1,G64 reset default
- uint8_t distance_mode; // G90,G91 reset default
-
- // coordinate systems and offsets
- float offset[COORDS+1][AXES]; // persistent coordinate offsets: absolute (G53) + G54,G55,G56,G57,G58,G59
-
- // settings for axes X,Y,Z,A B,C
- cfgAxis_t a[AXES];
-
- /**** Runtime variables (PRIVATE) ****/
-
- uint8_t combined_state; // stat: combination of states for display purposes
- uint8_t machine_state; // macs: machine/cycle/motion is the actual machine state
- uint8_t cycle_state; // cycs
- uint8_t motion_state; // momo
- uint8_t hold_state; // hold: feedhold sub-state machine
- uint8_t homing_state; // home: homing cycle sub-state machine
- uint8_t homed[AXES]; // individual axis homing flags
-
- uint8_t probe_state; // 1==success, 0==failed
- float probe_results[AXES]; // probing results
-
- uint8_t g28_flag; // true = complete a G28 move
- uint8_t g30_flag; // true = complete a G30 move
- uint8_t deferred_write_flag; // G10 data has changed (e.g. offsets) - flag to persist them
- uint8_t feedhold_requested; // feedhold character has been received
- uint8_t queue_flush_requested; // queue flush character has been received
- uint8_t cycle_start_requested; // cycle start character has been received (flag to end feedhold)
- float jogging_dest; // jogging direction as a relative move from current position
- struct GCodeState *am; // active Gcode model is maintained by state management
-
- /**** Model states ****/
- GCodeState_t gm; // core gcode model state
- GCodeStateX_t gmx; // extended gcode model state
- GCodeInput_t gn; // gcode input values - transient
- GCodeInput_t gf; // gcode input flags - transient
-
- magic_t magic_end;
+
+typedef struct cmSingleton { // struct to manage cm globals and cycles
+ magic_t magic_start; // magic number to test memory integrity
+
+ // Public
+ // system group settings
+ float junction_acceleration; // centripetal acceleration max for cornering
+ float chordal_tolerance; // arc chordal accuracy setting in mm
+ uint8_t soft_limit_enable;
+
+ // hidden system settings
+ float min_segment_len; // line drawing resolution in mm
+ float arc_segment_len; // arc drawing resolution in mm
+ float estd_segment_usec; // approximate segment time in microseconds
+
+ // gcode power-on default settings - defaults are not the same as the gm state
+ uint8_t coord_system; // G10 active coordinate system default
+ uint8_t select_plane; // G17,G18,G19 reset default
+ uint8_t units_mode; // G20,G21 reset default
+ uint8_t path_control; // G61,G61.1,G64 reset default
+ uint8_t distance_mode; // G90,G91 reset default
+
+ // coordinate systems and offsets
+ float offset[COORDS+1][AXES]; // persistent coordinate offsets: absolute (G53) + G54,G55,G56,G57,G58,G59
+
+ // settings for axes X,Y,Z,A B,C
+ cfgAxis_t a[AXES];
+
+ // Private
+ uint8_t combined_state; // stat: combination of states for display purposes
+ uint8_t machine_state; // macs: machine/cycle/motion is the actual machine state
+ uint8_t cycle_state; // cycs
+ uint8_t motion_state; // momo
+ uint8_t hold_state; // hold: feedhold sub-state machine
+ uint8_t homing_state; // home: homing cycle sub-state machine
+ uint8_t homed[AXES]; // individual axis homing flags
+
+ uint8_t probe_state; // 1==success, 0==failed
+ float probe_results[AXES]; // probing results
+
+ uint8_t g28_flag; // true = complete a G28 move
+ uint8_t g30_flag; // true = complete a G30 move
+ uint8_t deferred_write_flag; // G10 data has changed (e.g. offsets) - flag to persist them
+ uint8_t feedhold_requested; // feedhold character has been received
+ uint8_t queue_flush_requested; // queue flush character has been received
+ uint8_t cycle_start_requested; // cycle start character has been received (flag to end feedhold)
+ float jogging_dest; // jogging direction as a relative move from current position
+ struct GCodeState *am; // active Gcode model is maintained by state management
+
+ // Model states
+ GCodeState_t gm; // core gcode model state
+ GCodeStateX_t gmx; // extended gcode model state
+ GCodeInput_t gn; // gcode input values - transient
+ GCodeInput_t gf; // gcode input flags - transient
+
+ magic_t magic_end;
} cmSingleton_t;
-/**** Externs - See canonical_machine.c for allocation ****/
-extern cmSingleton_t cm; // canonical machine controller singleton
+extern cmSingleton_t cm; // canonical machine controller singleton
+
/*****************************************************************************
* MACHINE STATE MODEL
*/
/* Allowed states and combined states
*
- * MACHINE STATE CYCLE STATE MOTION_STATE COMBINED_STATE (FYI)
- * ------------- ------------ ------------- --------------------
- * MACHINE_UNINIT na na (U)
- * MACHINE_READY CYCLE_OFF MOTION_STOP (ROS) RESET-OFF-STOP
- * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP (SOS) STOP-OFF-STOP
- * MACHINE_PROG_END CYCLE_OFF MOTION_STOP (EOS) END-OFF-STOP
+ * MACHINE STATE CYCLE STATE MOTION_STATE COMBINED_STATE (FYI)
+ * ------------- ------------ ------------- --------------------
+ * MACHINE_UNINIT na na (U)
+ * MACHINE_READY CYCLE_OFF MOTION_STOP (ROS) RESET-OFF-STOP
+ * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP (SOS) STOP-OFF-STOP
+ * MACHINE_PROG_END CYCLE_OFF MOTION_STOP (EOS) END-OFF-STOP
*
- * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP (CSS) CYCLE-START-STOP
- * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN (CSR) CYCLE-START-RUN
- * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD (CSH) CYCLE-START-HOLD
- * MACHINE_CYCLE CYCLE_STARTED MOTION_END_HOLD (CSE) CYCLE-START-END_HOLD
+ * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP (CSS) CYCLE-START-STOP
+ * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN (CSR) CYCLE-START-RUN
+ * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD (CSH) CYCLE-START-HOLD
+ * MACHINE_CYCLE CYCLE_STARTED MOTION_END_HOLD (CSE) CYCLE-START-END_HOLD
*
- * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP (CHS) CYCLE-HOMING-STOP
+ * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP (CHS) CYCLE-HOMING-STOP
* MACHINE_CYCLE CYCLE_HOMING MOTION_RUN (CHR) CYCLE-HOMING-RUN
- * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD (CHH) CYCLE-HOMING-HOLD
- * MACHINE_CYCLE CYCLE_HOMING MOTION_END_HOLD (CHE) CYCLE-HOMING-END_HOLD
+ * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD (CHH) CYCLE-HOMING-HOLD
+ * MACHINE_CYCLE CYCLE_HOMING MOTION_END_HOLD (CHE) CYCLE-HOMING-END_HOLD
*/
// *** Note: check config printout strings align with all the state variables
// ### LAYER 8 CRITICAL REGION ###
// ### DO NOT CHANGE THESE ENUMERATIONS WITHOUT COMMUNITY INPUT ###
-enum cmCombinedState { // check alignment with messages in config.c / msg_stat strings
- COMBINED_INITIALIZING = 0, // [0] machine is initializing
- COMBINED_READY, // [1] machine is ready for use. Also used to force STOP state for null moves
- COMBINED_ALARM, // [2] machine in soft alarm state
- COMBINED_PROGRAM_STOP, // [3] program stop or no more blocks
- COMBINED_PROGRAM_END, // [4] program end
- COMBINED_RUN, // [5] motion is running
- COMBINED_HOLD, // [6] motion is holding
- COMBINED_PROBE, // [7] probe cycle active
- COMBINED_CYCLE, // [8] machine is running (cycling)
- COMBINED_HOMING, // [9] homing is treated as a cycle
- COMBINED_JOG, // [10] jogging is treated as a cycle
- COMBINED_SHUTDOWN, // [11] machine in hard alarm state (shutdown)
+enum cmCombinedState { // check alignment with messages in config.c / msg_stat strings
+ COMBINED_INITIALIZING = 0, // [0] machine is initializing
+ COMBINED_READY, // [1] machine is ready for use. Also used to force STOP state for null moves
+ COMBINED_ALARM, // [2] machine in soft alarm state
+ COMBINED_PROGRAM_STOP, // [3] program stop or no more blocks
+ COMBINED_PROGRAM_END, // [4] program end
+ COMBINED_RUN, // [5] motion is running
+ COMBINED_HOLD, // [6] motion is holding
+ COMBINED_PROBE, // [7] probe cycle active
+ COMBINED_CYCLE, // [8] machine is running (cycling)
+ COMBINED_HOMING, // [9] homing is treated as a cycle
+ COMBINED_JOG, // [10] jogging is treated as a cycle
+ COMBINED_SHUTDOWN, // [11] machine in hard alarm state (shutdown)
};
//### END CRITICAL REGION ###
+
enum cmMachineState {
- MACHINE_INITIALIZING = 0, // machine is initializing
- MACHINE_READY, // machine is ready for use
- MACHINE_ALARM, // machine in soft alarm state
- MACHINE_PROGRAM_STOP, // program stop or no more blocks
- MACHINE_PROGRAM_END, // program end
- MACHINE_CYCLE, // machine is running (cycling)
- MACHINE_SHUTDOWN, // machine in hard alarm state (shutdown)
+ MACHINE_INITIALIZING = 0, // machine is initializing
+ MACHINE_READY, // machine is ready for use
+ MACHINE_ALARM, // machine in soft alarm state
+ MACHINE_PROGRAM_STOP, // program stop or no more blocks
+ MACHINE_PROGRAM_END, // program end
+ MACHINE_CYCLE, // machine is running (cycling)
+ MACHINE_SHUTDOWN, // machine in hard alarm state (shutdown)
};
+
enum cmCycleState {
- CYCLE_OFF = 0, // machine is idle
- CYCLE_MACHINING, // in normal machining cycle
- CYCLE_PROBE, // in probe cycle
- CYCLE_HOMING, // homing is treated as a specialized cycle
- CYCLE_JOG // jogging is treated as a specialized cycle
+ CYCLE_OFF = 0, // machine is idle
+ CYCLE_MACHINING, // in normal machining cycle
+ CYCLE_PROBE, // in probe cycle
+ CYCLE_HOMING, // homing is treated as a specialized cycle
+ CYCLE_JOG // jogging is treated as a specialized cycle
};
+
enum cmMotionState {
- MOTION_STOP = 0, // motion has stopped
- MOTION_RUN, // machine is in motion
- MOTION_HOLD // feedhold in progress
+ MOTION_STOP = 0, // motion has stopped
+ MOTION_RUN, // machine is in motion
+ MOTION_HOLD // feedhold in progress
};
-enum cmFeedholdState { // feedhold_state machine
- FEEDHOLD_OFF = 0, // no feedhold in effect
- FEEDHOLD_SYNC, // start hold - sync to latest aline segment
- FEEDHOLD_PLAN, // replan blocks for feedhold
- FEEDHOLD_DECEL, // decelerate to hold point
- FEEDHOLD_HOLD, // holding
- FEEDHOLD_END_HOLD // end hold (transient state to OFF)
+
+enum cmFeedholdState { // feedhold_state machine
+ FEEDHOLD_OFF = 0, // no feedhold in effect
+ FEEDHOLD_SYNC, // start hold - sync to latest aline segment
+ FEEDHOLD_PLAN, // replan blocks for feedhold
+ FEEDHOLD_DECEL, // decelerate to hold point
+ FEEDHOLD_HOLD, // holding
+ FEEDHOLD_END_HOLD // end hold (transient state to OFF)
};
+
enum cmHomingState { // applies to cm.homing_state
- HOMING_NOT_HOMED = 0, // machine is not homed (0=false)
- HOMING_HOMED = 1, // machine is homed (1=true)
- HOMING_WAITING // machine waiting to be homed
+ HOMING_NOT_HOMED = 0, // machine is not homed (0=false)
+ HOMING_HOMED = 1, // machine is homed (1=true)
+ HOMING_WAITING // machine waiting to be homed
};
-enum cmProbeState { // applies to cm.probe_state
- PROBE_FAILED = 0, // probe reached endpoint without triggering
- PROBE_SUCCEEDED = 1, // probe was triggered, cm.probe_results has position
- PROBE_WAITING // probe is waiting to be started
+
+enum cmProbeState { // applies to cm.probe_state
+ PROBE_FAILED = 0, // probe reached endpoint without triggering
+ PROBE_SUCCEEDED = 1, // probe was triggered, cm.probe_results has position
+ PROBE_WAITING // probe is waiting to be started
};
+
/* The difference between NextAction and MotionMode is that NextAction is
* used by the current block, and may carry non-modal commands, whereas
* MotionMode persists across blocks (as G modal group 1)
*/
-
-enum cmNextAction { // these are in order to optimized CASE statement
- NEXT_ACTION_DEFAULT = 0, // Must be zero (invokes motion modes)
- NEXT_ACTION_SEARCH_HOME, // G28.2 homing cycle
- NEXT_ACTION_SET_ABSOLUTE_ORIGIN, // G28.3 origin set
- NEXT_ACTION_HOMING_NO_SET, // G28.4 homing cycle with no coordinate setting
- NEXT_ACTION_SET_G28_POSITION, // G28.1 set position in abs coordinates
- NEXT_ACTION_GOTO_G28_POSITION, // G28 go to machine position
- NEXT_ACTION_SET_G30_POSITION, // G30.1
- NEXT_ACTION_GOTO_G30_POSITION, // G30
- NEXT_ACTION_SET_COORD_DATA, // G10
- NEXT_ACTION_SET_ORIGIN_OFFSETS, // G92
- NEXT_ACTION_RESET_ORIGIN_OFFSETS, // G92.1
- NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS, // G92.2
- NEXT_ACTION_RESUME_ORIGIN_OFFSETS, // G92.3
- NEXT_ACTION_DWELL, // G4
- NEXT_ACTION_STRAIGHT_PROBE // G38.2
+enum cmNextAction { // these are in order to optimized CASE statement
+ NEXT_ACTION_DEFAULT = 0, // Must be zero (invokes motion modes)
+ NEXT_ACTION_SEARCH_HOME, // G28.2 homing cycle
+ NEXT_ACTION_SET_ABSOLUTE_ORIGIN, // G28.3 origin set
+ NEXT_ACTION_HOMING_NO_SET, // G28.4 homing cycle with no coordinate setting
+ NEXT_ACTION_SET_G28_POSITION, // G28.1 set position in abs coordinates
+ NEXT_ACTION_GOTO_G28_POSITION, // G28 go to machine position
+ NEXT_ACTION_SET_G30_POSITION, // G30.1
+ NEXT_ACTION_GOTO_G30_POSITION, // G30
+ NEXT_ACTION_SET_COORD_DATA, // G10
+ NEXT_ACTION_SET_ORIGIN_OFFSETS, // G92
+ NEXT_ACTION_RESET_ORIGIN_OFFSETS, // G92.1
+ NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS, // G92.2
+ NEXT_ACTION_RESUME_ORIGIN_OFFSETS, // G92.3
+ NEXT_ACTION_DWELL, // G4
+ NEXT_ACTION_STRAIGHT_PROBE // G38.2
};
-enum cmMotionMode { // G Modal Group 1
- MOTION_MODE_STRAIGHT_TRAVERSE=0, // G0 - straight traverse
- MOTION_MODE_STRAIGHT_FEED, // G1 - straight feed
- MOTION_MODE_CW_ARC, // G2 - clockwise arc feed
- MOTION_MODE_CCW_ARC, // G3 - counter-clockwise arc feed
- MOTION_MODE_CANCEL_MOTION_MODE, // G80
- MOTION_MODE_STRAIGHT_PROBE, // G38.2
- MOTION_MODE_CANNED_CYCLE_81, // G81 - drilling
- MOTION_MODE_CANNED_CYCLE_82, // G82 - drilling with dwell
- MOTION_MODE_CANNED_CYCLE_83, // G83 - peck drilling
- MOTION_MODE_CANNED_CYCLE_84, // G84 - right hand tapping
- MOTION_MODE_CANNED_CYCLE_85, // G85 - boring, no dwell, feed out
- MOTION_MODE_CANNED_CYCLE_86, // G86 - boring, spindle stop, rapid out
- MOTION_MODE_CANNED_CYCLE_87, // G87 - back boring
- MOTION_MODE_CANNED_CYCLE_88, // G88 - boring, spindle stop, manual out
- MOTION_MODE_CANNED_CYCLE_89 // G89 - boring, dwell, feed out
+
+enum cmMotionMode { // G Modal Group 1
+ MOTION_MODE_STRAIGHT_TRAVERSE = 0, // G0 - straight traverse
+ MOTION_MODE_STRAIGHT_FEED, // G1 - straight feed
+ MOTION_MODE_CW_ARC, // G2 - clockwise arc feed
+ MOTION_MODE_CCW_ARC, // G3 - counter-clockwise arc feed
+ MOTION_MODE_CANCEL_MOTION_MODE, // G80
+ MOTION_MODE_STRAIGHT_PROBE, // G38.2
+ MOTION_MODE_CANNED_CYCLE_81, // G81 - drilling
+ MOTION_MODE_CANNED_CYCLE_82, // G82 - drilling with dwell
+ MOTION_MODE_CANNED_CYCLE_83, // G83 - peck drilling
+ MOTION_MODE_CANNED_CYCLE_84, // G84 - right hand tapping
+ MOTION_MODE_CANNED_CYCLE_85, // G85 - boring, no dwell, feed out
+ MOTION_MODE_CANNED_CYCLE_86, // G86 - boring, spindle stop, rapid out
+ MOTION_MODE_CANNED_CYCLE_87, // G87 - back boring
+ MOTION_MODE_CANNED_CYCLE_88, // G88 - boring, spindle stop, manual out
+ MOTION_MODE_CANNED_CYCLE_89 // G89 - boring, dwell, feed out
};
-enum cmModalGroup { // Used for detecting gcode errors. See NIST section 3.4
- MODAL_GROUP_G0 = 0, // {G10,G28,G28.1,G92} non-modal axis commands (note 1)
- MODAL_GROUP_G1, // {G0,G1,G2,G3,G80} motion
- MODAL_GROUP_G2, // {G17,G18,G19} plane selection
- MODAL_GROUP_G3, // {G90,G91} distance mode
- MODAL_GROUP_G5, // {G93,G94} feed rate mode
- MODAL_GROUP_G6, // {G20,G21} units
- MODAL_GROUP_G7, // {G40,G41,G42} cutter radius compensation
- MODAL_GROUP_G8, // {G43,G49} tool length offset
- MODAL_GROUP_G9, // {G98,G99} return mode in canned cycles
- MODAL_GROUP_G12, // {G54,G55,G56,G57,G58,G59} coordinate system selection
- MODAL_GROUP_G13, // {G61,G61.1,G64} path control mode
- MODAL_GROUP_M4, // {M0,M1,M2,M30,M60} stopping
- MODAL_GROUP_M6, // {M6} tool change
- MODAL_GROUP_M7, // {M3,M4,M5} spindle turning
- MODAL_GROUP_M8, // {M7,M8,M9} coolant (M7 & M8 may be active together)
- MODAL_GROUP_M9 // {M48,M49} speed/feed override switches
+
+enum cmModalGroup { // Used for detecting gcode errors. See NIST section 3.4
+ MODAL_GROUP_G0 = 0, // {G10,G28,G28.1,G92} non-modal axis commands (note 1)
+ MODAL_GROUP_G1, // {G0,G1,G2,G3,G80} motion
+ MODAL_GROUP_G2, // {G17,G18,G19} plane selection
+ MODAL_GROUP_G3, // {G90,G91} distance mode
+ MODAL_GROUP_G5, // {G93,G94} feed rate mode
+ MODAL_GROUP_G6, // {G20,G21} units
+ MODAL_GROUP_G7, // {G40,G41,G42} cutter radius compensation
+ MODAL_GROUP_G8, // {G43,G49} tool length offset
+ MODAL_GROUP_G9, // {G98,G99} return mode in canned cycles
+ MODAL_GROUP_G12, // {G54,G55,G56,G57,G58,G59} coordinate system selection
+ MODAL_GROUP_G13, // {G61,G61.1,G64} path control mode
+ MODAL_GROUP_M4, // {M0,M1,M2,M30,M60} stopping
+ MODAL_GROUP_M6, // {M6} tool change
+ MODAL_GROUP_M7, // {M3,M4,M5} spindle turning
+ MODAL_GROUP_M8, // {M7,M8,M9} coolant (M7 & M8 may be active together)
+ MODAL_GROUP_M9 // {M48,M49} speed/feed override switches
};
-#define MODAL_GROUP_COUNT (MODAL_GROUP_M9+1)
+
+#define MODAL_GROUP_COUNT (MODAL_GROUP_M9 + 1)
+
// Note 1: Our G0 omits G4,G30,G53,G92.1,G92.2,G92.3 as these have no axis components to error check
-enum cmCanonicalPlane { // canonical plane - translates to:
- // axis_0 axis_1 axis_2
- CANON_PLANE_XY = 0, // G17 X Y Z
- CANON_PLANE_XZ, // G18 X Z Y
- CANON_PLANE_YZ // G19 Y Z X
+enum cmCanonicalPlane { // canonical plane - translates to:
+ // axis_0 axis_1 axis_2
+ CANON_PLANE_XY = 0, // G17 X Y Z
+ CANON_PLANE_XZ, // G18 X Z Y
+ CANON_PLANE_YZ // G19 Y Z X
};
+
enum cmUnitsMode {
- INCHES = 0, // G20
- MILLIMETERS, // G21
- DEGREES // ABC axes (this value used for displays only)
+ INCHES = 0, // G20
+ MILLIMETERS, // G21
+ DEGREES // ABC axes (this value used for displays only)
};
+
enum cmCoordSystem {
- ABSOLUTE_COORDS = 0, // machine coordinate system
- G54, // G54 coordinate system
- G55, // G55 coordinate system
- G56, // G56 coordinate system
- G57, // G57 coordinate system
- G58, // G58 coordinate system
- G59 // G59 coordinate system
+ ABSOLUTE_COORDS = 0, // machine coordinate system
+ G54, // G54 coordinate system
+ G55, // G55 coordinate system
+ G56, // G56 coordinate system
+ G57, // G57 coordinate system
+ G58, // G58 coordinate system
+ G59 // G59 coordinate system
};
-#define COORD_SYSTEM_MAX G59 // set this manually to the last one
-enum cmPathControlMode { // G Modal Group 13
- PATH_EXACT_PATH = 0, // G61 - hits corners but does not stop if it does not need to.
- PATH_EXACT_STOP, // G61.1 - stops at all corners
- PATH_CONTINUOUS // G64 and typically the default mode
+#define COORD_SYSTEM_MAX G59 // set this manually to the last one
+
+enum cmPathControlMode { // G Modal Group 13
+ PATH_EXACT_PATH = 0, // G61 - hits corners but does not stop if it does not need to.
+ PATH_EXACT_STOP, // G61.1 - stops at all corners
+ PATH_CONTINUOUS // G64 and typically the default mode
};
+
enum cmDistanceMode {
- ABSOLUTE_MODE = 0, // G90
- INCREMENTAL_MODE // G91
+ ABSOLUTE_MODE = 0, // G90
+ INCREMENTAL_MODE // G91
};
+
enum cmFeedRateMode {
- INVERSE_TIME_MODE = 0, // G93
- UNITS_PER_MINUTE_MODE, // G94
- UNITS_PER_REVOLUTION_MODE // G95 (unimplemented)
+ INVERSE_TIME_MODE = 0, // G93
+ UNITS_PER_MINUTE_MODE, // G94
+ UNITS_PER_REVOLUTION_MODE // G95 (unimplemented)
};
+
enum cmOriginOffset {
- ORIGIN_OFFSET_SET=0, // G92 - set origin offsets
- ORIGIN_OFFSET_CANCEL, // G92.1 - zero out origin offsets
- ORIGIN_OFFSET_SUSPEND, // G92.2 - do not apply offsets, but preserve the values
- ORIGIN_OFFSET_RESUME // G92.3 - resume application of the suspended offsets
+ ORIGIN_OFFSET_SET = 0, // G92 - set origin offsets
+ ORIGIN_OFFSET_CANCEL, // G92.1 - zero out origin offsets
+ ORIGIN_OFFSET_SUSPEND, // G92.2 - do not apply offsets, but preserve the values
+ ORIGIN_OFFSET_RESUME // G92.3 - resume application of the suspended offsets
};
+
enum cmProgramFlow {
- PROGRAM_STOP = 0,
- PROGRAM_END
+ PROGRAM_STOP = 0,
+ PROGRAM_END
};
-enum cmSpindleState { // spindle state settings (See hardware.h for bit settings)
- SPINDLE_OFF = 0,
- SPINDLE_CW,
- SPINDLE_CCW
+
+enum cmSpindleState { // spindle state settings (See hardware.h for bit settings)
+ SPINDLE_OFF = 0,
+ SPINDLE_CW,
+ SPINDLE_CCW
};
-enum cmCoolantState { // mist and flood coolant states
- COOLANT_OFF = 0, // all coolant off
- COOLANT_ON, // request coolant on or indicates both coolants are on
- COOLANT_MIST, // indicates mist coolant on
- COOLANT_FLOOD // indicates flood coolant on
+
+enum cmCoolantState { // mist and flood coolant states
+ COOLANT_OFF = 0, // all coolant off
+ COOLANT_ON, // request coolant on or indicates both coolants are on
+ COOLANT_MIST, // indicates mist coolant on
+ COOLANT_FLOOD // indicates flood coolant on
};
-enum cmDirection { // used for spindle and arc dir
- DIRECTION_CW = 0,
- DIRECTION_CCW
+
+enum cmDirection { // used for spindle and arc dir
+ DIRECTION_CW = 0,
+ DIRECTION_CCW
};
-enum cmAxisMode { // axis modes (ordered: see _cm_get_feed_time())
- AXIS_DISABLED = 0, // kill axis
- AXIS_STANDARD, // axis in coordinated motion w/standard behaviors
- AXIS_INHIBITED, // axis is computed but not activated
- AXIS_RADIUS // rotary axis calibrated to circumference
-}; // ordering must be preserved. See cm_set_move_times()
+enum cmAxisMode { // axis modes (ordered: see _cm_get_feed_time())
+ AXIS_DISABLED = 0, // kill axis
+ AXIS_STANDARD, // axis in coordinated motion w/standard behaviors
+ AXIS_INHIBITED, // axis is computed but not activated
+ AXIS_RADIUS // rotary axis calibrated to circumference
+}; // ordering must be preserved. See cm_set_move_times()
+
#define AXIS_MODE_MAX_LINEAR AXIS_INHIBITED
#define AXIS_MODE_MAX_ROTARY AXIS_RADIUS
-/*****************************************************************************
- * FUNCTION PROTOTYPES
- * Serves as a table of contents for the rather large canonical machine source file.
- */
-
-/*--- Internal functions and helpers ---*/
// Model state getters and setters
uint8_t cm_get_combined_state();
uint8_t cm_get_feed_rate_mode(GCodeState_t *gcode_state);
uint8_t cm_get_tool(GCodeState_t *gcode_state);
uint8_t cm_get_spindle_mode(GCodeState_t *gcode_state);
-uint8_t cm_get_block_delete_switch();
+uint8_t cm_get_block_delete_switch();
uint8_t cm_get_runtime_busy();
float cm_get_feed_rate(GCodeState_t *gcode_state);
void cm_set_model_target(float target[], float flag[]);
stat_t cm_test_soft_limits(float target[]);
-/*--- Canonical machining functions (loosely) defined by NIST [organized by NIST Gcode doc] ---*/
+// Canonical machining functions (loosely) defined by NIST [organized by NIST Gcode doc]
// Initialization and termination (4.3.2)
void canonical_machine_init();
stat_t cm_clear(nvObj_t *nv);
// Representation (4.3.3)
-stat_t cm_select_plane(uint8_t plane); // G17, G18, G19
-stat_t cm_set_units_mode(uint8_t mode); // G20, G21
-stat_t cm_set_distance_mode(uint8_t mode); // G90, G91
+stat_t cm_select_plane(uint8_t plane); // G17, G18, G19
+stat_t cm_set_units_mode(uint8_t mode); // G20, G21
+stat_t cm_set_distance_mode(uint8_t mode); // G90, G91
stat_t cm_set_coord_offsets(uint8_t coord_system, float offset[], float flag[]); // G10 L2
-void cm_set_position(uint8_t axis, float position); // set absolute position - single axis
+void cm_set_position(uint8_t axis, float position); // set absolute position - single axis
stat_t cm_set_absolute_origin(float origin[], float flag[]); // G28.3
void cm_set_axis_origin(uint8_t axis, const float position); // G28.3 planner callback
-stat_t cm_set_coord_system(uint8_t coord_system); // G54 - G59
-stat_t cm_set_origin_offsets(float offset[], float flag[]); // G92
-stat_t cm_reset_origin_offsets(); // G92.1
-stat_t cm_suspend_origin_offsets(); // G92.2
-stat_t cm_resume_origin_offsets(); // G92.3
+stat_t cm_set_coord_system(uint8_t coord_system); // G54 - G59
+stat_t cm_set_origin_offsets(float offset[], float flag[]); // G92
+stat_t cm_reset_origin_offsets(); // G92.1
+stat_t cm_suspend_origin_offsets(); // G92.2
+stat_t cm_resume_origin_offsets(); // G92.3
// Free Space Motion (4.3.4)
-stat_t cm_straight_traverse(float target[], float flags[]); // G0
-stat_t cm_set_g28_position(); // G28.1
+stat_t cm_straight_traverse(float target[], float flags[]); // G0
+stat_t cm_set_g28_position(); // G28.1
stat_t cm_goto_g28_position(float target[], float flags[]); // G28
-stat_t cm_set_g30_position(); // G30.1
-stat_t cm_goto_g30_position(float target[], float flags[]); // G30
+stat_t cm_set_g30_position(); // G30.1
+stat_t cm_goto_g30_position(float target[], float flags[]); // G30
// Machining Attributes (4.3.5)
stat_t cm_set_feed_rate(float feed_rate); // F parameter
-stat_t cm_set_feed_rate_mode(uint8_t mode); // G93, G94, (G95 unimplemented)
+stat_t cm_set_feed_rate_mode(uint8_t mode); // G93, G94, (G95 unimplemented)
stat_t cm_set_path_control(uint8_t mode); // G61, G61.1, G64
// Machining Functions (4.3.6)
-stat_t cm_straight_feed(float target[], float flags[]); // G1
-stat_t cm_arc_feed( float target[], float flags[], // G2, G3
- float i, float j, float k,
- float radius, uint8_t motion_mode);
-stat_t cm_dwell(float seconds); // G4, P parameter
+stat_t cm_straight_feed(float target[], float flags[]); // G1
+stat_t cm_arc_feed(float target[], float flags[], // G2, G3
+ float i, float j, float k,
+ float radius, uint8_t motion_mode);
+stat_t cm_dwell(float seconds); // G4, P parameter
// Spindle Functions (4.3.7)
// see spindle.h for spindle definitions - which would go right here
// Tool Functions (4.3.8)
-stat_t cm_select_tool(uint8_t tool); // T parameter
-stat_t cm_change_tool(uint8_t tool); // M6
+stat_t cm_select_tool(uint8_t tool); // T parameter
+stat_t cm_change_tool(uint8_t tool); // M6
// Miscellaneous Functions (4.3.9)
-stat_t cm_mist_coolant_control(uint8_t mist_coolant); // M7
-stat_t cm_flood_coolant_control(uint8_t flood_coolant); // M8, M9
+stat_t cm_mist_coolant_control(uint8_t mist_coolant); // M7
+stat_t cm_flood_coolant_control(uint8_t flood_coolant); // M8, M9
-stat_t cm_override_enables(uint8_t flag); // M48, M49
-stat_t cm_feed_rate_override_enable(uint8_t flag); // M50
-stat_t cm_feed_rate_override_factor(uint8_t flag); // M50.1
-stat_t cm_traverse_override_enable(uint8_t flag); // M50.2
+stat_t cm_override_enables(uint8_t flag); // M48, M49
+stat_t cm_feed_rate_override_enable(uint8_t flag); // M50
+stat_t cm_feed_rate_override_factor(uint8_t flag); // M50.1
+stat_t cm_traverse_override_enable(uint8_t flag); // M50.2
stat_t cm_traverse_override_factor(uint8_t flag); // M50.3
stat_t cm_spindle_override_enable(uint8_t flag); // M51
-stat_t cm_spindle_override_factor(uint8_t flag); // M51.1
+stat_t cm_spindle_override_factor(uint8_t flag); // M51.1
void cm_message(char_t *message); // msg to console (e.g. Gcode comments)
void cm_request_queue_flush();
void cm_request_cycle_start();
-stat_t cm_feedhold_sequencing_callback(); // process feedhold, cycle start and queue flush requests
+stat_t cm_feedhold_sequencing_callback(); // process feedhold, cycle start and queue flush requests
stat_t cm_queue_flush(); // flush serial and planner queues with coordinate resets
-void cm_cycle_start(); // (no Gcode)
-void cm_cycle_end(); // (no Gcode)
-void cm_feedhold(); // (no Gcode)
-void cm_program_stop(); // M0
-void cm_optional_program_stop(); // M1
-void cm_program_end(); // M2
+void cm_cycle_start(); // (no Gcode)
+void cm_cycle_end(); // (no Gcode)
+void cm_feedhold(); // (no Gcode)
+void cm_program_stop(); // M0
+void cm_optional_program_stop(); // M1
+void cm_program_end(); // M2
/*--- Cycles ---*/
// Homing cycles
-stat_t cm_homing_cycle_start(); // G28.2
-stat_t cm_homing_cycle_start_no_set(); // G28.4
-stat_t cm_homing_callback(); // G28.2/.4 main loop callback
+stat_t cm_homing_cycle_start(); // G28.2
+stat_t cm_homing_cycle_start_no_set(); // G28.4
+stat_t cm_homing_callback(); // G28.2/.4 main loop callback
// Probe cycles
-stat_t cm_straight_probe(float target[], float flags[]); // G38.2
-stat_t cm_probe_callback(); // G38.2 main loop callback
+stat_t cm_straight_probe(float target[], float flags[]); // G38.2
+stat_t cm_probe_callback(); // G38.2 main loop callback
// Jogging cycle
-stat_t cm_jogging_callback(); // jogging cycle main loop
-stat_t cm_jogging_cycle_start(uint8_t axis); // {"jogx":-100.3}
+stat_t cm_jogging_callback(); // jogging cycle main loop
+stat_t cm_jogging_cycle_start(uint8_t axis); // {"jogx":-100.3}
float cm_get_jogging_dest();
/*--- cfgArray interface functions ---*/
char_t cm_get_axis_char(const int8_t axis);
-stat_t cm_get_mline(nvObj_t *nv); // get model line number
+stat_t cm_get_mline(nvObj_t *nv); // get model line number
stat_t cm_get_line(nvObj_t *nv); // get active (model or runtime) line number
stat_t cm_get_stat(nvObj_t *nv); // get combined machine state as value and string
stat_t cm_get_macs(nvObj_t *nv); // get raw machine state as value and string
stat_t cm_get_path(nvObj_t *nv); // get patch control mode...
stat_t cm_get_dist(nvObj_t *nv); // get distance mode...
stat_t cm_get_frmo(nvObj_t *nv); // get feedrate mode...
-stat_t cm_get_toolv(nvObj_t *nv); // get tool (value)
-stat_t cm_get_pwr(nvObj_t *nv); // get motor power enable state
+stat_t cm_get_toolv(nvObj_t *nv); // get tool (value)
+stat_t cm_get_pwr(nvObj_t *nv); // get motor power enable state
-stat_t cm_get_vel(nvObj_t *nv); // get runtime velocity...
+stat_t cm_get_vel(nvObj_t *nv); // get runtime velocity...
stat_t cm_get_feed(nvObj_t *nv);
-stat_t cm_get_pos(nvObj_t *nv); // get runtime work position...
-stat_t cm_get_mpo(nvObj_t *nv); // get runtime machine position...
-stat_t cm_get_ofs(nvObj_t *nv); // get runtime work offset...
+stat_t cm_get_pos(nvObj_t *nv); // get runtime work position...
+stat_t cm_get_mpo(nvObj_t *nv); // get runtime machine position...
+stat_t cm_get_ofs(nvObj_t *nv); // get runtime work offset...
-stat_t cm_run_qf(nvObj_t *nv); // run queue flush
+stat_t cm_run_qf(nvObj_t *nv); // run queue flush
stat_t cm_run_home(nvObj_t *nv); // start homing cycle
-stat_t cm_dam(nvObj_t *nv); // dump active model (debugging command)
+stat_t cm_dam(nvObj_t *nv); // dump active model (debugging command)
stat_t cm_run_jogx(nvObj_t *nv); // start jogging cycle for x
stat_t cm_run_jogy(nvObj_t *nv); // start jogging cycle for y
stat_t cm_run_jogz(nvObj_t *nv); // start jogging cycle for z
stat_t cm_run_joga(nvObj_t *nv); // start jogging cycle for a
-stat_t cm_get_am(nvObj_t *nv); // get axis mode
-stat_t cm_set_am(nvObj_t *nv); // set axis mode
-stat_t cm_set_xjm(nvObj_t *nv); // set jerk max with 1,000,000 correction
-stat_t cm_set_xjh(nvObj_t *nv); // set jerk homing with 1,000,000 correction
-
-/*--- text_mode support functions ---*/
+stat_t cm_get_am(nvObj_t *nv); // get axis mode
+stat_t cm_set_am(nvObj_t *nv); // set axis mode
+stat_t cm_set_xjm(nvObj_t *nv); // set jerk max with 1,000,000 correction
+stat_t cm_set_xjh(nvObj_t *nv); // set jerk homing with 1,000,000 correction
#ifdef __TEXT_MODE
- void cm_print_vel(nvObj_t *nv); // model state reporting
- void cm_print_feed(nvObj_t *nv);
- void cm_print_line(nvObj_t *nv);
- void cm_print_stat(nvObj_t *nv);
- void cm_print_macs(nvObj_t *nv);
- void cm_print_cycs(nvObj_t *nv);
- void cm_print_mots(nvObj_t *nv);
- void cm_print_hold(nvObj_t *nv);
- void cm_print_home(nvObj_t *nv);
- void cm_print_unit(nvObj_t *nv);
- void cm_print_coor(nvObj_t *nv);
- void cm_print_momo(nvObj_t *nv);
- void cm_print_plan(nvObj_t *nv);
- void cm_print_path(nvObj_t *nv);
- void cm_print_dist(nvObj_t *nv);
- void cm_print_frmo(nvObj_t *nv);
- void cm_print_tool(nvObj_t *nv);
-
- void cm_print_gpl(nvObj_t *nv); // Gcode defaults
- void cm_print_gun(nvObj_t *nv);
- void cm_print_gco(nvObj_t *nv);
- void cm_print_gpa(nvObj_t *nv);
- void cm_print_gdi(nvObj_t *nv);
-
- void cm_print_lin(nvObj_t *nv); // generic print for linear values
- void cm_print_pos(nvObj_t *nv); // print runtime work position in prevailing units
- void cm_print_mpo(nvObj_t *nv); // print runtime work position always in MM units
- void cm_print_ofs(nvObj_t *nv); // print runtime work offset always in MM units
-
- void cm_print_ja(nvObj_t *nv); // global CM settings
- void cm_print_ct(nvObj_t *nv);
- void cm_print_sl(nvObj_t *nv);
- void cm_print_ml(nvObj_t *nv);
- void cm_print_ma(nvObj_t *nv);
- void cm_print_ms(nvObj_t *nv);
- void cm_print_st(nvObj_t *nv);
-
- void cm_print_am(nvObj_t *nv); // axis print functions
- void cm_print_fr(nvObj_t *nv);
- void cm_print_vm(nvObj_t *nv);
- void cm_print_tm(nvObj_t *nv);
- void cm_print_tn(nvObj_t *nv);
- void cm_print_jm(nvObj_t *nv);
- void cm_print_jh(nvObj_t *nv);
- void cm_print_jd(nvObj_t *nv);
- void cm_print_ra(nvObj_t *nv);
- void cm_print_sn(nvObj_t *nv);
- void cm_print_sx(nvObj_t *nv);
- void cm_print_sv(nvObj_t *nv);
- void cm_print_lv(nvObj_t *nv);
- void cm_print_lb(nvObj_t *nv);
- void cm_print_zb(nvObj_t *nv);
- void cm_print_cofs(nvObj_t *nv);
- void cm_print_cpos(nvObj_t *nv);
+void cm_print_vel(nvObj_t *nv); // model state reporting
+void cm_print_feed(nvObj_t *nv);
+void cm_print_line(nvObj_t *nv);
+void cm_print_stat(nvObj_t *nv);
+void cm_print_macs(nvObj_t *nv);
+void cm_print_cycs(nvObj_t *nv);
+void cm_print_mots(nvObj_t *nv);
+void cm_print_hold(nvObj_t *nv);
+void cm_print_home(nvObj_t *nv);
+void cm_print_unit(nvObj_t *nv);
+void cm_print_coor(nvObj_t *nv);
+void cm_print_momo(nvObj_t *nv);
+void cm_print_plan(nvObj_t *nv);
+void cm_print_path(nvObj_t *nv);
+void cm_print_dist(nvObj_t *nv);
+void cm_print_frmo(nvObj_t *nv);
+void cm_print_tool(nvObj_t *nv);
+
+void cm_print_gpl(nvObj_t *nv); // Gcode defaults
+void cm_print_gun(nvObj_t *nv);
+void cm_print_gco(nvObj_t *nv);
+void cm_print_gpa(nvObj_t *nv);
+void cm_print_gdi(nvObj_t *nv);
+
+void cm_print_lin(nvObj_t *nv); // generic print for linear values
+void cm_print_pos(nvObj_t *nv); // print runtime work position in prevailing units
+void cm_print_mpo(nvObj_t *nv); // print runtime work position always in MM units
+void cm_print_ofs(nvObj_t *nv); // print runtime work offset always in MM units
+
+void cm_print_ja(nvObj_t *nv); // global CM settings
+void cm_print_ct(nvObj_t *nv);
+void cm_print_sl(nvObj_t *nv);
+void cm_print_ml(nvObj_t *nv);
+void cm_print_ma(nvObj_t *nv);
+void cm_print_ms(nvObj_t *nv);
+void cm_print_st(nvObj_t *nv);
+
+void cm_print_am(nvObj_t *nv); // axis print functions
+void cm_print_fr(nvObj_t *nv);
+void cm_print_vm(nvObj_t *nv);
+void cm_print_tm(nvObj_t *nv);
+void cm_print_tn(nvObj_t *nv);
+void cm_print_jm(nvObj_t *nv);
+void cm_print_jh(nvObj_t *nv);
+void cm_print_jd(nvObj_t *nv);
+void cm_print_ra(nvObj_t *nv);
+void cm_print_sn(nvObj_t *nv);
+void cm_print_sx(nvObj_t *nv);
+void cm_print_sv(nvObj_t *nv);
+void cm_print_lv(nvObj_t *nv);
+void cm_print_lb(nvObj_t *nv);
+void cm_print_zb(nvObj_t *nv);
+void cm_print_cofs(nvObj_t *nv);
+void cm_print_cpos(nvObj_t *nv);
#else // __TEXT_MODE
- #define cm_print_vel tx_print_stub // model state reporting
- #define cm_print_feed tx_print_stub
- #define cm_print_line tx_print_stub
- #define cm_print_stat tx_print_stub
- #define cm_print_macs tx_print_stub
- #define cm_print_cycs tx_print_stub
- #define cm_print_mots tx_print_stub
- #define cm_print_hold tx_print_stub
- #define cm_print_home tx_print_stub
- #define cm_print_unit tx_print_stub
- #define cm_print_coor tx_print_stub
- #define cm_print_momo tx_print_stub
- #define cm_print_plan tx_print_stub
- #define cm_print_path tx_print_stub
- #define cm_print_dist tx_print_stub
- #define cm_print_frmo tx_print_stub
- #define cm_print_tool tx_print_stub
-
- #define cm_print_gpl tx_print_stub // Gcode defaults
- #define cm_print_gun tx_print_stub
- #define cm_print_gco tx_print_stub
- #define cm_print_gpa tx_print_stub
- #define cm_print_gdi tx_print_stub
-
- #define cm_print_lin tx_print_stub // generic print for linear values
- #define cm_print_pos tx_print_stub // print runtime work position in prevailing units
- #define cm_print_mpo tx_print_stub // print runtime work position always in MM uints
- #define cm_print_ofs tx_print_stub // print runtime work offset always in MM uints
-
- #define cm_print_ja tx_print_stub // global CM settings
- #define cm_print_ct tx_print_stub
- #define cm_print_sl tx_print_stub
- #define cm_print_ml tx_print_stub
- #define cm_print_ma tx_print_stub
- #define cm_print_ms tx_print_stub
- #define cm_print_st tx_print_stub
-
- #define cm_print_am tx_print_stub // axis print functions
- #define cm_print_fr tx_print_stub
- #define cm_print_vm tx_print_stub
- #define cm_print_tm tx_print_stub
- #define cm_print_tn tx_print_stub
- #define cm_print_jm tx_print_stub
- #define cm_print_jh tx_print_stub
- #define cm_print_jd tx_print_stub
- #define cm_print_ra tx_print_stub
- #define cm_print_sn tx_print_stub
- #define cm_print_sx tx_print_stub
- #define cm_print_sv tx_print_stub
- #define cm_print_lv tx_print_stub
- #define cm_print_lb tx_print_stub
- #define cm_print_zb tx_print_stub
- #define cm_print_cofs tx_print_stub
- #define cm_print_cpos tx_print_stub
+#define cm_print_vel tx_print_stub // model state reporting
+#define cm_print_feed tx_print_stub
+#define cm_print_line tx_print_stub
+#define cm_print_stat tx_print_stub
+#define cm_print_macs tx_print_stub
+#define cm_print_cycs tx_print_stub
+#define cm_print_mots tx_print_stub
+#define cm_print_hold tx_print_stub
+#define cm_print_home tx_print_stub
+#define cm_print_unit tx_print_stub
+#define cm_print_coor tx_print_stub
+#define cm_print_momo tx_print_stub
+#define cm_print_plan tx_print_stub
+#define cm_print_path tx_print_stub
+#define cm_print_dist tx_print_stub
+#define cm_print_frmo tx_print_stub
+#define cm_print_tool tx_print_stub
+
+#define cm_print_gpl tx_print_stub // Gcode defaults
+#define cm_print_gun tx_print_stub
+#define cm_print_gco tx_print_stub
+#define cm_print_gpa tx_print_stub
+#define cm_print_gdi tx_print_stub
+
+#define cm_print_lin tx_print_stub // generic print for linear values
+#define cm_print_pos tx_print_stub // print runtime work position in prevailing units
+#define cm_print_mpo tx_print_stub // print runtime work position always in MM uints
+#define cm_print_ofs tx_print_stub // print runtime work offset always in MM uints
+
+#define cm_print_ja tx_print_stub // global CM settings
+#define cm_print_ct tx_print_stub
+#define cm_print_sl tx_print_stub
+#define cm_print_ml tx_print_stub
+#define cm_print_ma tx_print_stub
+#define cm_print_ms tx_print_stub
+#define cm_print_st tx_print_stub
+
+#define cm_print_am tx_print_stub // axis print functions
+#define cm_print_fr tx_print_stub
+#define cm_print_vm tx_print_stub
+#define cm_print_tm tx_print_stub
+#define cm_print_tn tx_print_stub
+#define cm_print_jm tx_print_stub
+#define cm_print_jh tx_print_stub
+#define cm_print_jd tx_print_stub
+#define cm_print_ra tx_print_stub
+#define cm_print_sn tx_print_stub
+#define cm_print_sx tx_print_stub
+#define cm_print_sv tx_print_stub
+#define cm_print_lv tx_print_stub
+#define cm_print_lb tx_print_stub
+#define cm_print_zb tx_print_stub
+#define cm_print_cofs tx_print_stub
+#define cm_print_cpos tx_print_stub
#endif // __TEXT_MODE
-#endif // End of include guard: CANONICAL_MACHINE_H_ONCE
+#endif // CANONICAL_MACHINE_H_ONCE
*/
stat_t nv_set(nvObj_t *nv) {
if (nv->index >= nv_index_max())
- return(STAT_INTERNAL_RANGE_ERROR);
+ return STAT_INTERNAL_RANGE_ERROR;
return ((fptrCmd)GET_TABLE_WORD(set))(nv);
}
stat_t nv_persist(nvObj_t *nv) { // nv_persist() cannot be called from an interrupt on the AVR due to the AVR1008 EEPROM workaround
- if (nv_index_lt_groups(nv->index) == false) return(STAT_INTERNAL_RANGE_ERROR);
- if (GET_TABLE_BYTE(flags) & F_PERSIST) return(write_persistent_value(nv));
+ if (nv_index_lt_groups(nv->index) == false) return STAT_INTERNAL_RANGE_ERROR;
+ if (GET_TABLE_BYTE(flags) & F_PERSIST) return write_persistent_value(nv);
return STAT_OK;
}
stat_t set_defaults(nvObj_t *nv) {
// failsafe. nv->value must be true or no action occurs
- if (fp_FALSE(nv->value)) return(help_defa(nv));
+ if (fp_FALSE(nv->value)) return help_defa(nv);
_set_defa(nv);
// The values in nv are now garbage. Mark the nv as $defa so it displays nicely.
stat_t set_ui8(nvObj_t *nv) {
*((uint8_t *)GET_TABLE_WORD(target)) = nv->value;
nv->valuetype = TYPE_INTEGER;
- return(STAT_OK);
+ return STAT_OK;
}
stat_t set_int(nvObj_t *nv) {
*((uint32_t *)GET_TABLE_WORD(target)) = (uint32_t)nv->value;
nv->valuetype = TYPE_INTEGER;
- return(STAT_OK);
+ return STAT_OK;
}
uint32_t *v = (uint32_t*)&nv->value;
*((uint32_t *)GET_TABLE_WORD(target)) = *v;
nv->valuetype = TYPE_DATA;
- return(STAT_OK);
+ return STAT_OK;
}
*((float *)GET_TABLE_WORD(target)) = nv->value;
nv->precision = GET_TABLE_WORD(precision);
nv->valuetype = TYPE_FLOAT;
- return(STAT_OK);
+ return STAT_OK;
}
for (i = 0; i < index_max; i++) {
if ((c = GET_TOKEN_BYTE(token[0])) != str[0]) continue; // 1st character mismatch
- if ((c = GET_TOKEN_BYTE(token[1])) == 0) {if (str[1] == 0) return(i);} // one character match
+ if ((c = GET_TOKEN_BYTE(token[1])) == 0) {if (str[1] == 0) return i;} // one character match
if (c != str[1]) continue; // 2nd character mismatch
- if ((c = GET_TOKEN_BYTE(token[2])) == 0) {if (str[2] == 0) return(i);} // two character match
+ if ((c = GET_TOKEN_BYTE(token[2])) == 0) {if (str[2] == 0) return i;} // two character match
if (c != str[2]) continue; // 3rd character mismatch
- if ((c = GET_TOKEN_BYTE(token[3])) == 0) {if (str[3] == 0) return(i);} // three character match
+ if ((c = GET_TOKEN_BYTE(token[3])) == 0) {if (str[3] == 0) return i;} // three character match
if (c != str[3]) continue; // 4th character mismatch
- if ((c = GET_TOKEN_BYTE(token[4])) == 0) {if (str[4] == 0) return(i);} // four character match
+ if ((c = GET_TOKEN_BYTE(token[4])) == 0) {if (str[4] == 0) return i;} // four character match
if (c != str[4]) continue; // 5th character mismatch
return i; // five character match
}
nvObj_t *nv = nv_body;
for (uint8_t i=0; i<NV_BODY_LEN; i++) {
if (nv->valuetype != TYPE_EMPTY) {
- if ((nv = nv->nx) == 0) return(0); // not supposed to find a 0; here for safety
+ if ((nv = nv->nx) == 0) return 0; // not supposed to find a 0; here for safety
continue;
}
nvObj_t *nv = nv_body;
for (uint8_t i=0; i<NV_BODY_LEN; i++) {
if (nv->valuetype != TYPE_EMPTY) {
- if ((nv = nv->nx) == 0) return(0); // not supposed to find a 0; here for safety
+ if ((nv = nv->nx) == 0) return 0; // not supposed to find a 0; here for safety
continue;
}
nvObj_t *nv = nv_body;
for (uint8_t i=0; i<NV_BODY_LEN; i++) {
if (nv->valuetype != TYPE_EMPTY) {
- if ((nv = nv->nx) == 0) return(0); // not supposed to find a 0; here for safety
+ if ((nv = nv->nx) == 0) return 0; // not supposed to find a 0; here for safety
continue;
}
nvObj_t *nv = nv_body;
for (uint8_t i=0; i<NV_BODY_LEN; i++) {
if (nv->valuetype != TYPE_EMPTY) {
- if ((nv = nv->nx) == 0) return(0); // not supposed to find a 0; here for safety
+ if ((nv = nv->nx) == 0) return 0; // not supposed to find a 0; here for safety
continue;
}
float en_read_encoder(uint8_t motor)
{
- return((float)en.en[motor].encoder_steps);
+ return (float)en.en[motor].encoder_steps;
}
// queue a "(MSG" response
if (*msg) cm_message(msg); // queue the message
- return(_parse_gcode_block(block));
+ return _parse_gcode_block(block);
}
/*
char *end;
*value = strtof(*pstr, &end);
if(end == *pstr)
- return(STAT_BAD_NUMBER_FORMAT); // more robust test then checking for value=0;
+ return STAT_BAD_NUMBER_FORMAT; // more robust test then checking for value=0;
*pstr = end;
return STAT_OK; // pointer points to next character after the word
}
*/
static uint8_t _point(float value)
{
- return((uint8_t)(value*10 - trunc(value)*10)); // isolate the decimal point as an int
+ return (uint8_t)(value*10 - trunc(value)*10); // isolate the decimal point as an int
}
/*
stat_t gc_run_gc(nvObj_t *nv)
{
- return(gc_gcode_parser(*nv->stringp));
+ return gc_gcode_parser(*nv->stringp);
}
#ifndef GCODE_PARSER_H_ONCE
#define GCODE_PARSER_H_ONCE
-/*
- * Global Scope Functions
- */
stat_t gc_gcode_parser(char_t *block);
stat_t gc_get_gc(nvObj_t *nv);
stat_t gc_run_gc(nvObj_t *nv);
-#endif // End of include guard: GCODE_PARSER_H_ONCE
+#endif // GCODE_PARSER_H_ONCE
/// hw_run_boot() - invoke boot form the cfgArray
stat_t hw_run_boot(nvObj_t *nv) {
hw_request_bootloader();
- return(STAT_OK);
+ return STAT_OK;
}
* b0 (out) step (SET is step, CLR is rest)
* b1 (out) direction (CLR = Clockwise)
* b2 (out) motor enable (CLR = Enabled)
- * b3 (out) microstep 0
- * b4 (out) microstep 1
+ * b3 (out) chip select
+ * b4 (in) fault
* b5 (out) output bit for GPIO port1
- * b6 (in) min limit switch on GPIO 2 (note: motor controls and GPIO2 port mappings are not the same)
- * b7 (in) max limit switch on GPIO 2 (note: motor controls and GPIO2 port mappings are not the same)
+ * b6 (in) min limit switch on GPIO 2 (note: motor controls and GPIO2 port mappings are not the same)
+ * b7 (in) max limit switch on GPIO 2 (note: motor controls and GPIO2 port mappings are not the same)
*/
#define MOTOR_PORT_DIR_gm 0x3F // dir settings: lower 6 out, upper 2 in
STEP_BIT_bp = 0, // bit 0
DIRECTION_BIT_bp, // bit 1
MOTOR_ENABLE_BIT_bp, // bit 2
- MICROSTEP_BIT_0_bp, // bit 3
- MICROSTEP_BIT_1_bp, // bit 4
+ CHIP_SELECT_BIT_bp, // bit 3
+ FAULT_BIT_bp, // bit 4
GPIO1_OUT_BIT_bp, // bit 5 (4 gpio1 output bits; 1 from each axis)
SW_MIN_BIT_bp, // bit 6 (4 input bits for homing/limit switches)
SW_MAX_BIT_bp // bit 7 (4 input bits for homing/limit switches)
#define STEP_BIT_bm (1 << STEP_BIT_bp)
#define DIRECTION_BIT_bm (1 << DIRECTION_BIT_bp)
#define MOTOR_ENABLE_BIT_bm (1 << MOTOR_ENABLE_BIT_bp)
-#define MICROSTEP_BIT_0_bm (1 << MICROSTEP_BIT_0_bp)
-#define MICROSTEP_BIT_1_bm (1 << MICROSTEP_BIT_1_bp)
+#define CHIP_SELECT_BIT_bm (1 << CHIP_SELECT_BIT_bp)
+#define FAULT_BIT_bm (1 << FAULT_BIT_bp)
#define GPIO1_OUT_BIT_bm (1 << GPIO1_OUT_BIT_bp) // spindle and coolant output bits
#define SW_MIN_BIT_bm (1 << SW_MIN_BIT_bp) // minimum switch inputs
#define SW_MAX_BIT_bm (1 << SW_MAX_BIT_bp) // maximum switch inputs
_status_report_advisory();
_postscript();
rpt_print_system_ready_message();
-return(STAT_OK);
+return STAT_OK;
}
/*
"));
_status_report_advisory();
_postscript();
-return(STAT_OK);
+return STAT_OK;
}
/*
Homing is the exception. No initial position or clearance is assumed\n\
"));
_postscript();
-return(STAT_OK);
+return STAT_OK;
}
/*
Enter $defa=1 to reset the system to the factory default values.\n\
This will overwrite any changes you have made.\n"));
_postscript();
-return(STAT_OK);
+return STAT_OK;
}
/*
fprintf_P(stderr, PSTR("\
Enter $boot=1 to enter the boot loader.\n"));
_postscript();
-return(STAT_OK);
+return STAT_OK;
}
#endif // __HELP_SCREENS
nv->valuetype = TYPE_PARENT;
// *depth += 1; // nv_reset_nv() sets the next object's level so this is redundant
(*pstr)++;
- return(STAT_EAGAIN); // signal that there is more to parse
+ return STAT_EAGAIN; // signal that there is more to parse
// strings
} else if (**pstr == '\"') { // value is a string
if (nv->value >= JV_LINENUM) { js.echo_json_linenum = true;}
if (nv->value >= JV_VERBOSE) { js.echo_json_gcode_block = true;}
- return(STAT_OK);
+ return STAT_OK;
}
stat_t write_persistent_value(nvObj_t *nv) {
if (cm.cycle_state != CYCLE_OFF)
- return(rpt_exception(STAT_FILE_NOT_OPEN)); // can't write when machine is moving
+ return rpt_exception(STAT_FILE_NOT_OPEN); // can't write when machine is moving
nvm.tmp_value = nv->value;
ritorno(read_persistent_value(nv));
if (cm.motion_state == MOTION_STOP) cm_set_motion_state(MOTION_RUN);
}
if (bf->bf_func == 0)
- return(cm_hard_alarm(STAT_INTERNAL_ERROR)); // never supposed to get here
+ return cm_hard_alarm(STAT_INTERNAL_ERROR); // never supposed to get here
return bf->bf_func(bf); // run the move callback in the planner buffer
}
if (mr.section == SECTION_BODY) { status = _exec_aline_body();} else
if (mr.section == SECTION_TAIL) { status = _exec_aline_tail();} else
if (mr.move_state == MOVE_SKIP_BLOCK) { status = STAT_OK;}
- else { return(cm_hard_alarm(STAT_INTERNAL_ERROR));} // never supposed to get here
+ else { return cm_hard_alarm(STAT_INTERNAL_ERROR);} // never supposed to get here
// Feedhold processing. Refer to canonical_machine.h for state machine
// Catch the feedhold request and start the planning the hold
if (mr.section_state == SECTION_NEW) { // initialize the move singleton (mr)
if (fp_ZERO(mr.head_length)) {
mr.section = SECTION_BODY;
- return(_exec_aline_body()); // skip ahead to the body generator
+ return _exec_aline_body(); // skip ahead to the body generator
}
mr.midpoint_velocity = (mr.entry_velocity + mr.cruise_velocity) / 2;
mr.gm.move_time = mr.head_length / mr.midpoint_velocity; // time for entire accel region
mr.elapsed_accel_time = mr.segment_accel_time / 2; // elapsed time starting point (offset)
mr.segment_count = (uint32_t)mr.segments;
if (mr.segment_time < MIN_SEGMENT_TIME)
- return(STAT_MINIMUM_TIME_MOVE); // exit without advancing position
+ return STAT_MINIMUM_TIME_MOVE; // exit without advancing position
mr.section = SECTION_HEAD;
mr.section_state = SECTION_1st_HALF;
}
mr.section_state = SECTION_2nd_HALF;
mr.elapsed_accel_time = mr.segment_accel_time / 2; // start time from midpoint of segment
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
if (mr.section_state == SECTION_2nd_HALF) { // SECOND HAF (convex part of accel curve)
mr.segment_velocity = mr.midpoint_velocity +
(square(mr.elapsed_accel_time) * mr.jerk_div2);
if (_exec_aline_segment() == STAT_OK) { // OK means this section is done
if ((fp_ZERO(mr.body_length)) && (fp_ZERO(mr.tail_length)))
- return(STAT_OK); // ends the move
+ return STAT_OK; // ends the move
mr.section = SECTION_BODY;
mr.section_state = SECTION_NEW;
}
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
#else // __ JERK_EXEC
if (mr.section_state == SECTION_NEW) { // initialize the move singleton (mr)
if (fp_ZERO(mr.head_length)) {
mr.section = SECTION_BODY;
- return(_exec_aline_body()); // skip ahead to the body generator
+ return _exec_aline_body(); // skip ahead to the body generator
}
mr.gm.move_time = 2*mr.head_length / (mr.entry_velocity + mr.cruise_velocity);// time for entire accel region
mr.segments = ceil(uSec(mr.gm.move_time) / NOM_SEGMENT_USEC);// # of segments for the section
_init_forward_diffs(mr.entry_velocity, mr.cruise_velocity);
mr.segment_count = (uint32_t)mr.segments;
if (mr.segment_time < MIN_SEGMENT_TIME)
- return(STAT_MINIMUM_TIME_MOVE); // exit without advancing position
+ return STAT_MINIMUM_TIME_MOVE; // exit without advancing position
mr.section = SECTION_HEAD;
mr.section_state = SECTION_1st_HALF; // Note: Set to SECTION_1st_HALF for one segment
}
} else {
mr.section_state = SECTION_2nd_HALF;
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
if (mr.section_state == SECTION_2nd_HALF) { // SECOND HALF (convex part of accel curve)
#ifndef __KAHAN
if (_exec_aline_segment() == STAT_OK) { // set up for body
if ((fp_ZERO(mr.body_length)) && (fp_ZERO(mr.tail_length)))
- return(STAT_OK); // ends the move
+ return STAT_OK; // ends the move
mr.section = SECTION_BODY;
mr.section_state = SECTION_NEW;
} else {
#endif
}
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
#endif // __ JERK_EXEC
if (mr.section_state == SECTION_NEW) {
if (fp_ZERO(mr.body_length)) {
mr.section = SECTION_TAIL;
- return(_exec_aline_tail()); // skip ahead to tail periods
+ return _exec_aline_tail(); // skip ahead to tail periods
}
mr.gm.move_time = mr.body_length / mr.cruise_velocity;
mr.segments = ceil(uSec(mr.gm.move_time) / NOM_SEGMENT_USEC);
mr.segment_velocity = mr.cruise_velocity;
mr.segment_count = (uint32_t)mr.segments;
if (mr.segment_time < MIN_SEGMENT_TIME)
- return(STAT_MINIMUM_TIME_MOVE); // exit without advancing position
+ return STAT_MINIMUM_TIME_MOVE; // exit without advancing position
mr.section = SECTION_BODY;
mr.section_state = SECTION_2nd_HALF; // uses PERIOD_2 so last segment detection works
}
if (mr.section_state == SECTION_2nd_HALF) { // straight part (period 3)
if (_exec_aline_segment() == STAT_OK) { // OK means this section is done
if (fp_ZERO(mr.tail_length))
- return(STAT_OK); // ends the move
+ return STAT_OK; // ends the move
mr.section = SECTION_TAIL;
mr.section_state = SECTION_NEW;
}
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
/*********************************************************************************************
{
if (mr.section_state == SECTION_NEW) { // INITIALIZATION
if (fp_ZERO(mr.tail_length))
- return(STAT_OK); // end the move
+ return STAT_OK; // end the move
mr.midpoint_velocity = (mr.cruise_velocity + mr.exit_velocity) / 2;
mr.gm.move_time = mr.tail_length / mr.midpoint_velocity;
mr.segments = ceil(uSec(mr.gm.move_time) / (2 * NOM_SEGMENT_USEC));// # of segments in *each half*
mr.elapsed_accel_time = mr.segment_accel_time / 2; //compute time from midpoint of segment
mr.segment_count = (uint32_t)mr.segments;
if (mr.segment_time < MIN_SEGMENT_TIME)
- return(STAT_MINIMUM_TIME_MOVE); // exit without advancing position
+ return STAT_MINIMUM_TIME_MOVE; // exit without advancing position
mr.section = SECTION_TAIL;
mr.section_state = SECTION_1st_HALF;
}
mr.section_state = SECTION_2nd_HALF;
mr.elapsed_accel_time = mr.segment_accel_time / 2; // start time from midpoint of segment
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
if (mr.section_state == SECTION_2nd_HALF) { // SECOND HALF - concave part (period 5)
mr.segment_velocity = mr.midpoint_velocity -
(square(mr.elapsed_accel_time) * mr.jerk_div2);
return _exec_aline_segment(); // ends the move or continues EAGAIN
}
- return(STAT_EAGAIN); // should never get here
+ return STAT_EAGAIN; // should never get here
}
#else // __JERK_EXEC -- run forward differencing math
{
if (mr.section_state == SECTION_NEW) { // INITIALIZATION
if (fp_ZERO(mr.tail_length))
- return(STAT_OK); // end the move
+ return STAT_OK; // end the move
mr.gm.move_time = 2*mr.tail_length / (mr.cruise_velocity + mr.exit_velocity); // len/avg. velocity
mr.segments = ceil(uSec(mr.gm.move_time) / NOM_SEGMENT_USEC);// # of segments for the section
mr.segment_time = mr.gm.move_time / mr.segments; // time to advance for each segment
_init_forward_diffs(mr.cruise_velocity, mr.exit_velocity);
mr.segment_count = (uint32_t)mr.segments;
if (mr.segment_time < MIN_SEGMENT_TIME)
- return(STAT_MINIMUM_TIME_MOVE); // exit without advancing position
+ return STAT_MINIMUM_TIME_MOVE; // exit without advancing position
mr.section = SECTION_TAIL;
mr.section_state = SECTION_1st_HALF;
}
} else {
mr.section_state = SECTION_2nd_HALF;
}
- return(STAT_EAGAIN);
+ return STAT_EAGAIN;
}
if (mr.section_state == SECTION_2nd_HALF) { // SECOND HALF - concave part (period 5)
#ifndef __KAHAN
#endif
}
}
- return(STAT_EAGAIN); // should never get here
+ return STAT_EAGAIN; // should never get here
}
#endif // __JERK_EXEC
// get a cleared buffer and setup move variables
if ((bf = mp_get_write_buffer()) == 0)
- return(cm_hard_alarm(STAT_BUFFER_FULL_FATAL)); // never supposed to fail
+ return cm_hard_alarm(STAT_BUFFER_FULL_FATAL); // never supposed to fail
bf->bf_func = mp_exec_aline; // register the callback to the exec function
bf->length = length;
memcpy(&bf->gm, gm_in, sizeof(GCodeState_t)); // copy model state into planner buffer
* e) Vf = L^(2/3) * Jm^(1/3) + Vi
*
* FYI: Here's an expression that returns the jerk for a given deltaV and L:
- * return(cube(deltaV / (pow(L, 0.66666666))));
+ * return cube(deltaV / (pow(L, 0.66666666)));
*/
float mp_get_target_length(const float Vi, const float Vf, const mpBuf_t *bf)
mpBuf_t *bf;
if ((bf = mp_get_write_buffer()) == 0) // get write buffer or fail
- return(cm_hard_alarm(STAT_BUFFER_FULL_FATAL)); // not ever supposed to fail
+ return cm_hard_alarm(STAT_BUFFER_FULL_FATAL); // not ever supposed to fail
bf->bf_func = _exec_dwell; // register callback to dwell start
bf->gm.move_time = seconds; // in seconds, not minutes
mpBuf_t * mp_get_first_buffer()
{
- return(mp_get_run_buffer()); // returns buffer or 0 if nothing's running
+ return mp_get_run_buffer(); // returns buffer or 0 if nothing's running
}
mpBuf_t * mp_get_last_buffer()
mpBuf_t *bf = mp_get_run_buffer();
mpBuf_t *bp = bf;
- if (bf == 0) return(0);
+ if (bf == 0) return 0;
do {
if ((bp->nx->move_state == MOVE_OFF) || (bp->nx == bf)) {
TINYG_FIRMWARE_BUILD, status, get_status_message(status));
}
}
- return status; // makes it possible to inline, e.g: return(rpt_exception(status));
+ return status; // makes it possible to inline, e.g: return rpt_exception(status);
}
/*
*/
stat_t rpt_er(nvObj_t *nv)
{
- return(rpt_exception(STAT_GENERIC_EXCEPTION_REPORT)); // bogus exception report for testing
+ return rpt_exception(STAT_GENERIC_EXCEPTION_REPORT); // bogus exception report for testing
}
/**** Application Messages *********************************************************
if (elements == 0)
return STAT_INVALID_OR_MALFORMED_COMMAND;
memcpy(sr.status_report_list, status_report_list, sizeof(status_report_list));
- return(_populate_unfiltered_status_report()); // return current values
+ return _populate_unfiltered_status_report(); // return current values
}
/*
{
if (nv->value < STATUS_REPORT_MIN_MS) { nv->value = STATUS_REPORT_MIN_MS;}
sr.status_report_interval = (uint32_t)nv->value;
- return(STAT_OK);
+ return STAT_OK;
}
/*********************
{
float value[AXES] = { (float)spindle_mode, 0,0,0,0,0 };
mp_queue_command(_exec_spindle_control, value, value);
- return(STAT_OK);
+ return STAT_OK;
}
//static void _exec_spindle_control(uint8_t spindle_mode, float f, float *vector, float *flag)
#include "text_parser.h"
#include "util.h"
-/**** Allocate structures ****/
stConfig_t st_cfg;
stPrepSingleton_t st_pre;
static stRunSingleton_t st_run;
-/**** Setup local functions ****/
-
static void _load_move();
static void _request_load_move();
+
// handy macro
#define _f_to_period(f) (uint16_t)((float)F_CPU / (float)f)
+
/*
* stepper_init() - initialize stepper motor subsystem
*
* Notes:
* - This init requires sys_init() to be run beforehand
- * - microsteps are setup during config_init()
+ * - microsteps are setup during config_init()
* - motor polarity is setup during config_init()
* - high level interrupts must be enabled in main() once all inits are complete
*/
* pmc_enable_periph_clk(TC_ID_DDA);
* TC_Start(TC_BLOCK_DDA, TC_CHANNEL_DDA);
*/
+void stepper_init() {
+ memset(&st_run, 0, sizeof(st_run)); // clear all values, pointers and status
+ stepper_init_assertions();
-void stepper_init()
-{
- memset(&st_run, 0, sizeof(st_run)); // clear all values, pointers and status
- stepper_init_assertions();
+ // Configure virtual ports
+ PORTCFG.VPCTRLA = PORTCFG_VP0MAP_PORT_MOTOR_1_gc | PORTCFG_VP1MAP_PORT_MOTOR_2_gc;
+ PORTCFG.VPCTRLB = PORTCFG_VP2MAP_PORT_MOTOR_3_gc | PORTCFG_VP3MAP_PORT_MOTOR_4_gc;
- // Configure virtual ports
- PORTCFG.VPCTRLA = PORTCFG_VP0MAP_PORT_MOTOR_1_gc | PORTCFG_VP1MAP_PORT_MOTOR_2_gc;
- PORTCFG.VPCTRLB = PORTCFG_VP2MAP_PORT_MOTOR_3_gc | PORTCFG_VP3MAP_PORT_MOTOR_4_gc;
+ // setup ports and data structures
+ for (uint8_t i = 0; i < MOTORS; i++) {
+ hw.st_port[i]->DIR = MOTOR_PORT_DIR_gm; // sets outputs for motors & GPIO1, and GPIO2 inputs
+ hw.st_port[i]->OUT = MOTOR_ENABLE_BIT_bm; // zero port bits AND disable motor
+ }
- // setup ports and data structures
- for (uint8_t i=0; i<MOTORS; i++) {
- hw.st_port[i]->DIR = MOTOR_PORT_DIR_gm; // sets outputs for motors & GPIO1, and GPIO2 inputs
- hw.st_port[i]->OUT = MOTOR_ENABLE_BIT_bm;// zero port bits AND disable motor
- }
- // setup DDA timer
- TIMER_DDA.CTRLA = STEP_TIMER_DISABLE; // turn timer off
- TIMER_DDA.CTRLB = STEP_TIMER_WGMODE; // waveform mode
- TIMER_DDA.INTCTRLA = TIMER_DDA_INTLVL; // interrupt mode
+ // setup DDA timer
+ TIMER_DDA.CTRLA = STEP_TIMER_DISABLE; // turn timer off
+ TIMER_DDA.CTRLB = STEP_TIMER_WGMODE; // waveform mode
+ TIMER_DDA.INTCTRLA = TIMER_DDA_INTLVL; // interrupt mode
- // setup DWELL timer
- TIMER_DWELL.CTRLA = STEP_TIMER_DISABLE; // turn timer off
- TIMER_DWELL.CTRLB = STEP_TIMER_WGMODE; // waveform mode
- TIMER_DWELL.INTCTRLA = TIMER_DWELL_INTLVL; // interrupt mode
+ // setup DWELL timer
+ TIMER_DWELL.CTRLA = STEP_TIMER_DISABLE; // turn timer off
+ TIMER_DWELL.CTRLB = STEP_TIMER_WGMODE; // waveform mode
+ TIMER_DWELL.INTCTRLA = TIMER_DWELL_INTLVL; // interrupt mode
- // setup software interrupt load timer
- TIMER_LOAD.CTRLA = LOAD_TIMER_DISABLE; // turn timer off
- TIMER_LOAD.CTRLB = LOAD_TIMER_WGMODE; // waveform mode
- TIMER_LOAD.INTCTRLA = TIMER_LOAD_INTLVL; // interrupt mode
- TIMER_LOAD.PER = LOAD_TIMER_PERIOD; // set period
+ // setup software interrupt load timer
+ TIMER_LOAD.CTRLA = LOAD_TIMER_DISABLE; // turn timer off
+ TIMER_LOAD.CTRLB = LOAD_TIMER_WGMODE; // waveform mode
+ TIMER_LOAD.INTCTRLA = TIMER_LOAD_INTLVL; // interrupt mode
+ TIMER_LOAD.PER = LOAD_TIMER_PERIOD; // set period
- // setup software interrupt exec timer
- TIMER_EXEC.CTRLA = EXEC_TIMER_DISABLE; // turn timer off
- TIMER_EXEC.CTRLB = EXEC_TIMER_WGMODE; // waveform mode
- TIMER_EXEC.INTCTRLA = TIMER_EXEC_INTLVL; // interrupt mode
- TIMER_EXEC.PER = EXEC_TIMER_PERIOD; // set period
+ // setup software interrupt exec timer
+ TIMER_EXEC.CTRLA = EXEC_TIMER_DISABLE; // turn timer off
+ TIMER_EXEC.CTRLB = EXEC_TIMER_WGMODE; // waveform mode
+ TIMER_EXEC.INTCTRLA = TIMER_EXEC_INTLVL; // interrupt mode
+ TIMER_EXEC.PER = EXEC_TIMER_PERIOD; // set period
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC;
- st_reset(); // reset steppers to known state
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC;
+ st_reset(); // reset steppers to known state
}
+
/*
* stepper_init_assertions() - test assertions, return error code if violation exists
* stepper_test_assertions() - test assertions, return error code if violation exists
*/
-
-void stepper_init_assertions()
-{
- st_run.magic_end = MAGICNUM;
- st_run.magic_start = MAGICNUM;
- st_pre.magic_end = MAGICNUM;
- st_pre.magic_start = MAGICNUM;
+void stepper_init_assertions() {
+ st_run.magic_end = MAGICNUM;
+ st_run.magic_start = MAGICNUM;
+ st_pre.magic_end = MAGICNUM;
+ st_pre.magic_start = MAGICNUM;
}
-stat_t stepper_test_assertions()
-{
- if (st_run.magic_end != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
- if (st_run.magic_start != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
- if (st_pre.magic_end != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
- if (st_pre.magic_start != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
- return STAT_OK;
+
+stat_t stepper_test_assertions() {
+ if (st_run.magic_end != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
+ if (st_run.magic_start != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
+ if (st_pre.magic_end != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
+ if (st_pre.magic_start != MAGICNUM) return STAT_STEPPER_ASSERTION_FAILURE;
+
+ return STAT_OK;
}
+
/*
* st_runtime_isbusy() - return TRUE if runtime is busy:
*
* - motors are running
* - dwell is running
*/
-
-uint8_t st_runtime_isbusy()
-{
- if (st_run.dda_ticks_downcount == 0) {
- return false;
- }
- return true;
+uint8_t st_runtime_isbusy() {
+ return st_run.dda_ticks_downcount != 0;
}
-/*
- * st_reset() - reset stepper internals
- */
-void st_reset()
-{
- for (uint8_t motor=0; motor<MOTORS; motor++) {
- st_pre.mot[motor].prev_direction = STEP_INITIAL_DIRECTION;
- st_run.mot[motor].substep_accumulator = 0; // will become max negative during per-motor setup;
- st_pre.mot[motor].corrected_steps = 0; // diagnostic only - no action effect
- }
- mp_set_steps_to_runtime_position();
+/// Reset stepper internals
+void st_reset() {
+ for (uint8_t motor = 0; motor < MOTORS; motor++) {
+ st_pre.mot[motor].prev_direction = STEP_INITIAL_DIRECTION;
+ st_run.mot[motor].substep_accumulator = 0; // will become max negative during per-motor setup;
+ st_pre.mot[motor].corrected_steps = 0; // diagnostic only - no action effect
+ }
+
+ mp_set_steps_to_runtime_position();
}
-/*
- * st_clc() - clear counters
- */
-stat_t st_clc(nvObj_t *nv) // clear diagnostic counters, reset stepper prep
-{
- st_reset();
- return(STAT_OK);
+/// Clear counters
+stat_t st_clc(nvObj_t *nv) {
+ // clear diagnostic counters, reset stepper prep
+ st_reset();
+ return STAT_OK;
}
/*
* st_deenergize_motors() - remove power from all motors
* st_motor_power_callback() - callback to manage motor power sequencing
*/
+static uint8_t _motor_is_enabled(uint8_t motor) {
+ uint8_t port;
+ switch(motor) {
+ case (MOTOR_1): port = PORT_MOTOR_1_VPORT.OUT; break;
+ case (MOTOR_2): port = PORT_MOTOR_2_VPORT.OUT; break;
+ case (MOTOR_3): port = PORT_MOTOR_3_VPORT.OUT; break;
+ case (MOTOR_4): port = PORT_MOTOR_4_VPORT.OUT; break;
+ default: port = 0xff; // defaults to disabled for bad motor input value
+ }
-static uint8_t _motor_is_enabled(uint8_t motor)
-{
- uint8_t port;
- switch(motor) {
- case (MOTOR_1): { port = PORT_MOTOR_1_VPORT.OUT; break; }
- case (MOTOR_2): { port = PORT_MOTOR_2_VPORT.OUT; break; }
- case (MOTOR_3): { port = PORT_MOTOR_3_VPORT.OUT; break; }
- case (MOTOR_4): { port = PORT_MOTOR_4_VPORT.OUT; break; }
- default: port = 0xff; // defaults to disabled for bad motor input value
- }
- return (port & MOTOR_ENABLE_BIT_bm ? 0 : 1); // returns 1 if motor is enabled (motor is actually active low)
+ return port & MOTOR_ENABLE_BIT_bm ? 0 : 1; // returns 1 if motor is enabled (motor is actually active low)
}
-static void _deenergize_motor(const uint8_t motor)
-{
- switch (motor) {
- case (MOTOR_1): { PORT_MOTOR_1_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_2): { PORT_MOTOR_2_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_3): { PORT_MOTOR_3_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_4): { PORT_MOTOR_4_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break; }
- }
- st_run.mot[motor].power_state = MOTOR_OFF;
+
+static void _deenergize_motor(const uint8_t motor) {
+ switch (motor) {
+ case (MOTOR_1): PORT_MOTOR_1_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_2): PORT_MOTOR_2_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_3): PORT_MOTOR_3_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_4): PORT_MOTOR_4_VPORT.OUT |= MOTOR_ENABLE_BIT_bm; break;
+ }
+
+ st_run.mot[motor].power_state = MOTOR_OFF;
}
-static void _energize_motor(const uint8_t motor)
-{
- if (st_cfg.mot[motor].power_mode == MOTOR_DISABLED) {
- _deenergize_motor(motor);
- return;
- }
- switch(motor) {
- case (MOTOR_1): { PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_2): { PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_3): { PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break; }
- case (MOTOR_4): { PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break; }
- }
+static void _energize_motor(const uint8_t motor) {
+ if (st_cfg.mot[motor].power_mode == MOTOR_DISABLED) {
+ _deenergize_motor(motor);
+ return;
+ }
- st_run.mot[motor].power_state = MOTOR_POWER_TIMEOUT_START;
+ switch(motor) {
+ case (MOTOR_1): PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_2): PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_3): PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break;
+ case (MOTOR_4): PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; break;
+ }
+
+ st_run.mot[motor].power_state = MOTOR_POWER_TIMEOUT_START;
}
-void st_energize_motors()
-{
- for (uint8_t motor = MOTOR_1; motor < MOTORS; motor++) {
- _energize_motor(motor);
- st_run.mot[motor].power_state = MOTOR_POWER_TIMEOUT_START;
- }
+
+void st_energize_motors() {
+ for (uint8_t motor = MOTOR_1; motor < MOTORS; motor++) {
+ _energize_motor(motor);
+ st_run.mot[motor].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
}
-void st_deenergize_motors()
-{
- for (uint8_t motor = MOTOR_1; motor < MOTORS; motor++) {
- _deenergize_motor(motor);
- }
+
+void st_deenergize_motors() {
+ for (uint8_t motor = MOTOR_1; motor < MOTORS; motor++)
+ _deenergize_motor(motor);
}
+
/*
* st_motor_power_callback() - callback to manage motor power sequencing
*
* Handles motor power-down timing, low-power idle, and adaptive motor power
*/
-stat_t st_motor_power_callback() // called by controller
-{
- // manage power for each motor individually
- for (uint8_t m = MOTOR_1; m < MOTORS; m++) {
-
- // de-energize motor if it's set to MOTOR_DISABLED
- if (st_cfg.mot[m].power_mode == MOTOR_DISABLED) {
- _deenergize_motor(m);
- continue;
- }
-
- // energize motor if it's set to MOTOR_ALWAYS_POWERED
- if (st_cfg.mot[m].power_mode == MOTOR_ALWAYS_POWERED) {
- if (! _motor_is_enabled(m)) _energize_motor(m);
- continue;
- }
-
- // start a countdown if MOTOR_POWERED_IN_CYCLE or MOTOR_POWERED_ONLY_WHEN_MOVING
- if (st_run.mot[m].power_state == MOTOR_POWER_TIMEOUT_START) {
- st_run.mot[m].power_state = MOTOR_POWER_TIMEOUT_COUNTDOWN;
- st_run.mot[m].power_systick = SysTickTimer_getValue() +
- (st_cfg.motor_power_timeout * 1000);
- }
-
- // do not process countdown if in a feedhold
- if (cm_get_combined_state() == COMBINED_HOLD) {
- continue;
- }
-
- // do not process countdown if in a feedhold
- if (cm_get_combined_state() == COMBINED_HOLD) {
- continue;
- }
-
- // run the countdown if you are in a countdown
- if (st_run.mot[m].power_state == MOTOR_POWER_TIMEOUT_COUNTDOWN) {
- if (SysTickTimer_getValue() > st_run.mot[m].power_systick ) {
- st_run.mot[m].power_state = MOTOR_IDLE;
- _deenergize_motor(m);
- sr_request_status_report(SR_TIMED_REQUEST); // request a status report when motors shut down
- }
- }
+stat_t st_motor_power_callback() { // called by controller
+ // manage power for each motor individually
+ for (uint8_t m = MOTOR_1; m < MOTORS; m++) {
+
+ // de-energize motor if it's set to MOTOR_DISABLED
+ if (st_cfg.mot[m].power_mode == MOTOR_DISABLED) {
+ _deenergize_motor(m);
+ continue;
}
- return STAT_OK;
-}
-
-/******************************
- * Interrupt Service Routines *
- ******************************/
-
-/***** Stepper Interrupt Service Routine ************************************************
- * ISR - DDA timer interrupt routine - service ticks from DDA timer
- */
+ // energize motor if it's set to MOTOR_ALWAYS_POWERED
+ if (st_cfg.mot[m].power_mode == MOTOR_ALWAYS_POWERED) {
+ if (! _motor_is_enabled(m)) _energize_motor(m);
+ continue;
+ }
-/*
- * Uses direct struct addresses and literal values for hardware devices - it's faster than
- * using indexed timer and port accesses. I checked. Even when -0s or -03 is used.
- */
-ISR(TIMER_DDA_ISR_vect)
-{
- if ((st_run.mot[MOTOR_1].substep_accumulator += st_run.mot[MOTOR_1].substep_increment) > 0) {
- PORT_MOTOR_1_VPORT.OUT |= STEP_BIT_bm; // turn step bit on
- st_run.mot[MOTOR_1].substep_accumulator -= st_run.dda_ticks_X_substeps;
- INCREMENT_ENCODER(MOTOR_1);
+ // start a countdown if MOTOR_POWERED_IN_CYCLE or MOTOR_POWERED_ONLY_WHEN_MOVING
+ if (st_run.mot[m].power_state == MOTOR_POWER_TIMEOUT_START) {
+ st_run.mot[m].power_state = MOTOR_POWER_TIMEOUT_COUNTDOWN;
+ st_run.mot[m].power_systick = SysTickTimer_getValue() +
+ (st_cfg.motor_power_timeout * 1000);
}
- if ((st_run.mot[MOTOR_2].substep_accumulator += st_run.mot[MOTOR_2].substep_increment) > 0) {
- PORT_MOTOR_2_VPORT.OUT |= STEP_BIT_bm;
- st_run.mot[MOTOR_2].substep_accumulator -= st_run.dda_ticks_X_substeps;
- INCREMENT_ENCODER(MOTOR_2);
+
+ // do not process countdown if in a feedhold
+ if (cm_get_combined_state() == COMBINED_HOLD) {
+ continue;
}
- if ((st_run.mot[MOTOR_3].substep_accumulator += st_run.mot[MOTOR_3].substep_increment) > 0) {
- PORT_MOTOR_3_VPORT.OUT |= STEP_BIT_bm;
- st_run.mot[MOTOR_3].substep_accumulator -= st_run.dda_ticks_X_substeps;
- INCREMENT_ENCODER(MOTOR_3);
+
+ // do not process countdown if in a feedhold
+ if (cm_get_combined_state() == COMBINED_HOLD) {
+ continue;
}
- if ((st_run.mot[MOTOR_4].substep_accumulator += st_run.mot[MOTOR_4].substep_increment) > 0) {
- PORT_MOTOR_4_VPORT.OUT |= STEP_BIT_bm;
- st_run.mot[MOTOR_4].substep_accumulator -= st_run.dda_ticks_X_substeps;
- INCREMENT_ENCODER(MOTOR_4);
+
+ // run the countdown if you are in a countdown
+ if (st_run.mot[m].power_state == MOTOR_POWER_TIMEOUT_COUNTDOWN) {
+ if (SysTickTimer_getValue() > st_run.mot[m].power_systick ) {
+ st_run.mot[m].power_state = MOTOR_IDLE;
+ _deenergize_motor(m);
+ sr_request_status_report(SR_TIMED_REQUEST); // request a status report when motors shut down
+ }
}
+ }
- // pulse stretching for using external drivers.- turn step bits off
- PORT_MOTOR_1_VPORT.OUT &= ~STEP_BIT_bm; // ~ 5 uSec pulse width
- PORT_MOTOR_2_VPORT.OUT &= ~STEP_BIT_bm; // ~ 4 uSec
- PORT_MOTOR_3_VPORT.OUT &= ~STEP_BIT_bm; // ~ 3 uSec
- PORT_MOTOR_4_VPORT.OUT &= ~STEP_BIT_bm; // ~ 2 uSec
+ return STAT_OK;
+}
- if (--st_run.dda_ticks_downcount != 0) return;
- TIMER_DDA.CTRLA = STEP_TIMER_DISABLE; // disable DDA timer
- _load_move(); // load the next move
-}
+/***
+ Stepper Interrupt Service Routine
+ DDA timer interrupt routine - service ticks from DDA timer
+ Uses direct struct addresses and literal values for hardware devices - it's faster than
+ using indexed timer and port accesses. I checked. Even when -0s or -03 is used.
+*/
+ISR(TIMER_DDA_ISR_vect) {
+ if ((st_run.mot[MOTOR_1].substep_accumulator += st_run.mot[MOTOR_1].substep_increment) > 0) {
+ PORT_MOTOR_1_VPORT.OUT |= STEP_BIT_bm; // turn step bit on
+ st_run.mot[MOTOR_1].substep_accumulator -= st_run.dda_ticks_X_substeps;
+ INCREMENT_ENCODER(MOTOR_1);
+ }
-/***** Dwell Interrupt Service Routine **************************************************
- * ISR - DDA timer interrupt routine - service ticks from DDA timer
- */
+ if ((st_run.mot[MOTOR_2].substep_accumulator += st_run.mot[MOTOR_2].substep_increment) > 0) {
+ PORT_MOTOR_2_VPORT.OUT |= STEP_BIT_bm;
+ st_run.mot[MOTOR_2].substep_accumulator -= st_run.dda_ticks_X_substeps;
+ INCREMENT_ENCODER(MOTOR_2);
+ }
+ if ((st_run.mot[MOTOR_3].substep_accumulator += st_run.mot[MOTOR_3].substep_increment) > 0) {
+ PORT_MOTOR_3_VPORT.OUT |= STEP_BIT_bm;
+ st_run.mot[MOTOR_3].substep_accumulator -= st_run.dda_ticks_X_substeps;
+ INCREMENT_ENCODER(MOTOR_3);
+ }
+
+ if ((st_run.mot[MOTOR_4].substep_accumulator += st_run.mot[MOTOR_4].substep_increment) > 0) {
+ PORT_MOTOR_4_VPORT.OUT |= STEP_BIT_bm;
+ st_run.mot[MOTOR_4].substep_accumulator -= st_run.dda_ticks_X_substeps;
+ INCREMENT_ENCODER(MOTOR_4);
+ }
+
+ // pulse stretching for using external drivers.- turn step bits off
+ PORT_MOTOR_1_VPORT.OUT &= ~STEP_BIT_bm; // ~ 5 uSec pulse width
+ PORT_MOTOR_2_VPORT.OUT &= ~STEP_BIT_bm; // ~ 4 uSec
+ PORT_MOTOR_3_VPORT.OUT &= ~STEP_BIT_bm; // ~ 3 uSec
+ PORT_MOTOR_4_VPORT.OUT &= ~STEP_BIT_bm; // ~ 2 uSec
+
+ if (--st_run.dda_ticks_downcount != 0) return;
+
+ TIMER_DDA.CTRLA = STEP_TIMER_DISABLE; // disable DDA timer
+ _load_move(); // load the next move
+}
+
+
+/// DDA timer interrupt routine - service ticks from DDA timer
ISR(TIMER_DWELL_ISR_vect) { // DWELL timer interrupt
- if (--st_run.dda_ticks_downcount == 0) {
- TIMER_DWELL.CTRLA = STEP_TIMER_DISABLE; // disable DWELL timer
- _load_move();
- }
+ if (--st_run.dda_ticks_downcount == 0) {
+ TIMER_DWELL.CTRLA = STEP_TIMER_DISABLE; // disable DWELL timer
+ _load_move();
+ }
}
+
/****************************************************************************************
* Exec sequencing code - computes and prepares next load segment
* st_request_exec_move() - SW interrupt to request to execute a move
* exec_timer interrupt - interrupt handler for calling exec function
*/
-
-void st_request_exec_move()
-{
- if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) {// bother interrupting
- TIMER_EXEC.PER = EXEC_TIMER_PERIOD;
- TIMER_EXEC.CTRLA = EXEC_TIMER_ENABLE; // trigger a LO interrupt
- }
+void st_request_exec_move() {
+ if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) {// bother interrupting
+ TIMER_EXEC.PER = EXEC_TIMER_PERIOD;
+ TIMER_EXEC.CTRLA = EXEC_TIMER_ENABLE; // trigger a LO interrupt
+ }
}
+
ISR(TIMER_EXEC_ISR_vect) { // exec move SW interrupt
- TIMER_EXEC.CTRLA = EXEC_TIMER_DISABLE; // disable SW interrupt timer
-
- // exec_move
- if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) {
- if (mp_exec_move() != STAT_NOOP) {
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // flip it back
- _request_load_move();
- }
+ TIMER_EXEC.CTRLA = EXEC_TIMER_DISABLE; // disable SW interrupt timer
+
+ // exec_move
+ if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) {
+ if (mp_exec_move() != STAT_NOOP) {
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // flip it back
+ _request_load_move();
}
+ }
}
/****************************************************************************************
* the DDA or dwell ISR. A software interrupt has been provided to allow a non-ISR to
* request a load (see st_request_load_move())
*/
+static void _request_load_move() {
+ if (st_runtime_isbusy()) return; // don't request a load if the runtime is busy
-static void _request_load_move()
-{
- if (st_runtime_isbusy()) {
- return; // don't request a load if the runtime is busy
- }
- if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_LOADER) { // bother interrupting
- TIMER_LOAD.PER = LOAD_TIMER_PERIOD;
- TIMER_LOAD.CTRLA = LOAD_TIMER_ENABLE; // trigger a HI interrupt
- }
+ if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_LOADER) { // bother interrupting
+ TIMER_LOAD.PER = LOAD_TIMER_PERIOD;
+ TIMER_LOAD.CTRLA = LOAD_TIMER_ENABLE; // trigger a HI interrupt
+ }
}
-ISR(TIMER_LOAD_ISR_vect) { // load steppers SW interrupt
- TIMER_LOAD.CTRLA = LOAD_TIMER_DISABLE; // disable SW interrupt timer
- _load_move();
+
+ISR(TIMER_LOAD_ISR_vect) { // load steppers SW interrupt
+ TIMER_LOAD.CTRLA = LOAD_TIMER_DISABLE; // disable SW interrupt timer
+ _load_move();
}
* - If axis has 0 steps the direction setting can be omitted
* - If axis has 0 steps the motor must not be enabled to support power mode = 1
*/
-static void _load_move()
-{
- // Be aware that dda_ticks_downcount must equal zero for the loader to run.
- // So the initial load must also have this set to zero as part of initialization
- if (st_runtime_isbusy()) {
- return; // exit if the runtime is busy
- }
- if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_LOADER) { // if there are no moves to load...
- return;
+static void _load_move() {
+ // Be aware that dda_ticks_downcount must equal zero for the loader to run.
+ // So the initial load must also have this set to zero as part of initialization
+ if (st_runtime_isbusy()) return; // exit if the runtime is busy
+ if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_LOADER) return; // if there are no moves to load...
+
+ // handle aline loads first (most common case)
+ if (st_pre.move_type == MOVE_TYPE_ALINE) {
+ //**** setup the new segment ****
+ st_run.dda_ticks_downcount = st_pre.dda_ticks;
+ st_run.dda_ticks_X_substeps = st_pre.dda_ticks_X_substeps;
+
+ //**** MOTOR_1 LOAD ****
+
+ // These sections are somewhat optimized for execution speed. The whole load operation
+ // is supposed to take < 10 uSec (Xmega). Be careful if you mess with this.
+
+ // the following if() statement sets the runtime substep increment value or zeroes it
+ if ((st_run.mot[MOTOR_1].substep_increment = st_pre.mot[MOTOR_1].substep_increment) != 0) {
+ // NB: If motor has 0 steps the following is all skipped. This ensures that state comparisons
+ // always operate on the last segment actually run by this motor, regardless of how many
+ // segments it may have been inactive in between.
+
+ // Apply accumulator correction if the time base has changed since previous segment
+ if (st_pre.mot[MOTOR_1].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_1].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_1].substep_accumulator *= st_pre.mot[MOTOR_1].accumulator_correction;
+ }
+
+ // Detect direction change and if so:
+ // - Set the direction bit in hardware.
+ // - Compensate for direction change by flipping substep accumulator value about its midpoint.
+ if (st_pre.mot[MOTOR_1].direction != st_pre.mot[MOTOR_1].prev_direction) {
+ st_pre.mot[MOTOR_1].prev_direction = st_pre.mot[MOTOR_1].direction;
+ st_run.mot[MOTOR_1].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_1].substep_accumulator);
+
+ if (st_pre.mot[MOTOR_1].direction == DIRECTION_CW)
+ PORT_MOTOR_1_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_1_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ SET_ENCODER_STEP_SIGN(MOTOR_1, st_pre.mot[MOTOR_1].step_sign);
+
+ // Enable the stepper and start motor power management
+ if (st_cfg.mot[MOTOR_1].power_mode != MOTOR_DISABLED) {
+ PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; // energize motor
+ st_run.mot[MOTOR_1].power_state = MOTOR_POWER_TIMEOUT_START;// set power management state
+ }
+
+ } else if (st_cfg.mot[MOTOR_1].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ // Motor has 0 steps; might need to energize motor for power mode processing
+ PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; // energize motor
+ st_run.mot[MOTOR_1].power_state = MOTOR_POWER_TIMEOUT_START;
}
- // handle aline loads first (most common case)
- if (st_pre.move_type == MOVE_TYPE_ALINE) {
-
- //**** setup the new segment ****
-
- st_run.dda_ticks_downcount = st_pre.dda_ticks;
- st_run.dda_ticks_X_substeps = st_pre.dda_ticks_X_substeps;
-
- //**** MOTOR_1 LOAD ****
-
- // These sections are somewhat optimized for execution speed. The whole load operation
- // is supposed to take < 10 uSec (Xmega). Be careful if you mess with this.
-
- // the following if() statement sets the runtime substep increment value or zeroes it
- if ((st_run.mot[MOTOR_1].substep_increment = st_pre.mot[MOTOR_1].substep_increment) != 0) {
-
- // NB: If motor has 0 steps the following is all skipped. This ensures that state comparisons
- // always operate on the last segment actually run by this motor, regardless of how many
- // segments it may have been inactive in between.
-
- // Apply accumulator correction if the time base has changed since previous segment
- if (st_pre.mot[MOTOR_1].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_1].accumulator_correction_flag = false;
- st_run.mot[MOTOR_1].substep_accumulator *= st_pre.mot[MOTOR_1].accumulator_correction;
- }
-
- // Detect direction change and if so:
- // - Set the direction bit in hardware.
- // - Compensate for direction change by flipping substep accumulator value about its midpoint.
-
- if (st_pre.mot[MOTOR_1].direction != st_pre.mot[MOTOR_1].prev_direction) {
- st_pre.mot[MOTOR_1].prev_direction = st_pre.mot[MOTOR_1].direction;
- st_run.mot[MOTOR_1].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_1].substep_accumulator);
- if (st_pre.mot[MOTOR_1].direction == DIRECTION_CW)
- PORT_MOTOR_1_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_1_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- SET_ENCODER_STEP_SIGN(MOTOR_1, st_pre.mot[MOTOR_1].step_sign);
-
- // Enable the stepper and start motor power management
- if (st_cfg.mot[MOTOR_1].power_mode != MOTOR_DISABLED) {
- PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; // energize motor
- st_run.mot[MOTOR_1].power_state = MOTOR_POWER_TIMEOUT_START;// set power management state
- }
-
- } else { // Motor has 0 steps; might need to energize motor for power mode processing
- if (st_cfg.mot[MOTOR_1].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_1_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm; // energize motor
- st_run.mot[MOTOR_1].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- // accumulate counted steps to the step position and zero out counted steps for the segment currently being loaded
- ACCUMULATE_ENCODER(MOTOR_1);
+
+ // accumulate counted steps to the step position and zero out counted steps for the segment currently being loaded
+ ACCUMULATE_ENCODER(MOTOR_1);
#if (MOTORS >= 2) //**** MOTOR_2 LOAD ****
- if ((st_run.mot[MOTOR_2].substep_increment = st_pre.mot[MOTOR_2].substep_increment) != 0) {
- if (st_pre.mot[MOTOR_2].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_2].accumulator_correction_flag = false;
- st_run.mot[MOTOR_2].substep_accumulator *= st_pre.mot[MOTOR_2].accumulator_correction;
- }
- if (st_pre.mot[MOTOR_2].direction != st_pre.mot[MOTOR_2].prev_direction) {
- st_pre.mot[MOTOR_2].prev_direction = st_pre.mot[MOTOR_2].direction;
- st_run.mot[MOTOR_2].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_2].substep_accumulator);
- if (st_pre.mot[MOTOR_2].direction == DIRECTION_CW)
- PORT_MOTOR_2_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_2_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- SET_ENCODER_STEP_SIGN(MOTOR_2, st_pre.mot[MOTOR_2].step_sign);
- if (st_cfg.mot[MOTOR_2].power_mode != MOTOR_DISABLED) {
- PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_2].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- } else {
- if (st_cfg.mot[MOTOR_2].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_2].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- ACCUMULATE_ENCODER(MOTOR_2);
+ if ((st_run.mot[MOTOR_2].substep_increment = st_pre.mot[MOTOR_2].substep_increment) != 0) {
+ if (st_pre.mot[MOTOR_2].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_2].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_2].substep_accumulator *= st_pre.mot[MOTOR_2].accumulator_correction;
+ }
+
+ if (st_pre.mot[MOTOR_2].direction != st_pre.mot[MOTOR_2].prev_direction) {
+ st_pre.mot[MOTOR_2].prev_direction = st_pre.mot[MOTOR_2].direction;
+ st_run.mot[MOTOR_2].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_2].substep_accumulator);
+ if (st_pre.mot[MOTOR_2].direction == DIRECTION_CW)
+ PORT_MOTOR_2_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_2_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ SET_ENCODER_STEP_SIGN(MOTOR_2, st_pre.mot[MOTOR_2].step_sign);
+
+ if (st_cfg.mot[MOTOR_2].power_mode != MOTOR_DISABLED) {
+ PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_2].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+ } else if (st_cfg.mot[MOTOR_2].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ PORT_MOTOR_2_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_2].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ ACCUMULATE_ENCODER(MOTOR_2);
#endif
+
#if (MOTORS >= 3) //**** MOTOR_3 LOAD ****
- if ((st_run.mot[MOTOR_3].substep_increment = st_pre.mot[MOTOR_3].substep_increment) != 0) {
- if (st_pre.mot[MOTOR_3].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_3].accumulator_correction_flag = false;
- st_run.mot[MOTOR_3].substep_accumulator *= st_pre.mot[MOTOR_3].accumulator_correction;
- }
- if (st_pre.mot[MOTOR_3].direction != st_pre.mot[MOTOR_3].prev_direction) {
- st_pre.mot[MOTOR_3].prev_direction = st_pre.mot[MOTOR_3].direction;
- st_run.mot[MOTOR_3].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_3].substep_accumulator);
- if (st_pre.mot[MOTOR_3].direction == DIRECTION_CW)
- PORT_MOTOR_3_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_3_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- SET_ENCODER_STEP_SIGN(MOTOR_3, st_pre.mot[MOTOR_3].step_sign);
- if (st_cfg.mot[MOTOR_3].power_mode != MOTOR_DISABLED) {
- PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_3].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- } else {
- if (st_cfg.mot[MOTOR_3].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_3].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- ACCUMULATE_ENCODER(MOTOR_3);
+ if ((st_run.mot[MOTOR_3].substep_increment = st_pre.mot[MOTOR_3].substep_increment) != 0) {
+ if (st_pre.mot[MOTOR_3].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_3].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_3].substep_accumulator *= st_pre.mot[MOTOR_3].accumulator_correction;
+ }
+
+ if (st_pre.mot[MOTOR_3].direction != st_pre.mot[MOTOR_3].prev_direction) {
+ st_pre.mot[MOTOR_3].prev_direction = st_pre.mot[MOTOR_3].direction;
+ st_run.mot[MOTOR_3].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_3].substep_accumulator);
+ if (st_pre.mot[MOTOR_3].direction == DIRECTION_CW)
+ PORT_MOTOR_3_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_3_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ SET_ENCODER_STEP_SIGN(MOTOR_3, st_pre.mot[MOTOR_3].step_sign);
+
+ if (st_cfg.mot[MOTOR_3].power_mode != MOTOR_DISABLED) {
+ PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_3].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ } else if (st_cfg.mot[MOTOR_3].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ PORT_MOTOR_3_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_3].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ ACCUMULATE_ENCODER(MOTOR_3);
#endif
+
#if (MOTORS >= 4) //**** MOTOR_4 LOAD ****
- if ((st_run.mot[MOTOR_4].substep_increment = st_pre.mot[MOTOR_4].substep_increment) != 0) {
- if (st_pre.mot[MOTOR_4].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_4].accumulator_correction_flag = false;
- st_run.mot[MOTOR_4].substep_accumulator *= st_pre.mot[MOTOR_4].accumulator_correction;
- }
- if (st_pre.mot[MOTOR_4].direction != st_pre.mot[MOTOR_4].prev_direction) {
- st_pre.mot[MOTOR_4].prev_direction = st_pre.mot[MOTOR_4].direction;
- st_run.mot[MOTOR_4].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_4].substep_accumulator);
- if (st_pre.mot[MOTOR_4].direction == DIRECTION_CW)
- PORT_MOTOR_4_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_4_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- SET_ENCODER_STEP_SIGN(MOTOR_4, st_pre.mot[MOTOR_4].step_sign);
- if (st_cfg.mot[MOTOR_4].power_mode != MOTOR_DISABLED) {
- PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_4].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- } else {
- if (st_cfg.mot[MOTOR_4].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_4].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- ACCUMULATE_ENCODER(MOTOR_4);
+ if ((st_run.mot[MOTOR_4].substep_increment = st_pre.mot[MOTOR_4].substep_increment) != 0) {
+ if (st_pre.mot[MOTOR_4].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_4].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_4].substep_accumulator *= st_pre.mot[MOTOR_4].accumulator_correction;
+ }
+
+ if (st_pre.mot[MOTOR_4].direction != st_pre.mot[MOTOR_4].prev_direction) {
+ st_pre.mot[MOTOR_4].prev_direction = st_pre.mot[MOTOR_4].direction;
+ st_run.mot[MOTOR_4].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_4].substep_accumulator);
+
+ if (st_pre.mot[MOTOR_4].direction == DIRECTION_CW)
+ PORT_MOTOR_4_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_4_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ SET_ENCODER_STEP_SIGN(MOTOR_4, st_pre.mot[MOTOR_4].step_sign);
+
+ if (st_cfg.mot[MOTOR_4].power_mode != MOTOR_DISABLED) {
+ PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_4].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ } else if (st_cfg.mot[MOTOR_4].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ PORT_MOTOR_4_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_4].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ ACCUMULATE_ENCODER(MOTOR_4);
#endif
+
#if (MOTORS >= 5) //**** MOTOR_5 LOAD ****
- if ((st_run.mot[MOTOR_5].substep_increment = st_pre.mot[MOTOR_5].substep_increment) != 0) {
- if (st_pre.mot[MOTOR_5].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_5].accumulator_correction_flag = false;
- st_run.mot[MOTOR_5].substep_accumulator *= st_pre.mot[MOTOR_5].accumulator_correction;
- }
- if (st_pre.mot[MOTOR_5].direction != st_pre.mot[MOTOR_5].prev_direction) {
- st_pre.mot[MOTOR_5].prev_direction = st_pre.mot[MOTOR_5].direction;
- st_run.mot[MOTOR_5].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_5].substep_accumulator);
- if (st_pre.mot[MOTOR_5].direction == DIRECTION_CW)
- PORT_MOTOR_5_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_5_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- PORT_MOTOR_5_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_5].power_state = MOTOR_POWER_TIMEOUT_START;
- SET_ENCODER_STEP_SIGN(MOTOR_5, st_pre.mot[MOTOR_5].step_sign);
- } else {
- if (st_cfg.mot[MOTOR_5].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_5_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_5].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- ACCUMULATE_ENCODER(MOTOR_5);
+ if ((st_run.mot[MOTOR_5].substep_increment = st_pre.mot[MOTOR_5].substep_increment) != 0) {
+ if (st_pre.mot[MOTOR_5].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_5].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_5].substep_accumulator *= st_pre.mot[MOTOR_5].accumulator_correction;
+ }
+
+ if (st_pre.mot[MOTOR_5].direction != st_pre.mot[MOTOR_5].prev_direction) {
+ st_pre.mot[MOTOR_5].prev_direction = st_pre.mot[MOTOR_5].direction;
+ st_run.mot[MOTOR_5].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_5].substep_accumulator);
+
+ if (st_pre.mot[MOTOR_5].direction == DIRECTION_CW)
+ PORT_MOTOR_5_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_5_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ PORT_MOTOR_5_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_5].power_state = MOTOR_POWER_TIMEOUT_START;
+ SET_ENCODER_STEP_SIGN(MOTOR_5, st_pre.mot[MOTOR_5].step_sign);
+
+ } else if (st_cfg.mot[MOTOR_5].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ PORT_MOTOR_5_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_5].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ ACCUMULATE_ENCODER(MOTOR_5);
#endif
+
#if (MOTORS >= 6) //**** MOTOR_6 LOAD ****
- if ((st_run.mot[MOTOR_6].substep_increment = st_pre.mot[MOTOR_6].substep_increment) != 0) {
- if (st_pre.mot[MOTOR_6].accumulator_correction_flag == true) {
- st_pre.mot[MOTOR_6].accumulator_correction_flag = false;
- st_run.mot[MOTOR_6].substep_accumulator *= st_pre.mot[MOTOR_6].accumulator_correction;
- }
- if (st_pre.mot[MOTOR_6].direction != st_pre.mot[MOTOR_6].prev_direction) {
- st_pre.mot[MOTOR_6].prev_direction = st_pre.mot[MOTOR_6].direction;
- st_run.mot[MOTOR_6].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_6].substep_accumulator);
- if (st_pre.mot[MOTOR_6].direction == DIRECTION_CW)
- PORT_MOTOR_6_VPORT.OUT &= ~DIRECTION_BIT_bm; else
- PORT_MOTOR_6_VPORT.OUT |= DIRECTION_BIT_bm;
- }
- PORT_MOTOR_6_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_6].power_state = MOTOR_POWER_TIMEOUT_START;
- SET_ENCODER_STEP_SIGN(MOTOR_6, st_pre.mot[MOTOR_6].step_sign);
- } else {
- if (st_cfg.mot[MOTOR_6].power_mode == MOTOR_POWERED_IN_CYCLE) {
- PORT_MOTOR_6_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
- st_run.mot[MOTOR_6].power_state = MOTOR_POWER_TIMEOUT_START;
- }
- }
- ACCUMULATE_ENCODER(MOTOR_6);
+ if ((st_run.mot[MOTOR_6].substep_increment = st_pre.mot[MOTOR_6].substep_increment) != 0) {
+ if (st_pre.mot[MOTOR_6].accumulator_correction_flag == true) {
+ st_pre.mot[MOTOR_6].accumulator_correction_flag = false;
+ st_run.mot[MOTOR_6].substep_accumulator *= st_pre.mot[MOTOR_6].accumulator_correction;
+ }
+
+ if (st_pre.mot[MOTOR_6].direction != st_pre.mot[MOTOR_6].prev_direction) {
+ st_pre.mot[MOTOR_6].prev_direction = st_pre.mot[MOTOR_6].direction;
+ st_run.mot[MOTOR_6].substep_accumulator = -(st_run.dda_ticks_X_substeps + st_run.mot[MOTOR_6].substep_accumulator);
+ if (st_pre.mot[MOTOR_6].direction == DIRECTION_CW)
+ PORT_MOTOR_6_VPORT.OUT &= ~DIRECTION_BIT_bm;
+ else PORT_MOTOR_6_VPORT.OUT |= DIRECTION_BIT_bm;
+ }
+
+ PORT_MOTOR_6_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_6].power_state = MOTOR_POWER_TIMEOUT_START;
+ SET_ENCODER_STEP_SIGN(MOTOR_6, st_pre.mot[MOTOR_6].step_sign);
+
+ } else if (st_cfg.mot[MOTOR_6].power_mode == MOTOR_POWERED_IN_CYCLE) {
+ PORT_MOTOR_6_VPORT.OUT &= ~MOTOR_ENABLE_BIT_bm;
+ st_run.mot[MOTOR_6].power_state = MOTOR_POWER_TIMEOUT_START;
+ }
+
+ ACCUMULATE_ENCODER(MOTOR_6);
#endif
- //**** do this last ****
- TIMER_DDA.PER = st_pre.dda_period;
- TIMER_DDA.CTRLA = STEP_TIMER_ENABLE; // enable the DDA timer
+ //**** do this last ****
+ TIMER_DDA.PER = st_pre.dda_period;
+ TIMER_DDA.CTRLA = STEP_TIMER_ENABLE; // enable the DDA timer
+ } else if (st_pre.move_type == MOVE_TYPE_DWELL) {
// handle dwells
- } else if (st_pre.move_type == MOVE_TYPE_DWELL) {
- st_run.dda_ticks_downcount = st_pre.dda_ticks;
- TIMER_DWELL.PER = st_pre.dda_period; // load dwell timer period
- TIMER_DWELL.CTRLA = STEP_TIMER_ENABLE; // enable the dwell timer
+ st_run.dda_ticks_downcount = st_pre.dda_ticks;
+ TIMER_DWELL.PER = st_pre.dda_period; // load dwell timer period
+ TIMER_DWELL.CTRLA = STEP_TIMER_ENABLE; // enable the dwell timer
+ } else if (st_pre.move_type == MOVE_TYPE_COMMAND)
// handle synchronous commands
- } else if (st_pre.move_type == MOVE_TYPE_COMMAND) {
- mp_runtime_command(st_pre.bf);
- }
+ mp_runtime_command(st_pre.bf);
- // all other cases drop to here (e.g. Null moves after Mcodes skip to here)
- st_pre.move_type = MOVE_TYPE_0;
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // we are done with the prep buffer - flip the flag back
- st_request_exec_move(); // exec and prep next move
+ // all other cases drop to here (e.g. Null moves after Mcodes skip to here)
+ st_pre.move_type = MOVE_TYPE_0;
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // we are done with the prep buffer - flip the flag back
+ st_request_exec_move(); // exec and prep next move
}
+
/***********************************************************************************
* st_prep_line() - Prepare the next move for the loader
*
* 100% accurate this will affect the move velocity, but not the distance traveled.
*
* NOTE: Many of the expressions are sensitive to casting and execution order to avoid long-term
- * accuracy errors due to floating point round off. One earlier failed attempt was:
- * dda_ticks_X_substeps = (int32_t)((microseconds/1000000) * f_dda * dda_substeps);
+ * accuracy errors due to floating point round off. One earlier failed attempt was:
+ * dda_ticks_X_substeps = (int32_t)((microseconds / 1000000) * f_dda * dda_substeps);
*/
-
-stat_t st_prep_line(float travel_steps[], float following_error[], float segment_time)
-{
- // trap conditions that would prevent queueing the line
- if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_EXEC) {
- return cm_hard_alarm(STAT_INTERNAL_ERROR);
- } else if (isinf(segment_time)) { return cm_hard_alarm(STAT_PREP_LINE_MOVE_TIME_IS_INFINITE); // never supposed to happen
- } else if (isnan(segment_time)) { return cm_hard_alarm(STAT_PREP_LINE_MOVE_TIME_IS_NAN); // never supposed to happen
- } else if (segment_time < EPSILON) { return STAT_MINIMUM_TIME_MOVE;
+stat_t st_prep_line(float travel_steps[], float following_error[], float segment_time) {
+ // trap conditions that would prevent queueing the line
+ if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_EXEC) return cm_hard_alarm(STAT_INTERNAL_ERROR);
+ else if (isinf(segment_time)) return cm_hard_alarm(STAT_PREP_LINE_MOVE_TIME_IS_INFINITE); // never supposed to happen
+ else if (isnan(segment_time)) return cm_hard_alarm(STAT_PREP_LINE_MOVE_TIME_IS_NAN); // never supposed to happen
+ else if (segment_time < EPSILON) return STAT_MINIMUM_TIME_MOVE;
+
+ // setup segment parameters
+ // - dda_ticks is the integer number of DDA clock ticks needed to play out the segment
+ // - ticks_X_substeps is the maximum depth of the DDA accumulator (as a negative number)
+ st_pre.dda_period = _f_to_period(FREQUENCY_DDA);
+ st_pre.dda_ticks = (int32_t)(segment_time * 60 * FREQUENCY_DDA);// NB: converts minutes to seconds
+ st_pre.dda_ticks_X_substeps = st_pre.dda_ticks * DDA_SUBSTEPS;
+
+ // setup motor parameters
+ float correction_steps;
+ for (uint8_t motor = 0; motor < MOTORS; motor++) {
+ // Skip this motor if there are no new steps. Leave all other values intact.
+ if (fp_ZERO(travel_steps[motor])) {
+ st_pre.mot[motor].substep_increment = 0;
+ continue;
}
- // setup segment parameters
- // - dda_ticks is the integer number of DDA clock ticks needed to play out the segment
- // - ticks_X_substeps is the maximum depth of the DDA accumulator (as a negative number)
- st_pre.dda_period = _f_to_period(FREQUENCY_DDA);
- st_pre.dda_ticks = (int32_t)(segment_time * 60 * FREQUENCY_DDA);// NB: converts minutes to seconds
- st_pre.dda_ticks_X_substeps = st_pre.dda_ticks * DDA_SUBSTEPS;
+ // Setup the direction, compensating for polarity.
+ // Set the step_sign which is used by the stepper ISR to accumulate step position
+ if (travel_steps[motor] >= 0) { // positive direction
+ st_pre.mot[motor].direction = DIRECTION_CW ^ st_cfg.mot[motor].polarity;
+ st_pre.mot[motor].step_sign = 1;
- // setup motor parameters
-
- float correction_steps;
- for (uint8_t motor=0; motor<MOTORS; motor++) { // I want to remind myself that this is motors, not axes
+ } else {
+ st_pre.mot[motor].direction = DIRECTION_CCW ^ st_cfg.mot[motor].polarity;
+ st_pre.mot[motor].step_sign = -1;
+ }
- // Skip this motor if there are no new steps. Leave all other values intact.
- if (fp_ZERO(travel_steps[motor])) { st_pre.mot[motor].substep_increment = 0; continue;}
+ // Detect segment time changes and setup the accumulator correction factor and flag.
+ // Putting this here computes the correct factor even if the motor was dormant for some
+ // number of previous moves. Correction is computed based on the last segment time actually used.
+ if (fabs(segment_time - st_pre.mot[motor].prev_segment_time) > 0.0000001) { // highly tuned FP != compare
+ if (fp_NOT_ZERO(st_pre.mot[motor].prev_segment_time)) { // special case to skip first move
+ st_pre.mot[motor].accumulator_correction_flag = true;
+ st_pre.mot[motor].accumulator_correction = segment_time / st_pre.mot[motor].prev_segment_time;
+ }
- // Setup the direction, compensating for polarity.
- // Set the step_sign which is used by the stepper ISR to accumulate step position
+ st_pre.mot[motor].prev_segment_time = segment_time;
+ }
- if (travel_steps[motor] >= 0) { // positive direction
- st_pre.mot[motor].direction = DIRECTION_CW ^ st_cfg.mot[motor].polarity;
- st_pre.mot[motor].step_sign = 1;
- } else {
- st_pre.mot[motor].direction = DIRECTION_CCW ^ st_cfg.mot[motor].polarity;
- st_pre.mot[motor].step_sign = -1;
- }
+#ifdef __STEP_CORRECTION
+ // 'Nudge' correction strategy. Inject a single, scaled correction value then hold off
+ if ((--st_pre.mot[motor].correction_holdoff < 0) &&
+ (fabs(following_error[motor]) > STEP_CORRECTION_THRESHOLD)) {
- // Detect segment time changes and setup the accumulator correction factor and flag.
- // Putting this here computes the correct factor even if the motor was dormant for some
- // number of previous moves. Correction is computed based on the last segment time actually used.
+ st_pre.mot[motor].correction_holdoff = STEP_CORRECTION_HOLDOFF;
+ correction_steps = following_error[motor] * STEP_CORRECTION_FACTOR;
- if (fabs(segment_time - st_pre.mot[motor].prev_segment_time) > 0.0000001) { // highly tuned FP != compare
- if (fp_NOT_ZERO(st_pre.mot[motor].prev_segment_time)) { // special case to skip first move
- st_pre.mot[motor].accumulator_correction_flag = true;
- st_pre.mot[motor].accumulator_correction = segment_time / st_pre.mot[motor].prev_segment_time;
- }
- st_pre.mot[motor].prev_segment_time = segment_time;
- }
+ if (correction_steps > 0)
+ correction_steps = min3(correction_steps, fabs(travel_steps[motor]), STEP_CORRECTION_MAX);
+ else correction_steps = max3(correction_steps, -fabs(travel_steps[motor]), -STEP_CORRECTION_MAX);
-#ifdef __STEP_CORRECTION
- // 'Nudge' correction strategy. Inject a single, scaled correction value then hold off
-
- if ((--st_pre.mot[motor].correction_holdoff < 0) &&
- (fabs(following_error[motor]) > STEP_CORRECTION_THRESHOLD)) {
-
- st_pre.mot[motor].correction_holdoff = STEP_CORRECTION_HOLDOFF;
- correction_steps = following_error[motor] * STEP_CORRECTION_FACTOR;
-
- if (correction_steps > 0) {
- correction_steps = min3(correction_steps, fabs(travel_steps[motor]), STEP_CORRECTION_MAX);
- } else {
- correction_steps = max3(correction_steps, -fabs(travel_steps[motor]), -STEP_CORRECTION_MAX);
- }
- st_pre.mot[motor].corrected_steps += correction_steps;
- travel_steps[motor] -= correction_steps;
- }
+ st_pre.mot[motor].corrected_steps += correction_steps;
+ travel_steps[motor] -= correction_steps;
+ }
#endif
- // Compute substeb increment. The accumulator must be *exactly* the incoming
- // fractional steps times the substep multiplier or positional drift will occur.
- // Rounding is performed to eliminate a negative bias in the uint32 conversion
- // that results in long-term negative drift. (fabs/round order doesn't matter)
- st_pre.mot[motor].substep_increment = round(fabs(travel_steps[motor] * DDA_SUBSTEPS));
- }
- st_pre.move_type = MOVE_TYPE_ALINE;
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
- return STAT_OK;
-}
+ // Compute substeb increment. The accumulator must be *exactly* the incoming
+ // fractional steps times the substep multiplier or positional drift will occur.
+ // Rounding is performed to eliminate a negative bias in the uint32 conversion
+ // that results in long-term negative drift. (fabs/round order doesn't matter)
+ st_pre.mot[motor].substep_increment = round(fabs(travel_steps[motor] * DDA_SUBSTEPS));
+ }
-/*
- * st_prep_null() - Keeps the loader happy. Otherwise performs no action
- */
+ st_pre.move_type = MOVE_TYPE_ALINE;
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
-void st_prep_null()
-{
- st_pre.move_type = MOVE_TYPE_0;
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // signal that prep buffer is empty
+ return STAT_OK;
}
-/*
- * st_prep_command() - Stage command to execution
- */
-void st_prep_command(void *bf)
-{
- st_pre.move_type = MOVE_TYPE_COMMAND;
- st_pre.bf = (mpBuf_t *)bf;
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
+/// Keeps the loader happy. Otherwise performs no action
+void st_prep_null() {
+ st_pre.move_type = MOVE_TYPE_0;
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // signal that prep buffer is empty
}
-/*
- * st_prep_dwell() - Add a dwell to the move buffer
- */
-void st_prep_dwell(float microseconds)
-{
- st_pre.move_type = MOVE_TYPE_DWELL;
- st_pre.dda_period = _f_to_period(FREQUENCY_DWELL);
- st_pre.dda_ticks = (uint32_t)((microseconds/1000000) * FREQUENCY_DWELL);
- st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
+/// Stage command to execution
+void st_prep_command(void *bf) {
+ st_pre.move_type = MOVE_TYPE_COMMAND;
+ st_pre.bf = (mpBuf_t *)bf;
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
}
-/*
- * _set_hw_microsteps() - set microsteps in hardware
- *
- * For now the microsteps is the same as the microsteps (1,2,4,8)
- * This may change if microstep morphing is implemented.
- */
-static void _set_hw_microsteps(const uint8_t motor, const uint8_t microsteps)
-{
- if (microsteps == 8) {
- hw.st_port[motor]->OUTSET = MICROSTEP_BIT_0_bm;
- hw.st_port[motor]->OUTSET = MICROSTEP_BIT_1_bm;
- } else if (microsteps == 4) {
- hw.st_port[motor]->OUTCLR = MICROSTEP_BIT_0_bm;
- hw.st_port[motor]->OUTSET = MICROSTEP_BIT_1_bm;
- } else if (microsteps == 2) {
- hw.st_port[motor]->OUTSET = MICROSTEP_BIT_0_bm;
- hw.st_port[motor]->OUTCLR = MICROSTEP_BIT_1_bm;
- } else if (microsteps == 1) {
- hw.st_port[motor]->OUTCLR = MICROSTEP_BIT_0_bm;
- hw.st_port[motor]->OUTCLR = MICROSTEP_BIT_1_bm;
- }
+/// Add a dwell to the move buffer
+void st_prep_dwell(float microseconds) {
+ st_pre.move_type = MOVE_TYPE_DWELL;
+ st_pre.dda_period = _f_to_period(FREQUENCY_DWELL);
+ st_pre.dda_ticks = (uint32_t)(microseconds / 1000000 * FREQUENCY_DWELL);
+ st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready
}
-/***********************************************************************************
- * CONFIGURATION AND INTERFACE FUNCTIONS
- * Functions to get and set variables from the cfgArray table
- ***********************************************************************************/
+/// Helper to return motor number as an index
+static int8_t _get_motor(const nvObj_t *nv) {
+ return nv->group[0] ? nv->group[0] : nv->token[0] - 0x31;
+}
-/* HELPERS
- * _get_motor() - helper to return motor number as an index
- */
-static int8_t _get_motor(const nvObj_t *nv)
-{
- return (nv->group[0] ? nv->group[0] : nv->token[0] - 0x31);
+/// This function will need to be rethought if microstep morphing is implemented
+static void _set_motor_steps_per_unit(nvObj_t *nv) {
+ uint8_t m = _get_motor(nv);
+ st_cfg.mot[m].steps_per_unit = (360 * st_cfg.mot[m].microsteps) / (st_cfg.mot[m].travel_rev * st_cfg.mot[m].step_angle);
+ st_reset();
}
-/*
- * _set_motor_steps_per_unit() - what it says
- * This function will need to be rethought if microstep morphing is implemented
- */
-static void _set_motor_steps_per_unit(nvObj_t *nv)
-{
- uint8_t m = _get_motor(nv);
- st_cfg.mot[m].steps_per_unit = (360 * st_cfg.mot[m].microsteps) / (st_cfg.mot[m].travel_rev * st_cfg.mot[m].step_angle);
- st_reset();
+/// Set motor step angle
+stat_t st_set_sa(nvObj_t *nv) {
+ set_flt(nv);
+ _set_motor_steps_per_unit(nv);
+
+ return STAT_OK;
}
-/* PER-MOTOR FUNCTIONS
- * st_set_sa() - set motor step angle
- * st_set_tr() - set travel per motor revolution
- * st_set_mi() - set motor microsteps
- * st_set_pm() - set motor power mode
- * st_set_pl() - set motor power level
- */
-stat_t st_set_sa(nvObj_t *nv) // motor step angle
-{
- set_flt(nv);
- _set_motor_steps_per_unit(nv);
- return(STAT_OK);
-}
+/// Set motor travel per revolution
+stat_t st_set_tr(nvObj_t *nv) {
+ set_flu(nv);
+ _set_motor_steps_per_unit(nv);
-stat_t st_set_tr(nvObj_t *nv) // motor travel per revolution
-{
- set_flu(nv);
- _set_motor_steps_per_unit(nv);
- return(STAT_OK);
+ return STAT_OK;
}
-stat_t st_set_mi(nvObj_t *nv) // motor microsteps
-{
- uint32_t mi = (uint32_t)nv->value;
- if ((mi != 1) && (mi != 2) && (mi != 4) && (mi != 8)) {
- nv_add_conditional_message((const char_t *)"*** WARNING *** Setting non-standard microstep value");
- }
- set_int(nv); // set it anyway, even if it's unsupported. It could also be > 255
- _set_motor_steps_per_unit(nv);
- _set_hw_microsteps(_get_motor(nv), (uint8_t)nv->value);
- return STAT_OK;
+
+// Set motor microsteps
+stat_t st_set_mi(nvObj_t *nv) {
+ set_int(nv);
+ _set_motor_steps_per_unit(nv);
+
+ return STAT_OK;
}
-stat_t st_set_pm(nvObj_t *nv) // motor power mode
-{
- if ((uint8_t)nv->value >= MOTOR_POWER_MODE_MAX_VALUE)
- return STAT_INPUT_VALUE_RANGE_ERROR;
- set_ui8(nv);
- return STAT_OK;
- // NOTE: The motor power callback makes these settings take effect immediately
+
+// Set motor power mode
+stat_t st_set_pm(nvObj_t *nv) {
+ // NOTE: The motor power callback makes these settings take effect immediately
+ if ((uint8_t)nv->value >= MOTOR_POWER_MODE_MAX_VALUE)
+ return STAT_INPUT_VALUE_RANGE_ERROR;
+
+ set_ui8(nv);
+
+ return STAT_OK;
}
+
/*
* st_set_pl() - set motor power level
*
* This function sets both the scaled and dynamic power levels, and applies the
* scaled value to the vref.
*/
-stat_t st_set_pl(nvObj_t *nv) // motor power level
-{
- return(STAT_OK);
+stat_t st_set_pl(nvObj_t *nv) {
+ return STAT_OK;
}
-/*
- * st_get_pwr() - get motor enable power state
- */
-stat_t st_get_pwr(nvObj_t *nv)
-{
- nv->value = _motor_is_enabled(_get_motor(nv));
- nv->valuetype = TYPE_INTEGER;
- return STAT_OK;
+
+/// get motor enable power state
+stat_t st_get_pwr(nvObj_t *nv) {
+ nv->value = _motor_is_enabled(_get_motor(nv));
+ nv->valuetype = TYPE_INTEGER;
+
+ return STAT_OK;
}
+
/* GLOBAL FUNCTIONS (SYSTEM LEVEL)
- *
- * st_set_mt() - set motor timeout in seconds
- * st_set_md() - disable motor power
- * st_set_me() - enable motor power
- *
* Calling me or md with 0 will enable or disable all motors
* Setting a value of 0 will enable or disable all motors
* Setting a value from 1 to MOTORS will enable or disable that motor only
*/
-stat_t st_set_mt(nvObj_t *nv)
-{
- st_cfg.motor_power_timeout = min(MOTOR_TIMEOUT_SECONDS_MAX, max(nv->value, MOTOR_TIMEOUT_SECONDS_MIN));
- return STAT_OK;
+/// Set motor timeout in seconds
+stat_t st_set_mt(nvObj_t *nv) {
+ st_cfg.motor_power_timeout = min(MOTOR_TIMEOUT_SECONDS_MAX, max(nv->value, MOTOR_TIMEOUT_SECONDS_MIN));
+ return STAT_OK;
}
-stat_t st_set_md(nvObj_t *nv) // Make sure this function is not part of initialization --> f00
-{
- if (((uint8_t)nv->value == 0) || (nv->valuetype == TYPE_0)) {
- st_deenergize_motors();
- } else {
- uint8_t motor = (uint8_t)nv->value;
- if (motor > MOTORS) {
- return STAT_INPUT_VALUE_RANGE_ERROR;
- }
- _deenergize_motor(motor-1); // adjust so that motor 1 is actually 0 (etc)
- }
- return STAT_OK;
+
+/// Disable motor power
+stat_t st_set_md(nvObj_t *nv) {
+ // Make sure this function is not part of initialization --> f00
+ if (((uint8_t)nv->value == 0) || (nv->valuetype == TYPE_0))
+ st_deenergize_motors();
+
+ else {
+ uint8_t motor = (uint8_t)nv->value;
+ if (motor > MOTORS) return STAT_INPUT_VALUE_RANGE_ERROR;
+ _deenergize_motor(motor - 1); // adjust so that motor 1 is actually 0 (etc)
+ }
+
+ return STAT_OK;
}
-stat_t st_set_me(nvObj_t *nv) // Make sure this function is not part of initialization --> f00
-{
- if (((uint8_t)nv->value == 0) || (nv->valuetype == TYPE_0)) {
- st_energize_motors();
- } else {
- uint8_t motor = (uint8_t)nv->value;
- if (motor > MOTORS) {
- return STAT_INPUT_VALUE_RANGE_ERROR;
- }
- _energize_motor(motor-1); // adjust so that motor 1 is actually 0 (etc)
- }
- return STAT_OK;
+
+/// enable motor power
+stat_t st_set_me(nvObj_t *nv) {
+ // Make sure this function is not part of initialization --> f00
+ if (((uint8_t)nv->value == 0) || (nv->valuetype == TYPE_0))
+ st_energize_motors();
+
+ else {
+ uint8_t motor = (uint8_t)nv->value;
+ if (motor > MOTORS) return STAT_INPUT_VALUE_RANGE_ERROR;
+ _energize_motor(motor - 1); // adjust so that motor 1 is actually 0 (etc)
+ }
+
+ return STAT_OK;
}
-/***********************************************************************************
- * TEXT MODE SUPPORT
- * Functions to print variables from the cfgArray table
- ***********************************************************************************/
#ifdef __TEXT_MODE
static const char msg_units0[] PROGMEM = " in"; // used by generic print functions
static const char msg_units1[] PROGMEM = " mm";
static const char msg_units2[] PROGMEM = " deg";
-static const char *const msg_units[] PROGMEM = { msg_units0, msg_units1, msg_units2 };
+static const char *const msg_units[] PROGMEM = {msg_units0, msg_units1, msg_units2};
#define DEGREE_INDEX 2
static const char fmt_me[] PROGMEM = "motors energized\n";
static const char fmt_0ma[] PROGMEM = "[%s%s] m%s map to axis%15d [0=X,1=Y,2=Z...]\n";
static const char fmt_0sa[] PROGMEM = "[%s%s] m%s step angle%20.3f%s\n";
static const char fmt_0tr[] PROGMEM = "[%s%s] m%s travel per revolution%10.4f%s\n";
-static const char fmt_0mi[] PROGMEM = "[%s%s] m%s microsteps%16d [1,2,4,8]\n";
+static const char fmt_0mi[] PROGMEM = "[%s%s] m%s microsteps%16d [1,2,4,8,16,32,64,128,256]\n";
static const char fmt_0po[] PROGMEM = "[%s%s] m%s polarity%18d [0=normal,1=reverse]\n";
static const char fmt_0pm[] PROGMEM = "[%s%s] m%s power management%10d [0=disabled,1=always on,2=in cycle,3=when moving]\n";
static const char fmt_0pl[] PROGMEM = "[%s%s] m%s motor power level%13.3f [0.000=minimum, 1.000=maximum]\n";
static const char fmt_pwr[] PROGMEM = "Motor %c power enabled state:%2.0f\n";
-void st_print_mt(nvObj_t *nv) { text_print_flt(nv, fmt_mt);}
-void st_print_me(nvObj_t *nv) { text_print_nul(nv, fmt_me);}
-void st_print_md(nvObj_t *nv) { text_print_nul(nv, fmt_md);}
+void st_print_mt(nvObj_t *nv) {text_print_flt(nv, fmt_mt);}
+void st_print_me(nvObj_t *nv) {text_print_nul(nv, fmt_me);}
+void st_print_md(nvObj_t *nv) {text_print_nul(nv, fmt_md);}
-static void _print_motor_ui8(nvObj_t *nv, const char *format)
-{
- fprintf_P(stderr, format, nv->group, nv->token, nv->group, (uint8_t)nv->value);
+
+static void _print_motor_ui8(nvObj_t *nv, const char *format) {
+ fprintf_P(stderr, format, nv->group, nv->token, nv->group, (uint8_t)nv->value);
}
-static void _print_motor_flt_units(nvObj_t *nv, const char *format, uint8_t units)
-{
- fprintf_P(stderr, format, nv->group, nv->token, nv->group, nv->value, GET_TEXT_ITEM(msg_units, units));
+
+static void _print_motor_flt_units(nvObj_t *nv, const char *format, uint8_t units) {
+ fprintf_P(stderr, format, nv->group, nv->token, nv->group, nv->value, GET_TEXT_ITEM(msg_units, units));
}
-static void _print_motor_flt(nvObj_t *nv, const char *format)
-{
- fprintf_P(stderr, format, nv->group, nv->token, nv->group, nv->value);
+
+static void _print_motor_flt(nvObj_t *nv, const char *format) {
+ fprintf_P(stderr, format, nv->group, nv->token, nv->group, nv->value);
}
-static void _print_motor_pwr(nvObj_t *nv, const char *format)
-{
- fprintf_P(stderr, format, nv->token[0], nv->value);
+static void _print_motor_pwr(nvObj_t *nv, const char *format) {
+ fprintf_P(stderr, format, nv->token[0], nv->value);
}
-void st_print_ma(nvObj_t *nv) { _print_motor_ui8(nv, fmt_0ma);}
-void st_print_sa(nvObj_t *nv) { _print_motor_flt_units(nv, fmt_0sa, DEGREE_INDEX);}
-void st_print_tr(nvObj_t *nv) { _print_motor_flt_units(nv, fmt_0tr, cm_get_units_mode(MODEL));}
-void st_print_mi(nvObj_t *nv) { _print_motor_ui8(nv, fmt_0mi);}
-void st_print_po(nvObj_t *nv) { _print_motor_ui8(nv, fmt_0po);}
-void st_print_pm(nvObj_t *nv) { _print_motor_ui8(nv, fmt_0pm);}
-void st_print_pl(nvObj_t *nv) { _print_motor_flt(nv, fmt_0pl);}
-void st_print_pwr(nvObj_t *nv){ _print_motor_pwr(nv, fmt_pwr);}
+
+void st_print_ma(nvObj_t *nv) {_print_motor_ui8(nv, fmt_0ma);}
+void st_print_sa(nvObj_t *nv) {_print_motor_flt_units(nv, fmt_0sa, DEGREE_INDEX);}
+void st_print_tr(nvObj_t *nv) {_print_motor_flt_units(nv, fmt_0tr, cm_get_units_mode(MODEL));}
+void st_print_mi(nvObj_t *nv) {_print_motor_ui8(nv, fmt_0mi);}
+void st_print_po(nvObj_t *nv) {_print_motor_ui8(nv, fmt_0po);}
+void st_print_pm(nvObj_t *nv) {_print_motor_ui8(nv, fmt_0pm);}
+void st_print_pl(nvObj_t *nv) {_print_motor_flt(nv, fmt_0pl);}
+void st_print_pwr(nvObj_t *nv){_print_motor_pwr(nv, fmt_pwr);}
#endif // __TEXT_MODE
* Also, all moves are loaded from the DDA interrupt level (HI), avoiding the need
* for mutual exclusion locking or volatiles (which slow things down).
*/
+
/*
- **** Move generation overview and timing illustration ****
- *
- * This ASCII art illustrates a 4 segment move to show stepper sequencing timing.
- *
- * LOAD/STEP (~5000uSec) [L1][segment1][L2][segment2][L3][segment3][L4][segment4][Lb1]
- * PREP (100 uSec) [P1] [P2] [P3] [P4] [Pb1]
- * EXEC (400 uSec) [EXEC1] [EXEC2] [EXEC3] [EXEC4] [EXECb1]
- * PLAN (<4ms) [planmoveA][plan move B][plan move C][plan move D][plan move E] etc.
- *
- * The move begins with the planner PLANning move A [planmoveA]. When this is done the
- * computations for the first segment of move A's S curve are performed by the planner
- * runtime, EXEC1. The runtime computes the number of segments and the segment-by-segment
- * accelerations and decelerations for the move. Each call to EXEC generates the values
- * for the next segment to be run. Once the move is running EXEC is executed as a
- * callback from the step loader.
- *
- * When the runtime calculations are done EXEC calls the segment PREParation function [P1].
- * PREP turns the EXEC results into values needed for the loader and does some encoder work.
- * The combined exec and prep take about 400 uSec.
- *
- * PREP takes care of heavy numerics and other cycle-intesive operations so the step loader
- * L1 can run as fast as possible. The time budget for LOAD is about 10 uSec. In the diagram,
- * when P1 is done segment 1 is loaded into the stepper runtime [L1]
- *
- * Once the segment is loaded it will pulse out steps for the duration of the segment.
- * Segment timing can vary, but segments take around 5 Msec to pulse out, which is 250 DDA
- * ticks at a 50 KHz step clock.
- *
- * Now the move is pulsing out segment 1 (at HI interrupt level). Once the L1 loader is
- * finished it invokes the exec function for the next segment (at LO interrupt level).
- * [EXEC2] and [P2] compute and prepare the segment 2 for the loader so it can be loaded
- * as soon as segment 1 is complete [L2]. When move A is done EXEC pulls the next move
- * (moveB) from the planner queue, The process repeats until there are no more segments or moves.
- *
- * While all this is happening subsequent moves (B, C, and D) are being planned in background.
- * As long as a move takes less than the segment times (5ms x N) the timing budget is satisfied,
- *
- * A few things worth noting:
- * - This scheme uses 2 interrupt levels and background, for 3 levels of execution:
- * - STEP pulsing and LOADs occur at HI interrupt level
- * - EXEC and PREP occur at LO interrupt level (leaving MED int level for serial IO)
- * - move PLANning occurs in background and is managed by the controller
- *
- * - Because of the way the timing is laid out there is no contention for resources between
- * the STEP, LOAD, EXEC, and PREP phases. PLANing is similarly isolated. Very few volatiles
- * or mutexes are needed, which makes the code simpler and faster. With the exception of
- * the actual values used in step generation (which runs continuously) you can count on
- * LOAD, EXEC, PREP and PLAN not stepping on each other's variables.
- */
+**** Move generation overview and timing illustration ****
+*
+* This ASCII art illustrates a 4 segment move to show stepper sequencing timing.
+*
+* LOAD/STEP (~5000uSec) [L1][segment1][L2][segment2][L3][segment3][L4][segment4][Lb1]
+* PREP (100 uSec) [P1] [P2] [P3] [P4] [Pb1]
+* EXEC (400 uSec) [EXEC1] [EXEC2] [EXEC3] [EXEC4] [EXECb1]
+* PLAN (<4ms) [planmoveA][plan move B][plan move C][plan move D][plan move E] etc.
+*
+* The move begins with the planner PLANning move A [planmoveA]. When this is done the
+* computations for the first segment of move A's S curve are performed by the planner
+* runtime, EXEC1. The runtime computes the number of segments and the segment-by-segment
+* accelerations and decelerations for the move. Each call to EXEC generates the values
+* for the next segment to be run. Once the move is running EXEC is executed as a
+* callback from the step loader.
+*
+* When the runtime calculations are done EXEC calls the segment PREParation function [P1].
+* PREP turns the EXEC results into values needed for the loader and does some encoder work.
+* The combined exec and prep take about 400 uSec.
+*
+* PREP takes care of heavy numerics and other cycle-intesive operations so the step loader
+* L1 can run as fast as possible. The time budget for LOAD is about 10 uSec. In the diagram,
+* when P1 is done segment 1 is loaded into the stepper runtime [L1]
+*
+* Once the segment is loaded it will pulse out steps for the duration of the segment.
+* Segment timing can vary, but segments take around 5 Msec to pulse out, which is 250 DDA
+* ticks at a 50 KHz step clock.
+*
+* Now the move is pulsing out segment 1 (at HI interrupt level). Once the L1 loader is
+* finished it invokes the exec function for the next segment (at LO interrupt level).
+* [EXEC2] and [P2] compute and prepare the segment 2 for the loader so it can be loaded
+* as soon as segment 1 is complete [L2]. When move A is done EXEC pulls the next move
+* (moveB) from the planner queue, The process repeats until there are no more segments or moves.
+*
+* While all this is happening subsequent moves (B, C, and D) are being planned in background.
+* As long as a move takes less than the segment times (5ms x N) the timing budget is satisfied,
+*
+* A few things worth noting:
+* - This scheme uses 2 interrupt levels and background, for 3 levels of execution:
+* - STEP pulsing and LOADs occur at HI interrupt level
+* - EXEC and PREP occur at LO interrupt level (leaving MED int level for serial IO)
+* - move PLANning occurs in background and is managed by the controller
+*
+* - Because of the way the timing is laid out there is no contention for resources between
+* the STEP, LOAD, EXEC, and PREP phases. PLANing is similarly isolated. Very few volatiles
+* or mutexes are needed, which makes the code simpler and faster. With the exception of
+* the actual values used in step generation (which runs continuously) you can count on
+* LOAD, EXEC, PREP and PLAN not stepping on each other's variables.
+*/
+
/**** Line planning and execution (in more detail) ****
*
* Move planning, execution and pulse generation takes place at 3 levels:
* timer interrupts that generate the stepper pulses. This level also transfers new
* stepper parameters once each pulse train ("segment") is complete ("load" and "run" stages).
*/
-/* What happens when the pulse generator is done with the current pulse train (segment)
+
+/* What happens when the pulse generator is done with the current pulse train (segment)
* is a multi-stage "pull" queue that looks like this:
*
* As long as the steppers are running the sequence of events is:
* invoked from the main loop by the software interrupt, and the stepper load is
* invoked from the exec by another software interrupt.
*/
+
/* Control flow can be a bit confusing. This is a typical sequence for planning
* executing, and running an acceleration planned line:
*
* Note: For this to work you have to be really careful about what structures
* are modified at what level, and use volatiles where necessary.
*/
+
/* Partial steps and phase angle compensation
*
* The DDA accepts partial steps as input. Fractional steps are managed by the
* be thought of as a phase angle value for the DDA accumulation. Each 360
* degrees of phase angle results in a step being generated.
*/
+
#ifndef STEPPER_H_ONCE
#define STEPPER_H_ONCE
-/*********************************
- * Stepper configs and constants *
- *********************************/
-//See hardware.h for platform specific stepper definitions
+// See hardware.h for platform specific stepper definitions
enum prepBufferState {
- PREP_BUFFER_OWNED_BY_LOADER = 0, // staging buffer is ready for load
- PREP_BUFFER_OWNED_BY_EXEC // staging buffer is being loaded
+ PREP_BUFFER_OWNED_BY_LOADER = 0, // staging buffer is ready for load
+ PREP_BUFFER_OWNED_BY_EXEC // staging buffer is being loaded
};
+
// Currently there is no distinction between IDLE and OFF (DEENERGIZED)
// In the future IDLE will be powered at a low, torque-maintaining current
-
-enum motorPowerState { // used w/start and stop flags to sequence motor power
- MOTOR_OFF = 0, // motor is stopped and deenergized
- MOTOR_IDLE, // motor is stopped and may be partially energized for torque maintenance
- MOTOR_RUNNING, // motor is running (and fully energized)
- MOTOR_POWER_TIMEOUT_START, // transitional state to start power-down timeout
- MOTOR_POWER_TIMEOUT_COUNTDOWN // count down the time to de-energizing motors
+enum motorPowerState { // used w/start and stop flags to sequence motor power
+ MOTOR_OFF = 0, // motor is stopped and deenergized
+ MOTOR_IDLE, // motor is stopped and may be partially energized for torque maintenance
+ MOTOR_RUNNING, // motor is running (and fully energized)
+ MOTOR_POWER_TIMEOUT_START, // transitional state to start power-down timeout
+ MOTOR_POWER_TIMEOUT_COUNTDOWN // count down the time to de-energizing motors
};
+
enum cmMotorPowerMode {
- MOTOR_DISABLED = 0, // motor enable is deactivated
- MOTOR_ALWAYS_POWERED, // motor is always powered while machine is ON
- MOTOR_POWERED_IN_CYCLE, // motor fully powered during cycles, de-powered out of cycle
- MOTOR_POWERED_ONLY_WHEN_MOVING, // motor only powered while moving - idles shortly after it's stopped - even in cycle
-// MOTOR_POWER_REDUCED_WHEN_IDLE, // enable Vref current reduction for idle (FUTURE)
-// MOTOR_ADAPTIVE_POWER // adjust motor current with velocity (FUTURE)
- MOTOR_POWER_MODE_MAX_VALUE // for input range checking
+ MOTOR_DISABLED = 0, // motor enable is deactivated
+ MOTOR_ALWAYS_POWERED, // motor is always powered while machine is ON
+ MOTOR_POWERED_IN_CYCLE, // motor fully powered during cycles, de-powered out of cycle
+ MOTOR_POWERED_ONLY_WHEN_MOVING, // motor only powered while moving - idles shortly after it's stopped - even in cycle
+ MOTOR_POWER_MODE_MAX_VALUE // for input range checking
};
+
// Min/Max timeouts allowed for motor disable. Allow for inertial stop; must be non-zero
-#define MOTOR_TIMEOUT_SECONDS_MIN (float)0.1 // seconds !!! SHOULD NEVER BE ZERO !!!
+#define MOTOR_TIMEOUT_SECONDS_MIN (float)0.1 // seconds !!! SHOULD NEVER BE ZERO !!!
#define MOTOR_TIMEOUT_SECONDS_MAX (float)4294967 // (4294967295/1000) -- for conversion to uint32_t
-#define MOTOR_TIMEOUT_SECONDS (float)0.1 // seconds in DISABLE_AXIS_WHEN_IDLE mode
-#define MOTOR_TIMEOUT_WHEN_MOVING (float)0.25 // timeout for a motor in _ONLY_WHEN_MOVING mode
+#define MOTOR_TIMEOUT_SECONDS (float)0.1 // seconds in DISABLE_AXIS_WHEN_IDLE mode
+#define MOTOR_TIMEOUT_WHEN_MOVING (float)0.25 // timeout for a motor in _ONLY_WHEN_MOVING mode
/* DDA substepping
* DDA Substepping is a fixed.point scheme to increase the resolution of the DDA pulse generation
*/
#define DDA_SUBSTEPS ((MAX_LONG * 0.90) / (FREQUENCY_DDA * (NOM_SEGMENT_TIME * 60)))
+
/* Step correction settings
* Step correction settings determine how the encoder error is fed back to correct position errors.
* Since the following_error is running 2 segments behind the current segment you have to be careful
* and error will grow instead of shrink (or oscillate).
*/
#define STEP_CORRECTION_THRESHOLD (float)2.00 // magnitude of forwarding error to apply correction (in steps)
-#define STEP_CORRECTION_FACTOR (float)0.25 // factor to apply to step correction for a single segment
-#define STEP_CORRECTION_MAX (float)0.60 // max step correction allowed in a single segment
-#define STEP_CORRECTION_HOLDOFF 5 // minimum number of segments to wait between error correction
-#define STEP_INITIAL_DIRECTION DIRECTION_CW
+#define STEP_CORRECTION_FACTOR (float)0.25 // factor to apply to step correction for a single segment
+#define STEP_CORRECTION_MAX (float)0.60 // max step correction allowed in a single segment
+#define STEP_CORRECTION_HOLDOFF 5 // minimum number of segments to wait between error correction
+#define STEP_INITIAL_DIRECTION DIRECTION_CW
+
/*
* Stepper control structures
* There are 5 main structures involved in stepper operations;
*
* data structure: found in: runs primarily at:
- * mpBuffer planning buffers (bf) planner.c main loop
- * mrRuntimeSingleton (mr) planner.c MED ISR
- * stConfig (st_cfg) stepper.c write=bkgd, read=ISRs
- * stPrepSingleton (st_pre) stepper.c MED ISR
- * stRunSingleton (st_run) stepper.c HI ISR
+ * mpBuffer planning buffers (bf) planner.c main loop
+ * mrRuntimeSingleton (mr) planner.c MED ISR
+ * stConfig (st_cfg) stepper.c write=bkgd, read=ISRs
+ * stPrepSingleton (st_pre) stepper.c MED ISR
+ * stRunSingleton (st_run) stepper.c HI ISR
*
* Care has been taken to isolate actions on these structures to the execution level
* in which they run and to use the minimum number of volatiles in these structures.
*/
// Motor config structure
-
-typedef struct cfgMotor { // per-motor configs
- // public
- uint8_t motor_map; // map motor to axis
- uint32_t microsteps; // microsteps to apply for each axis (ex: 8)
- uint8_t polarity; // 0=normal polarity, 1=reverse motor direction
- uint8_t power_mode; // See cmMotorPowerMode for enum
- float power_level; // set 0.000 to 1.000 for PMW vref setting
- float step_angle; // degrees per whole step (ex: 1.8)
- float travel_rev; // mm or deg of travel per motor revolution
- float steps_per_unit; // microsteps per mm (or degree) of travel
- float units_per_step; // mm or degrees of travel per microstep
-
- // private
- float power_level_scaled; // scaled to internal range - must be between 0 and 1
+typedef struct cfgMotor { // per-motor configs
+ // public
+ uint8_t motor_map; // map motor to axis
+ uint32_t microsteps; // microsteps to apply for each axis (ex: 8)
+ uint8_t polarity; // 0=normal polarity, 1=reverse motor direction
+ uint8_t power_mode; // See cmMotorPowerMode for enum
+ float power_level; // set 0.000 to 1.000 for PMW vref setting
+ float step_angle; // degrees per whole step (ex: 1.8)
+ float travel_rev; // mm or deg of travel per motor revolution
+ float steps_per_unit; // microsteps per mm (or degree) of travel
+ float units_per_step; // mm or degrees of travel per microstep
+
+ // private
+ float power_level_scaled; // scaled to internal range - must be between 0 and 1
} cfgMotor_t;
-typedef struct stConfig { // stepper configs
- float motor_power_timeout; // seconds before setting motors to idle current (currently this is OFF)
- cfgMotor_t mot[MOTORS]; // settings for motors 1-N
+
+typedef struct stConfig { // stepper configs
+ float motor_power_timeout; // seconds before setting motors to idle current (currently this is OFF)
+ cfgMotor_t mot[MOTORS]; // settings for motors 1-N
} stConfig_t;
-// Motor runtime structure. Used exclusively by step generation ISR (HI)
-typedef struct stRunMotor { // one per controlled motor
- uint32_t substep_increment; // total steps in axis times substeps factor
- int32_t substep_accumulator; // DDA phase angle accumulator
- uint8_t power_state; // state machine for managing motor power
- uint32_t power_systick; // sys_tick for next motor power state transition
+// Motor runtime structure. Used exclusively by step generation ISR (HI)
+typedef struct stRunMotor { // one per controlled motor
+ uint32_t substep_increment; // total steps in axis times substeps factor
+ int32_t substep_accumulator; // DDA phase angle accumulator
+ uint8_t power_state; // state machine for managing motor power
+ uint32_t power_systick; // sys_tick for next motor power state transition
} stRunMotor_t;
-typedef struct stRunSingleton { // Stepper static values and axis parameters
- uint16_t magic_start; // magic number to test memory integrity
- uint32_t dda_ticks_downcount; // tick down-counter (unscaled)
- uint32_t dda_ticks_X_substeps; // ticks multiplied by scaling factor
- stRunMotor_t mot[MOTORS]; // runtime motor structures
- uint16_t magic_end;
+
+typedef struct stRunSingleton { // Stepper static values and axis parameters
+ uint16_t magic_start; // magic number to test memory integrity
+ uint32_t dda_ticks_downcount; // tick down-counter (unscaled)
+ uint32_t dda_ticks_X_substeps; // ticks multiplied by scaling factor
+ stRunMotor_t mot[MOTORS]; // runtime motor structures
+ uint16_t magic_end;
} stRunSingleton_t;
+
// Motor prep structure. Used by exec/prep ISR (MED) and read-only during load
// Must be careful about volatiles in this one
-
typedef struct stPrepMotor {
- uint32_t substep_increment; // total steps in axis times substep factor
+ uint32_t substep_increment; // total steps in axis times substep factor
- // direction and direction change
- int8_t direction; // travel direction corrected for polarity
- uint8_t prev_direction; // travel direction from previous segment run for this motor
- int8_t step_sign; // set to +1 or -1 for encoders
+ // direction and direction change
+ int8_t direction; // travel direction corrected for polarity
+ uint8_t prev_direction; // travel direction from previous segment run for this motor
+ int8_t step_sign; // set to +1 or -1 for encoders
- // following error correction
- int32_t correction_holdoff; // count down segments between corrections
- float corrected_steps; // accumulated correction steps for the cycle (for diagnostic display only)
+ // following error correction
+ int32_t correction_holdoff; // count down segments between corrections
+ float corrected_steps; // accumulated correction steps for the cycle (for diagnostic display only)
- // accumulator phase correction
- float prev_segment_time; // segment time from previous segment run for this motor
- float accumulator_correction; // factor for adjusting accumulator between segments
- uint8_t accumulator_correction_flag;// signals accumulator needs correction
+ // accumulator phase correction
+ float prev_segment_time; // segment time from previous segment run for this motor
+ float accumulator_correction; // factor for adjusting accumulator between segments
+ uint8_t accumulator_correction_flag;// signals accumulator needs correction
} stPrepMotor_t;
+
typedef struct stPrepSingleton {
- uint16_t magic_start; // magic number to test memory integrity
- volatile uint8_t buffer_state; // prep buffer state - owned by exec or loader
- struct mpBuffer *bf; // static pointer to relevant buffer
- uint8_t move_type; // move type
-
- uint16_t dda_period; // DDA or dwell clock period setting
- uint32_t dda_ticks; // DDA or dwell ticks for the move
- uint32_t dda_ticks_X_substeps; // DDA ticks scaled by substep factor
- stPrepMotor_t mot[MOTORS]; // prep time motor structs
- uint16_t magic_end;
+ uint16_t magic_start; // magic number to test memory integrity
+ volatile uint8_t buffer_state; // prep buffer state - owned by exec or loader
+ struct mpBuffer *bf; // static pointer to relevant buffer
+ uint8_t move_type; // move type
+
+ uint16_t dda_period; // DDA or dwell clock period setting
+ uint32_t dda_ticks; // DDA or dwell ticks for the move
+ uint32_t dda_ticks_X_substeps; // DDA ticks scaled by substep factor
+ stPrepMotor_t mot[MOTORS]; // prep time motor structs
+ uint16_t magic_end;
} stPrepSingleton_t;
-extern stConfig_t st_cfg; // config struct is exposed. The rest are private
-extern stPrepSingleton_t st_pre; // only used by config_app diagnostics
-/**** FUNCTION PROTOTYPES ****/
+extern stConfig_t st_cfg; // config struct is exposed. The rest are private
+extern stPrepSingleton_t st_pre; // only used by config_app diagnostics
+
void stepper_init();
void stepper_init_assertions();
#ifdef __TEXT_MODE
- void st_print_ma(nvObj_t *nv);
- void st_print_sa(nvObj_t *nv);
- void st_print_tr(nvObj_t *nv);
- void st_print_mi(nvObj_t *nv);
- void st_print_po(nvObj_t *nv);
- void st_print_pm(nvObj_t *nv);
- void st_print_pl(nvObj_t *nv);
- void st_print_pwr(nvObj_t *nv);
- void st_print_mt(nvObj_t *nv);
- void st_print_me(nvObj_t *nv);
- void st_print_md(nvObj_t *nv);
+void st_print_ma(nvObj_t *nv);
+void st_print_sa(nvObj_t *nv);
+void st_print_tr(nvObj_t *nv);
+void st_print_mi(nvObj_t *nv);
+void st_print_po(nvObj_t *nv);
+void st_print_pm(nvObj_t *nv);
+void st_print_pl(nvObj_t *nv);
+void st_print_pwr(nvObj_t *nv);
+void st_print_mt(nvObj_t *nv);
+void st_print_me(nvObj_t *nv);
+void st_print_md(nvObj_t *nv);
#else
- #define st_print_ma tx_print_stub
- #define st_print_sa tx_print_stub
- #define st_print_tr tx_print_stub
- #define st_print_mi tx_print_stub
- #define st_print_po tx_print_stub
- #define st_print_pm tx_print_stub
- #define st_print_pl tx_print_stub
- #define st_print_pwr tx_print_stub
- #define st_print_mt tx_print_stub
- #define st_print_me tx_print_stub
- #define st_print_md tx_print_stub
+#define st_print_ma tx_print_stub
+#define st_print_sa tx_print_stub
+#define st_print_tr tx_print_stub
+#define st_print_mi tx_print_stub
+#define st_print_po tx_print_stub
+#define st_print_pm tx_print_stub
+#define st_print_pl tx_print_stub
+#define st_print_pwr tx_print_stub
+#define st_print_mt tx_print_stub
+#define st_print_me tx_print_stub
+#define st_print_md tx_print_stub
#endif // __TEXT_MODE
-#endif // End of include guard: STEPPER_H_ONCE
+#endif // STEPPER_H_ONCE
// ritorno is a handy way to provide exception returns
// It returns only if an error occurred. (ritorno is Italian for return)
-#define ritorno(a) if((status_code=a) != STAT_OK) { return(status_code); }
+#define ritorno(a) if((status_code=a) != STAT_OK) { return status_code; }
// OS, communications and low-level status
#define STAT_OK 0 // function completed OK