diff --git a/g2core/alarm.cpp b/g2core/alarm.cpp index 7a962f5d..9516d98e 100644 --- a/g2core/alarm.cpp +++ b/g2core/alarm.cpp @@ -123,7 +123,7 @@ stat_t cm_is_alarmed() void cm_halt_all(void) { cm_halt_motion(); - cm_spindle_off_immediate(); + spindle_off_immediate(); cm_coolant_off_immediate(); } diff --git a/g2core/canonical_machine.cpp b/g2core/canonical_machine.cpp index 4117289c..fbbe3c84 100644 --- a/g2core/canonical_machine.cpp +++ b/g2core/canonical_machine.cpp @@ -1555,7 +1555,7 @@ static void _exec_program_finalize(float *value, bool *flag) cm_select_plane(cm->default_select_plane); // reset to default arc plane cm_set_distance_mode(cm->default_distance_mode); cm_set_arc_distance_mode(INCREMENTAL_DISTANCE_MODE);// always the default - cm_spindle_off_immediate(); // M5 + spindle_off_immediate(); // M5 cm_coolant_off_immediate(); // M9 cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // G94 cm_set_motion_mode(MODEL, MOTION_MODE_CANCEL_MOTION_MODE);// NIST specifies G1 (MOTION_MODE_STRAIGHT_FEED), but we cancel motion mode. Safer. @@ -2262,7 +2262,6 @@ stat_t cm_run_jog(nvObj_t *nv) return (STAT_OK); } - /*********************************************************************************** * Debugging Commands ***********************************************************************************/ diff --git a/g2core/config_app.cpp b/g2core/config_app.cpp index b547ab02..18d75cc8 100644 --- a/g2core/config_app.cpp +++ b/g2core/config_app.cpp @@ -852,16 +852,29 @@ const cfgItem_t cfgArray[] = { { "", "md", _f0, 0, st_print_md, get_nul, st_set_md, (float *)&cs.null, 0 }, // SET to disable motors // Spindle functions - { "sys","spep",_fipn,0, cm_print_spep,get_ui8, set_01, (float *)&spindle.enable_polarity, SPINDLE_ENABLE_POLARITY }, - { "sys","spdp",_fipn,0, cm_print_spdp,get_ui8, set_01, (float *)&spindle.dir_polarity, SPINDLE_DIR_POLARITY }, - { "sys","spph",_fipn,0, cm_print_spph,get_ui8, set_01, (float *)&spindle.pause_on_hold, SPINDLE_PAUSE_ON_HOLD }, - { "sys","spdw",_fipn,2, cm_print_spdw,get_flt, set_flt, (float *)&spindle.dwell_seconds, SPINDLE_DWELL_TIME }, - { "sys","ssoe",_fipn,0, cm_print_ssoe,get_ui8, set_01, (float *)&spindle.sso_enable, SPINDLE_OVERRIDE_ENABLE}, - { "sys","sso", _fipn,3, cm_print_sso, get_flt,cm_set_sso,(float *)&spindle.sso_factor, SPINDLE_OVERRIDE_FACTOR}, - { "", "spe", _fiz, 0, cm_print_spe, get_ui8, set_nul, (float *)&spindle.enable, 0 }, // get spindle enable - { "", "spd", _fiz, 0, cm_print_spd, get_ui8,cm_set_dir,(float *)&spindle.direction, 0 }, // get spindle direction - { "", "sps", _fiz, 0, cm_print_sps, get_flt, set_nul, (float *)&spindle.speed, 0 }, // get spindle speed - + { "sp","spmo",_fipn, 0, sp_print_spmo, sp_get_spmo, sp_set_spmo, (float *)&cs.null, SPINDLE_MODE }, + { "sp","spep",_fipn, 0, sp_print_spep, sp_get_spep, sp_set_spep, (float *)&cs.null, SPINDLE_ENABLE_POLARITY }, + { "sp","spdp",_fipn, 0, sp_print_spdp, sp_get_spdp, sp_set_spdp, (float *)&cs.null, SPINDLE_DIR_POLARITY }, + { "sp","spph",_fipn, 0, sp_print_spph, sp_get_spph, sp_set_spph, (float *)&cs.null, SPINDLE_PAUSE_ON_HOLD }, + { "sp","spdw",_fipn, 2, sp_print_spdw, sp_get_spdw, sp_set_spdw, (float *)&cs.null, SPINDLE_DWELL_TIME }, + { "sp","spsn",_fipn, 2, sp_print_spsn, sp_get_spsn, sp_set_spsn, (float *)&cs.null, SPINDLE_SPEED_MIN}, + { "sp","spsm",_fipn, 2, sp_print_spsm, sp_get_spsm, sp_set_spsm, (float *)&cs.null, SPINDLE_SPEED_MAX}, + { "sp","ssoe",_fipn, 0, sp_print_ssoe, sp_get_spep, sp_set_spep, (float *)&cs.null, SPINDLE_OVERRIDE_ENABLE}, + { "sp","sso", _fipn, 3, sp_print_sso, sp_get_sso, sp_set_sso, (float *)&cs.null, SPINDLE_OVERRIDE_FACTOR}, + { "", "sps", _fiz, 0, sp_print_sps, sp_get_sps, sp_set_sps, (float *)&cs.null, 0 }, // get spindle speed + { "", "spe", _fiz, 0, sp_print_spe, sp_get_spe, set_nul, (float *)&cs.null, 0 }, // get spindle enable state + { "", "spd", _fiz, 0, sp_print_spd, sp_get_spd, sp_set_spd, (float *)&cs.null, 0 }, // get spindle direction +/* + { "sys","spep",_fipn,0, sp_print_spep, get_ui8, set_01, (float *)&spindle.enable_polarity, SPINDLE_ENABLE_POLARITY }, + { "sys","spdp",_fipn,0, sp_print_spdp, get_ui8, set_01, (float *)&spindle.dir_polarity, SPINDLE_DIR_POLARITY }, + { "sys","spph",_fipn,0, sp_print_spph, get_ui8, set_01, (float *)&spindle.pause_on_hold, SPINDLE_PAUSE_ON_HOLD }, + { "sys","spdw",_fipn,2, sp_print_spdw, get_flt, set_flt, (float *)&spindle.dwell_seconds, SPINDLE_DWELL_TIME }, + { "sys","ssoe",_fipn,0, sp_print_ssoe, get_ui8, set_01, (float *)&spindle.sso_enable, SPINDLE_OVERRIDE_ENABLE}, + { "sys","sso", _fipn,3, sp_print_sso, sp_get_sso, sp_set_sso,(float *)&spindle.sso_factor, SPINDLE_OVERRIDE_FACTOR}, + { "", "spe", _fiz, 0, sp_print_spe, get_ui8, set_nul, (float *)&spindle.state, 0 }, // get spindle enable state + { "", "spd", _fiz, 0, sp_print_spd, get_ui8,sp_set_dir,(float *)&spindle.direction, 0 }, // get spindle direction + { "", "sps", _fiz, 0, sp_print_sps, get_flt, set_nul, (float *)&spindle.speed, 0 }, // get spindle speed +*/ // Coolant functions { "sys","cofp",_fipn,0, cm_print_cofp,get_ui8, set_01, (float *)&coolant.flood_polarity, COOLANT_FLOOD_POLARITY }, { "sys","comp",_fipn,0, cm_print_comp,get_ui8, set_01, (float *)&coolant.mist_polarity, COOLANT_MIST_POLARITY }, @@ -1059,9 +1072,10 @@ const cfgItem_t cfgArray[] = { // - Optional DIAGNOSTIC_PARAMETERS // - Uber groups (count these separately) -#define FIXED_GROUPS 2 +#define FIXED_GROUPS 3 { "","sys",_f0, 0, tx_print_nul, get_grp, set_grp,(float *)&cs.null,0 }, // system group { "","p1", _f0, 0, tx_print_nul, get_grp, set_grp,(float *)&cs.null,0 }, // PWM 1 group + { "","sp", _f0, 0, tx_print_nul, get_grp, set_grp,(float *)&cs.null,0 }, // Spindle group #define AXIS_GROUPS AXES { "","x", _f0, 0, tx_print_nul, get_grp, set_grp,(float *)&cs.null,0 }, // axis groups diff --git a/g2core/cycle_feedhold.cpp b/g2core/cycle_feedhold.cpp index a0a5efa1..9fd22510 100644 --- a/g2core/cycle_feedhold.cpp +++ b/g2core/cycle_feedhold.cpp @@ -37,11 +37,20 @@ #include "util.h" /*********************************************************************************** - **** CODE ************************************************************************* + **** Feedholds ******************************************************************** ***********************************************************************************/ /* - * Feedholds, queue flushes and end_holds are all related. The request functions set flags - * or change state to "REQUESTED". The sequencing callback interprets the flags as so: + * Feedholds, queue flushes and end_holds are all related and are in this file. + * Feedholds are implemented as a state machine (cmFeedholdState) that runs in the + * planner (plan_exec.cpp, see Feedhold Processing around line 500) and in this file. + * + * Feedholds also use the dual planner (secondary context, or hold context) where a + * new canonical machine and planner are spun up and entered when a feedhold is initiated. + * This allows (almost) all of the machine operations to be accessible during a feedhold. + * + * Feedholds are initiated and ended by a series of request flags (requests). + * The request functions set flags or change state to "REQUESTED". + * The sequencing callback interprets the flags as so: * - A feedhold request received during motion should be honored * - A feedhold request received during a feedhold should be ignored * - A feedhold request received during a motion stop should be ignored @@ -55,8 +64,8 @@ * - Said end_hold 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 - * - * Below the request level, feedholds work like this: + */ +/* Below the request level, feedholds work like this: * - The hold is initiated by calling cm_start_hold(). cm->hold_state is set to * FEEDHOLD_SYNC, motion_state is set to MOTION_HOLD, and the spindle is turned off * (if it it on). The remainder of feedhold @@ -101,7 +110,7 @@ - Machine alarm state is not (yet) taken into account in feedhold sequencing and restart */ -/* +/*********************************************************************************** * cm_request_feedhold() * cm_request_end_hold() * cm_request_queue_flush() @@ -161,7 +170,7 @@ stat_t cm_feedhold_sequencing_callback() return (STAT_OK); } -/* +/*********************************************************************************** * cm_has_hold() - return true if a hold condition exists (or a pending hold request) * cm_start_hold() - start a feedhhold by signalling the exec * cm_end_hold() - end a feedhold by returning the system to normal operation @@ -187,7 +196,7 @@ void cm_end_hold() } } -/* +/*********************************************************************************** * cm_switch_to_hold_context() - switch to secondary machine context * * Moving between contexts is only safe when the machine is completely stopped @@ -248,7 +257,7 @@ stat_t cm_switch_to_hold_context() return (STAT_OK); } -/* +/*********************************************************************************** * cm_return_from_hold_context() - initiate return from secondary context * cm_return_from_hold_callback() - main loop callback to finsh return once moves are done * _planner_done_callback() - callback to sync to end of planner operations @@ -320,7 +329,8 @@ stat_t cm_return_from_hold_callback() return (STAT_OK); } -/* Queue Flush operation +/*********************************************************************************** + * Queue Flush operations * * This one's complicated. See here first: * https://github.com/synthetos/g2/wiki/Alarm-Processing @@ -355,7 +365,8 @@ stat_t cm_return_from_hold_callback() * to ensure that it either arrives on the data channel or that the data channel is * empty before writing it to the control channel. */ -/* + +/*********************************************************************************** * cm_queue_flush() - Flush planner queue and correct model positions */ diff --git a/g2core/cycle_probing.cpp b/g2core/cycle_probing.cpp index 425b77a2..ff254fda 100644 --- a/g2core/cycle_probing.cpp +++ b/g2core/cycle_probing.cpp @@ -251,7 +251,7 @@ static uint8_t _probing_init() { gpio_set_probing_mode(pb.probe_input, true); // turn off spindle and start the move - cm_spindle_optional_pause(true); // pause the spindle if it's on + spindle_optional_pause(true); // pause the spindle if it's on return (_set_pb_func(_probing_start)); // start the probe move } @@ -391,7 +391,7 @@ static void _probe_restore_settings() { cm_set_distance_mode(pb.saved_distance_mode); // restart spindle if it was paused - cm_spindle_resume(spindle.dwell_seconds); + spindle_resume(spindle.dwell_seconds); // cancel the feed modes used during probing cm_set_motion_mode(MODEL, MOTION_MODE_CANCEL_MOTION_MODE); diff --git a/g2core/gcode_parser.cpp b/g2core/gcode_parser.cpp index 656068e0..b51f6699 100644 --- a/g2core/gcode_parser.cpp +++ b/g2core/gcode_parser.cpp @@ -733,14 +733,14 @@ static stat_t _execute_gcode_block(char *active_comment) cm_set_model_linenum(gv.linenum); EXEC_FUNC(cm_set_feed_rate_mode, feed_rate_mode); // G93, G94 EXEC_FUNC(cm_set_feed_rate, F_word); // F - EXEC_FUNC(cm_set_spindle_speed, S_word); // S + EXEC_FUNC(spindle_queue_speed, S_word); // S if (gf.sso_control) { // spindle speed override - ritorno(cm_sso_control(gv.P_word, gf.P_word)); + ritorno(spindle_override_control(gv.P_word, gf.P_word)); } EXEC_FUNC(cm_select_tool, tool_select); // tool_select is where it's written EXEC_FUNC(cm_change_tool, tool_change); // M6 - EXEC_FUNC(cm_spindle_control, spindle_control); // spindle CW, CCW, OFF + EXEC_FUNC(spindle_queue_control, spindle_control); // spindle CW, CCW, OFF EXEC_FUNC(cm_mist_coolant_control, mist_coolant); // M7, M9 EXEC_FUNC(cm_flood_coolant_control, flood_coolant); // M8, M9 also disables mist coolant if OFF diff --git a/g2core/gpio.h b/g2core/gpio.h old mode 100755 new mode 100644 index e156caad..9caf5644 --- a/g2core/gpio.h +++ b/g2core/gpio.h @@ -53,6 +53,24 @@ typedef enum { #define NORMALLY_OPEN IO_ACTIVE_LOW // equivalent #define NORMALLY_CLOSED IO_ACTIVE_HIGH // equivalent +// *** NOTE: The active hi/low values currently agree with spindle and coolant values +// The above will all need to be changed to ACTIVE_HIGH = 0, ACTIVE_LOW = 1 +// See: https://github.com/synthetos/g2_private/wiki/GPIO-Design-Discussion#settings-common-to-all-io-types + +/* The above will become: +typedef enum { + IO_ACTIVE_HIGH = 0, // input is active high (aka normally closed) + IO_ACTIVE_LOW = 1 // input is active low (aka normally open) +} ioPolarity; +#define NORMALLY_OPEN IO_ACTIVE_LOW // equivalent +#define NORMALLY_CLOSED IO_ACTIVE_HIGH // equivalent + +typedef enum { + IO_DISABLED = 0, // IO will not operate + IO_ENABLED // IO will operate +} ioMode; +*/ + typedef enum { // actions are initiated from within the input's ISR INPUT_ACTION_NONE = 0, INPUT_ACTION_STOP, // stop at normal jerk - preserves positional accuracy diff --git a/g2core/settings/settings_default.h b/g2core/settings/settings_default.h index 09f6bd6c..f87a3ee7 100644 --- a/g2core/settings/settings_default.h +++ b/g2core/settings/settings_default.h @@ -81,6 +81,10 @@ #define SAFETY_INTERLOCK_ENABLE 1 // {saf: 0=off, 1=on #endif +#ifndef SPINDLE_MODE +#define SPINDLE_MODE 1 // {spmo; 0=diabled, 1=plan to stop, 2=continuous +#endif + #ifndef SPINDLE_ENABLE_POLARITY #define SPINDLE_ENABLE_POLARITY SPINDLE_ACTIVE_HIGH // {spep: 0=active low, 1=active high #endif @@ -97,6 +101,18 @@ #define SPINDLE_DWELL_TIME 1.0 // {spdw: #endif +#ifndef SPINDLE_DWELL_MAX +#define SPINDLE_DWELL_MAX 10000000.0 // maximum allowable dwell time. May be overridden in settings files +#endif + +#ifndef SPINDLE_SPEED_MIN +#define SPINDLE_SPEED_MIN 0.0 // {spsn: +#endif + +#ifndef SPINDLE_SPEED_MAX +#define SPINDLE_SPEED_MAX 1000000.0 // {spsm: +#endif + #ifndef COOLANT_MIST_POLARITY #define COOLANT_MIST_POLARITY 1 // {comp: 0=active low, 1=active high #endif diff --git a/g2core/spindle.cpp b/g2core/spindle.cpp index de3ebb8d..0e5dcca6 100644 --- a/g2core/spindle.cpp +++ b/g2core/spindle.cpp @@ -33,6 +33,7 @@ #include "spindle.h" #include "planner.h" #include "hardware.h" +#include "settings.h" #include "pwm.h" #include "util.h" @@ -44,9 +45,9 @@ cmSpindleton_t spindle; static void _exec_spindle_speed(float *value, bool *flag); static void _exec_spindle_control(float *value, bool *flag); -static float _get_spindle_pwm (cmSpindleEnable enable, cmSpindleDir direction); +static float _get_spindle_pwm (spState state, spDir direction); -/* +/*********************************************************************************** * spindle_init() * spindle_reset() - stop spindle, set speed to zero, and reset values */ @@ -64,20 +65,58 @@ void spindle_reset() float value[AXES] = { 0,0,0,0,0,0 }; // set spindle speed to zero bool flags[] = { 1,0,0,0,0,0 }; _exec_spindle_speed(value, flags); - cm_spindle_off_immediate(); // turn spindle off + spindle_off_immediate(); // turn spindle off } -/* - * cm_set_spindle_speed() - queue the S parameter to the planner buffer +/*********************************************************************************** + * spindle_off_immediate() - turn on/off spindle w/o planning + * spindle_optional_pause() - pause spindle immediately if option is true + * spindle_resume() - restart a paused spindle with an optional dwell + */ + +void spindle_off_immediate() +{ + spindle.state = SPINDLE_OFF; + float value[] = { (float)SPINDLE_OFF, 0,0,0,0,0 }; + bool flags[] = { 1,0,0,0,0,0 }; + _exec_spindle_control(value, flags); +} + +void spindle_optional_pause(bool option) +{ + if (option && spindle.state == SPINDLE_ON) { + spindle_off_immediate(); + spindle.state = SPINDLE_PAUSE; + } +} + +void spindle_resume(float dwell_seconds) +{ + if(spindle.state == SPINDLE_PAUSE) { + spindle.state = SPINDLE_ON; + mp_request_out_of_band_dwell(dwell_seconds); + float value[] = { (float)SPINDLE_ON, (float)spindle.direction, 0,0,0,0 }; + bool flags[] = { 1,0,0,0,0,0 }; + _exec_spindle_control(value, flags); + } +} + +/*********************************************************************************** + * spindle_queue_speed() - queue the S parameter to the planner buffer * _exec_spindle_speed() - spindle speed callback from planner queue */ -stat_t cm_set_spindle_speed(float speed) +stat_t spindle_queue_speed(float speed) { -// if (speed > cfg.max_spindle speed) { return (STAT_MAX_SPINDLE_SPEED_EXCEEDED);} + if (speed < spindle.speed_min) { + return (STAT_SPINDLE_SPEED_BELOW_MINIMUM); + } + if (speed > spindle.speed_max) { + return (STAT_SPINDLE_SPEED_MAX_EXCEEDED); + } float value[AXES] = { speed, 0,0,0,0,0 }; - bool flags[] = { 1,0,0,0,0,0 }; + bool flags[] = { 1,0,0,0,0,0 }; mp_queue_command(_exec_spindle_speed, value, flags); return (STAT_OK); } @@ -89,81 +128,47 @@ static void _exec_spindle_speed(float *value, bool *flag) } if (flag[1]) { - spindle.direction = (cmSpindleDir)value[1]; + spindle.direction = (spDir)value[1]; } // update spindle speed if we're running - pwm_set_duty(PWM_1, _get_spindle_pwm(spindle.enable, spindle.direction)); + pwm_set_duty(PWM_1, _get_spindle_pwm(spindle.state, spindle.direction)); } -/* - * cm_spindle_off_immediate() - turn on/off spindle w/o planning - * cm_spindle_optional_pause() - pause spindle immediately if option is true - * cm_spindle_resume() - restart a paused spindle with an optional dwell - */ - -void cm_spindle_off_immediate() -{ - spindle.enable = SPINDLE_OFF; - float value[] = { (float)SPINDLE_OFF, 0,0,0,0,0 }; - bool flags[] = { 1,0,0,0,0,0 }; - _exec_spindle_control(value, flags); -} - -void cm_spindle_optional_pause(bool option) -{ - if (option && spindle.enable == SPINDLE_ON) { - cm_spindle_off_immediate(); - spindle.enable = SPINDLE_PAUSE; - } -} - -void cm_spindle_resume(float dwell_seconds) -{ - if(spindle.enable == SPINDLE_PAUSE) { - spindle.enable = SPINDLE_ON; - mp_request_out_of_band_dwell(dwell_seconds); - float value[] = { (float)SPINDLE_ON, (float)spindle.direction, 0,0,0,0 }; - bool flags[] = { 1,0,0,0,0,0 }; - _exec_spindle_control(value, flags); - } -} - -/* - * cm_spindle_control() - queue the spindle command to the planner buffer. Observe PAUSE +/*********************************************************************************** + * spindle_queue_control() - queue the spindle command to the planner buffer. Observe PAUSE * _exec_spindle_control() - actually execute the spindle command */ -stat_t cm_spindle_control(uint8_t control) // requires SPINDLE_CONTROL_xxx style args +stat_t spindle_queue_control(uint8_t control) // requires SPINDLE_CONTROL_xxx style args { if (control == SPINDLE_CONTROL_OFF) { - spindle.enable = SPINDLE_OFF; + spindle.state = SPINDLE_OFF; } else { - spindle.enable = SPINDLE_ON; + spindle.state = SPINDLE_ON; if (control == SPINDLE_CONTROL_CW) { spindle.direction = SPINDLE_CW; } else { spindle.direction = SPINDLE_CCW; } } - - float value[] = { (float)spindle.enable, (float)spindle.direction, 0,0,0,0 }; + float value[] = { (float)spindle.state, (float)spindle.direction, 0,0,0,0 }; bool flags[] = { 1,1,0,0,0,0 }; mp_queue_command(_exec_spindle_control, value, flags); return(STAT_OK); } - #define _set_spindle_enable_bit_hi() spindle_enable_pin.set() - #define _set_spindle_enable_bit_lo() spindle_enable_pin.clear() - #define _set_spindle_direction_bit_hi() spindle_dir_pin.set() - #define _set_spindle_direction_bit_lo() spindle_dir_pin.clear() +#define _set_spindle_enable_bit_hi() spindle_enable_pin.set() +#define _set_spindle_enable_bit_lo() spindle_enable_pin.clear() +#define _set_spindle_direction_bit_hi() spindle_dir_pin.set() +#define _set_spindle_direction_bit_lo() spindle_dir_pin.clear() static void _exec_spindle_control(float *value, bool *flag) { // set the direction first if (flag[1]) { - spindle.direction = (cmSpindleDir)value[1]; // record spindle direction in the struct + spindle.direction = (spDir)value[1]; // record spindle direction in the struct if (spindle.direction ^ spindle.dir_polarity) { _set_spindle_direction_bit_hi(); } else { @@ -174,22 +179,21 @@ static void _exec_spindle_control(float *value, bool *flag) if (flag[0]) { // set on/off. Mask out PAUSE and consider it OFF - spindle.enable = (cmSpindleEnable)value[0]; // record spindle enable in the struct - if ((spindle.enable & 0x01) ^ spindle.enable_polarity) { + spindle.state = (spState)value[0]; // record spindle state in the struct + if ((spindle.state & 0x01) ^ spindle.enable_polarity) { _set_spindle_enable_bit_lo(); } else { _set_spindle_enable_bit_hi(); } } - - pwm_set_duty(PWM_1, _get_spindle_pwm(spindle.enable, spindle.direction)); + pwm_set_duty(PWM_1, _get_spindle_pwm(spindle.state, spindle.direction)); } -/* +/*********************************************************************************** * _get_spindle_pwm() - return PWM phase (duty cycle) for dir and speed */ -static float _get_spindle_pwm (cmSpindleEnable enable, cmSpindleDir direction) +static float _get_spindle_pwm (spState state, spDir direction) { float speed_lo=0, speed_hi=0, phase_lo=0, phase_hi=0; if (direction == SPINDLE_CW ) { @@ -204,7 +208,7 @@ static float _get_spindle_pwm (cmSpindleEnable enable, cmSpindleDir direction) phase_hi = pwm.c[PWM_1].ccw_phase_hi; } - if (enable == SPINDLE_ON) { + if (state == SPINDLE_ON) { // clamp spindle speed to lo/hi range if (spindle.speed < speed_lo) { spindle.speed = speed_lo; @@ -220,24 +224,23 @@ static float _get_spindle_pwm (cmSpindleEnable enable, cmSpindleDir direction) } } - -/* - * cm_spindle_override_control() - * cm_start_spindle_override() - * cm_end_spindle_override() +/*********************************************************************************** + * spindle_override_control() + * spindle_sp_start_spindle_override() + * sp_end_spindle_override() */ -void cm_start_spindle_override(const float ramp_time, const float override_factor) +void spindle_start_override(const float ramp_time, const float override_factor) { return; } -void cm_end_spindle_override(const float ramp_time) +void spindle_end_override(const float ramp_time) { return; } -stat_t cm_sso_control(const float P_word, const bool P_flag) // M51 +stat_t spindle_override_control(const float P_word, const bool P_flag) // M51 { bool new_enable = true; bool new_override = false; @@ -257,9 +260,9 @@ stat_t cm_sso_control(const float P_word, const bool P_flag) // M51 } if (cm->gmx.m48_enable) { // if master enable is ON if (new_enable && (new_override || !spindle.sso_enable)) { // 3 cases to start a ramp - cm_start_spindle_override(SPINDLE_OVERRIDE_RAMP_TIME, spindle.sso_factor); + spindle_start_override(SPINDLE_OVERRIDE_RAMP_TIME, spindle.sso_factor); } else if (spindle.sso_enable && !new_enable) { // case to turn off the ramp - cm_end_spindle_override(SPINDLE_OVERRIDE_RAMP_TIME); + spindle_end_override(SPINDLE_OVERRIDE_RAMP_TIME); } } spindle.sso_enable = new_enable; // always update the enable state @@ -275,37 +278,66 @@ stat_t cm_sso_control(const float P_word, const bool P_flag) // M51 * Functions to get and set variables from the cfgArray table ***********************************************************************************/ -/* - * cm_set_dir() - a cheat to set direction w/o using the M commands - * - * This is provided as a way to set and clear spindle direction without using M commands - * It's here because disabling a spindle (M5) does not change the direction, only the enable. +/*********************************************************************************** + **** Spindle Settings + ***********************************************************************************/ + +stat_t sp_get_spmo(nvObj_t *nv) { return(get_int(nv, spindle.mode)); } +stat_t sp_set_spmo(nvObj_t *nv) { return(set_int(nv, (uint8_t &)spindle.mode, SPINDLE_DISABLED, SPINDLE_MODE_MAX)); } + +stat_t sp_get_spep(nvObj_t *nv) { return(get_int(nv, spindle.enable_polarity)); } +stat_t sp_set_spep(nvObj_t *nv) { return(set_int(nv, (uint8_t &)spindle.enable_polarity, 0, 1)); } +stat_t sp_get_spdp(nvObj_t *nv) { return(get_int(nv, spindle.dir_polarity)); } +stat_t sp_set_spdp(nvObj_t *nv) { return(set_int(nv, (uint8_t &)spindle.dir_polarity, 0, 1)); } +stat_t sp_get_spph(nvObj_t *nv) { return(get_int(nv, spindle.dir_polarity)); } +stat_t sp_set_spph(nvObj_t *nv) { return(set_int(nv, (uint8_t &)spindle.dir_polarity, 0, 1)); } + +stat_t sp_get_spdw(nvObj_t *nv) { return(get_float(nv, spindle.dwell_seconds)); } +stat_t sp_set_spdw(nvObj_t *nv) { return(set_float_range(nv, spindle.dwell_seconds, 0, SPINDLE_DWELL_MAX)); } +stat_t sp_get_spsn(nvObj_t *nv) { return(get_float(nv, spindle.speed_min)); } +stat_t sp_set_spsn(nvObj_t *nv) { return(set_float_range(nv, spindle.speed_min, SPINDLE_SPEED_MIN, SPINDLE_SPEED_MAX)); } +stat_t sp_get_spsm(nvObj_t *nv) { return(get_float(nv, spindle.speed_max)); } +stat_t sp_set_spsm(nvObj_t *nv) { return(set_float_range(nv, spindle.speed_max, SPINDLE_SPEED_MIN, SPINDLE_SPEED_MAX)); } + +stat_t sp_get_ssoe(nvObj_t *nv) { return(get_int(nv, spindle.sso_enable)); } +stat_t sp_set_ssoe(nvObj_t *nv) { return(set_int(nv, (uint8_t &)spindle.sso_enable, 0, 1)); } +stat_t sp_get_sso(nvObj_t *nv) { return(get_float(nv, spindle.sso_factor)); } +stat_t sp_set_sso(nvObj_t *nv) { return(set_float_range(nv, spindle.sso_factor, SPINDLE_OVERRIDE_MIN, SPINDLE_OVERRIDE_MAX)); } + +/* These are provided as a way to set and clear spindle states without using M commands + * SPD is useful because disabling a spindle (M5) does not change the direction, only the enable. */ -stat_t cm_set_dir(nvObj_t *nv) +stat_t sp_get_sps(nvObj_t *nv) { return(get_float(nv, spindle.speed)); } +stat_t sp_set_sps(nvObj_t *nv) { - set_01(nv); - float value[] = { (float)spindle.enable, (float)spindle.direction, 0,0,0,0 }; - bool flags[] = { 1,1,0,0,0,0 }; - _exec_spindle_control(value, flags); + set_float_range(nv, spindle.speed, spindle.speed_min, spindle.speed_max); + float value[] = { spindle.speed, 0,0,0,0,0 }; + bool flags[] = { 1,0,0,0,0,0 }; + _exec_spindle_speed(value, flags); return (STAT_OK); } - +stat_t sp_get_spe(nvObj_t *nv) { return(get_int(nv, spindle.state)); } /* - * cm_set_sso() - set spindle speed feedrate override factor - */ - -stat_t cm_set_sso(nvObj_t *nv) +stat_t sp_set_spe(nvObj_t *nv) { - if (nv->value < SPINDLE_OVERRIDE_MIN) { - return (STAT_INPUT_LESS_THAN_MIN_VALUE); - } - if (nv->value > SPINDLE_OVERRIDE_MAX) { - return (STAT_INPUT_EXCEEDS_MAX_VALUE); - } - set_flt(nv); - return(STAT_OK); +// set_int(nv, (uint8_t &)spindle.state, 0, 1); + float value[] = { (float)spindle.state, (float)spindle.direction, 0,0,0,0 }; + bool flags[] = { 1,1,0,0,0,0 }; + _exec_spindle_control(value, flags); + return (STAT_OK); +} +*/ + +stat_t sp_get_spd(nvObj_t *nv) { return(get_int(nv, spindle.direction)); } +stat_t sp_set_spd(nvObj_t *nv) +{ + set_int(nv, (uint8_t &)spindle.direction, 0, 1); + float value[] = { (float)spindle.state, (float)spindle.direction, 0,0,0,0 }; + bool flags[] = { 1,1,0,0,0,0 }; + _exec_spindle_control(value, flags); + return (STAT_OK); } /*********************************************************************************** @@ -315,24 +347,30 @@ stat_t cm_set_sso(nvObj_t *nv) #ifdef __TEXT_MODE +const char fmt_spmo[] = "[spmo] spindle mode%16d [0=disabled,1=plan-to-stop,2=continuous]\n"; const char fmt_spep[] = "[spep] spindle enable polarity%5d [0=active_low,1=active_high]\n"; const char fmt_spdp[] = "[spdp] spindle direction polarity%2d [0=CW_low,1=CW_high]\n"; const char fmt_spph[] = "[spph] spindle pause on hold%7d [0=no,1=pause_on_hold]\n"; const char fmt_spdw[] = "[spdw] spindle dwell time%12.1f seconds\n"; -const char fmt_ssoe[] ="[ssoe] spindle speed override ena%2d [0=disable,1=enable]\n"; -const char fmt_sso[] ="[sso] spindle speed override%11.3f [0.050 < sso < 2.000]\n"; -const char fmt_spe[] = "Spindle Enable:%7d [0=OFF,1=ON,2=PAUSE]\n"; -const char fmt_spd[] = "Spindle Direction:%4d [0=CW,1=CCW]\n"; -const char fmt_sps[] = "Spindle Speed: %7.0f rpm\n"; +const char fmt_spsn[] = "[spsn] spindle speed min%14.2f rpm\n"; +const char fmt_spsm[] = "[spsm] spindle speed max%14.2f rpm\n"; +const char fmt_ssoe[] = "[ssoe] spindle speed override ena%2d [0=disable,1=enable]\n"; +const char fmt_sso[] = "[sso] spindle speed override%10.3f [0.050 < sso < 2.000]\n"; +const char fmt_sps[] = "Spindle Speed: %7.0f rpm\n"; +const char fmt_spe[] = "Spindle Enable:%7d [0=OFF,1=ON,2=PAUSE]\n"; +const char fmt_spd[] = "Spindle Direction:%4d [0=CW,1=CCW]\n"; -void cm_print_spep(nvObj_t *nv) { text_print(nv, fmt_spep);} // TYPE_INT -void cm_print_spdp(nvObj_t *nv) { text_print(nv, fmt_spdp);} // TYPE_INT -void cm_print_spph(nvObj_t *nv) { text_print(nv, fmt_spph);} // TYPE_INT -void cm_print_spdw(nvObj_t *nv) { text_print(nv, fmt_spdw);} // TYPE_FLOAT -void cm_print_ssoe(nvObj_t *nv) { text_print(nv, fmt_ssoe);} // TYPE INT -void cm_print_sso(nvObj_t *nv) { text_print(nv, fmt_sso);} // TYPE FLOAT -void cm_print_spe(nvObj_t *nv) { text_print(nv, fmt_spe);} // TYPE_INT -void cm_print_spd(nvObj_t *nv) { text_print(nv, fmt_spd);} // TYPE_INT -void cm_print_sps(nvObj_t *nv) { text_print(nv, fmt_sps);} // TYPE_FLOAT +void sp_print_spmo(nvObj_t *nv) { text_print(nv, fmt_spmo);} // TYPE_INT +void sp_print_spep(nvObj_t *nv) { text_print(nv, fmt_spep);} // TYPE_INT +void sp_print_spdp(nvObj_t *nv) { text_print(nv, fmt_spdp);} // TYPE_INT +void sp_print_spph(nvObj_t *nv) { text_print(nv, fmt_spph);} // TYPE_INT +void sp_print_spdw(nvObj_t *nv) { text_print(nv, fmt_spdw);} // TYPE_FLOAT +void sp_print_spsn(nvObj_t *nv) { text_print(nv, fmt_spsn);} // TYPE_FLOAT +void sp_print_spsm(nvObj_t *nv) { text_print(nv, fmt_spsm);} // TYPE_FLOAT +void sp_print_ssoe(nvObj_t *nv) { text_print(nv, fmt_ssoe);} // TYPE INT +void sp_print_sso(nvObj_t *nv) { text_print(nv, fmt_sso);} // TYPE FLOAT +void sp_print_spe(nvObj_t *nv) { text_print(nv, fmt_spe);} // TYPE_INT +void sp_print_spd(nvObj_t *nv) { text_print(nv, fmt_spd);} // TYPE_INT +void sp_print_sps(nvObj_t *nv) { text_print(nv, fmt_sps);} // TYPE_FLOAT #endif // __TEXT_MODE diff --git a/g2core/spindle.h b/g2core/spindle.h index 5ed3e877..f2446155 100644 --- a/g2core/spindle.h +++ b/g2core/spindle.h @@ -32,23 +32,36 @@ typedef enum { // how spindle controls are presented by the Gco SPINDLE_CONTROL_OFF = 0, // M5 SPINDLE_CONTROL_CW, // M3 SPINDLE_CONTROL_CCW // M4 -} cmSpindleControl; - -typedef enum { - SPINDLE_OFF = 0, - SPINDLE_ON, - SPINDLE_PAUSE // meaning it was on and now it's off -} cmSpindleEnable; +} spControl; typedef enum { // spindle direction state SPINDLE_CW = 0, SPINDLE_CCW -} cmSpindleDir; +} spDir; -typedef enum { - SPINDLE_ACTIVE_LOW = 0, - SPINDLE_ACTIVE_HIGH -} cmSpindlePolarity; + +// *** NOTE: The spindle polarity active hi/low values currently agree with ioMode in gpio.h +// These will all need to be changed to ACTIVE_HIGH = 0, ACTIVE_LOW = 1 +// See: https://github.com/synthetos/g2_private/wiki/GPIO-Design-Discussion#settings-common-to-all-io-types + +typedef enum { + SPINDLE_DISABLED = 0, // spindle will not operate + SPINDLE_PLAN_TO_STOP, // spindle operating, plans to stop + SPINDLE_CONTINUOUS, // spindle operating, does not plan to stop +} spMode; +#define SPINDLE_MODE_MAX SPINDLE_CONTINUOUS + +typedef enum { // Note: These values agree with + SPINDLE_ACTIVE_LOW = 0, // Will set output to 0 to enable the spindle or CW direction + SPINDLE_ACTIVE_HIGH = 1, // Will set output to 1 to enable the spindle or CW direction +} spPolarity; + +typedef enum { // basic spindle state machine + SPINDLE_OFF = 0, + SPINDLE_ON, // spindle on and at speed + SPINDLE_PAUSE, // meaning it was on and now it's off + SPINDLE_WAITING // spindle not at speed yet +} spState; typedef enum { ESC_ONLINE = 0, @@ -56,7 +69,7 @@ typedef enum { ESC_LOCKOUT, ESC_REBOOTING, ESC_LOCKOUT_AND_REBOOTING, -} cmESCState; +} ESCState; #define SPINDLE_OVERRIDE_ENABLE false #define SPINDLE_OVERRIDE_FACTOR 1.00 @@ -69,21 +82,27 @@ typedef enum { */ typedef struct cmSpindleSingleton { - float speed; // S in RPM - cmSpindleEnable enable; // OFF, ON, PAUSE - cmSpindleDir direction; // CW, CCW - bool pause_on_hold; // pause on feedhold - cmSpindlePolarity enable_polarity; // 0=active low, 1=active high - cmSpindlePolarity dir_polarity; // 0=clockwise low, 1=clockwise high - float dwell_seconds; // dwell on spindle resume + // Public and settable + spMode mode; // spondle operating mode + float speed; // S in RPM + float speed_min; // minimum settable spindle speed + float speed_max; // maximum settable spindle speed + spDir direction; // CW, CCW + spPolarity enable_polarity; // 0=active low, 1=active high + spPolarity dir_polarity; // 0=clockwise low, 1=clockwise high + float dwell_seconds; // dwell on spindle resume + bool pause_on_hold; // pause on feedhold + bool sso_enable; // TRUE = spindle speed override enabled (see also m48_enable in canonical machine) + float sso_factor; // 1.0000 x S spindle speed. Go up or down from there + + // Spindle internal state - not directly settable by user or program + spState state; // OFF, ON, PAUSE, WAITING - bool sso_enable; // TRUE = spindle speed override enabled (see also m48_enable in canonical machine) - float sso_factor; // 1.0000 x S spindle speed. Go up or down from there - - cmESCState esc_state; // state management for ESC controller - uint32_t esc_boot_timer; // When the ESC last booted up - uint32_t esc_lockout_timer; // When the ESC lockout last triggered + // Spindle speed controller variables + ESCState esc_state; // state management for ESC controller + uint32_t esc_boot_timer; // When the ESC last booted up + uint32_t esc_lockout_timer; // When the ESC lockout last triggered } cmSpindleton_t; extern cmSpindleton_t spindle; @@ -94,44 +113,75 @@ extern cmSpindleton_t spindle; void spindle_init(); void spindle_reset(); -stat_t cm_set_spindle_speed(float speed); // S parameter -stat_t cm_spindle_control(uint8_t control); // M3, M4, M5 integrated spindle control -void cm_spindle_off_immediate(void); -void cm_spindle_optional_pause(bool option); // stop spindle based on system options selected -void cm_spindle_resume(float dwell_seconds); // restart spindle after pause based on previous state +stat_t spindle_queue_speed(float speed); // S parameter +stat_t spindle_queue_control(uint8_t control); // M3, M4, M5 integrated spindle control +void spindle_off_immediate(void); +void spindle_optional_pause(bool option); // stop spindle based on system options selected +void spindle_resume(float dwell_seconds); // restart spindle after pause based on previous state -stat_t cm_sso_control(const float P_word, const bool P_flag); // M51 -void cm_start_spindle_override(const float ramp_time, const float override_factor); -void cm_end_spindle_override(const float ramp_time); +stat_t spindle_override_control(const float P_word, const bool P_flag); // M51 +void spindle_start_override(const float ramp_time, const float override_factor); +void spindle_end_override(const float ramp_time); -stat_t cm_set_dir(nvObj_t* nv); -stat_t cm_set_sso(nvObj_t* nv); +stat_t sp_get_spmo(nvObj_t *nv); +stat_t sp_set_spmo(nvObj_t *nv); +stat_t sp_get_spep(nvObj_t *nv); +stat_t sp_set_spep(nvObj_t *nv); +stat_t sp_get_spdp(nvObj_t *nv); +stat_t sp_set_spdp(nvObj_t *nv); +stat_t sp_get_spph(nvObj_t *nv); +stat_t sp_set_spph(nvObj_t *nv); + +stat_t sp_get_spdw(nvObj_t *nv); +stat_t sp_set_spdw(nvObj_t *nv); +stat_t sp_get_spsn(nvObj_t *nv); +stat_t sp_set_spsn(nvObj_t *nv); +stat_t sp_get_spsm(nvObj_t *nv); +stat_t sp_set_spsm(nvObj_t *nv); + +stat_t sp_get_ssoe(nvObj_t* nv); +stat_t sp_set_ssoe(nvObj_t* nv); +stat_t sp_get_sso(nvObj_t* nv); +stat_t sp_set_sso(nvObj_t* nv); + +stat_t sp_get_sps(nvObj_t* nv); +stat_t sp_set_sps(nvObj_t* nv); +stat_t sp_get_spe(nvObj_t* nv); +stat_t sp_set_spe(nvObj_t* nv); +stat_t sp_get_spd(nvObj_t* nv); +stat_t sp_set_spd(nvObj_t* nv); /*--- text_mode support functions ---*/ #ifdef __TEXT_MODE - void cm_print_spep(nvObj_t* nv); - void cm_print_spdp(nvObj_t* nv); - void cm_print_spph(nvObj_t* nv); - void cm_print_spdw(nvObj_t* nv); - void cm_print_ssoe(nvObj_t* nv); - void cm_print_sso(nvObj_t* nv); - void cm_print_spe(nvObj_t* nv); - void cm_print_spd(nvObj_t* nv); - void cm_print_sps(nvObj_t* nv); + void sp_print_spmo(nvObj_t* nv); + void sp_print_spep(nvObj_t* nv); + void sp_print_spdp(nvObj_t* nv); + void sp_print_spph(nvObj_t* nv); + void sp_print_spdw(nvObj_t* nv); + void sp_print_spsn(nvObj_t* nv); + void sp_print_spsm(nvObj_t* nv); + void sp_print_ssoe(nvObj_t* nv); + void sp_print_sso(nvObj_t* nv); + void sp_print_sps(nvObj_t* nv); + void sp_print_spe(nvObj_t* nv); + void sp_print_spd(nvObj_t* nv); #else - #define cm_print_spep tx_print_stub - #define cm_print_spdp tx_print_stub - #define cm_print_spph tx_print_stub - #define cm_print_spdw tx_print_stub - #define cm_print_ssoe tx_print_stub - #define cm_print_spe tx_print_stub - #define cm_print_sso tx_print_stub - #define cm_print_spd tx_print_stub - #define cm_print_sps tx_print_stub + #define sp_print_spmo tx_print_stub + #define sp_print_spep tx_print_stub + #define sp_print_spdp tx_print_stub + #define sp_print_spph tx_print_stub + #define sp_print_spdw tx_print_stub + #define sp_print_spsn tx_print_stub + #define sp_print_spsm tx_print_stub + #define sp_print_ssoe tx_print_stub + #define sp_print_spe tx_print_stub + #define sp_print_sps tx_print_stub + #define sp_print_sso tx_print_stub + #define sp_print_spd tx_print_stub #endif // __TEXT_MODE