diff --git a/config.h b/config.h index 6e96453..f27a4b7 100755 --- a/config.h +++ b/config.h @@ -62,13 +62,40 @@ #define COOLANT_FLOOD_PORT PORTC #define COOLANT_FLOOD_BIT 0 // Uno Analog Pin 0 -// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable. +// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable. #ifdef ENABLE_M7 #define COOLANT_MIST_DDR DDRC #define COOLANT_MIST_PORT PORTC #define COOLANT_MIST_BIT 1 // Uno Analog Pin 1 #endif +// Default settings (used when resetting eeprom-settings) +// TODO: Begin to fill these out for various as-built machines, i.e. config_sherline5400.h +#define MICROSTEPS 4 +#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS) +#define DEFAULT_STEP_PULSE_MICROSECONDS 10 +#define DEFAULT_MM_PER_ARC_SEGMENT 0.1 +#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min +#define DEFAULT_FEEDRATE 250.0 +#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2 +#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm +#define DEFAULT_STEPPING_INVERT_MASK ((1< NOW CODED INTO SETTINGS #define BLOCK_DELETE_ENABLE 0 // Block delete enable/disable flag during g-code parsing - -// This parameter sets the delay time before disabling the steppers after the final block of movement. -// A short delay ensures the steppers come to a complete stop and the residual inertial force in the -// CNC axes don't cause the axes to drift off position. This is particularly important when manually -// entering g-code into grbl, i.e. locating part zero or simple manual machining. If the axes drift, -// grbl has no way to know this has happened, since stepper motors are open-loop control. Depending -// on the machine, this parameter may need to be larger or smaller than the default time. -// NOTE: If set to zero, no lock will occur. If set to max 255, the lock will never release, in other -// words, the steppers never disable for users that require this. -// -> NOW INSTALLED IN SETTINGS #define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer > 0 - -// Number of arc generation iterations by small angle approximation before exact arc trajectory -// correction. This parameter maybe decreased if there are issues with the accuracy of the arc -// generations. In general, the default value is more than enough for the intended CNC applications -// of grbl, and should be on the order or greater than the size of the buffer to help with the -// computational efficiency of generating arcs. -// -> NOW INSTALLED IN SETTINGS #define N_ARC_CORRECTION 25 // Integer (1-255) - -// Specifies the number of work coordinate systems grbl will support (G54 - G59). -// This parameter must be one or greater, currently supporting up to a value of 6. -// -> NOW CODED INTO SETTINGS.C #define N_COORDINATE_SYSTEM 6 - // TODO: Install compile-time option to send numeric status codes rather than strings. #endif diff --git a/gcode.c b/gcode.c index 2ba47c0..235371c 100755 --- a/gcode.c +++ b/gcode.c @@ -177,7 +177,7 @@ uint8_t gc_execute_line(char *line) switch(int_value) { case 0: gc.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause case 1: // Program pause with optional stop on, otherwise do nothing. - if (bit_istrue(sys.switches,BITFLAG_OPT_STOP)) { + if (bit_istrue(gc.switches,BITFLAG_OPT_STOP)) { gc.program_flow = PROGRAM_FLOW_PAUSED; } break; @@ -253,13 +253,20 @@ uint8_t gc_execute_line(char *line) NOTE: Independent non-motion/settings parameters are set out of this order for code efficiency and simplicity purposes, but this should not affect proper g-code execution. */ + // ([F]: Set feed rate. Already performed, but enforce rapids for dry runs.) + if (bit_istrue(gc.switches,BITFLAG_DRY_RUN)) { gc.feed_rate = settings.default_seek_rate; } + // ([M6]: Tool change should be executed here.) // [M3,M4,M5]: Update spindle state - spindle_run(gc.spindle_direction); //, gc.spindle_speed); + if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) { + spindle_run(gc.spindle_direction); //, gc.spindle_speed); + } // [*M7,M8,M9]: Update coolant state - coolant_run(gc.coolant_mode); + if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) { + coolant_run(gc.coolant_mode); + } // [G54,G55,...,G59]: Coordinate system selection if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_12)) ) { // Check if called in block @@ -275,8 +282,11 @@ uint8_t gc_execute_line(char *line) case NON_MODAL_DWELL: if (p < 0) { // Time cannot be negative. FAIL(STATUS_INVALID_STATEMENT); - } else { - mc_dwell(p); + } else { + // Ignore dwell in dry run and check gcode modes + if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) { + mc_dwell(p); + } } break; case NON_MODAL_SET_COORDINATE_DATA: @@ -537,7 +547,7 @@ uint8_t gc_execute_line(char *line) // M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may // refill and can only be resumed by the cycle start run-time command. - if (gc.program_flow || bit_istrue(sys.switches,BITFLAG_SINGLE_BLOCK)) { + if (gc.program_flow || bit_istrue(gc.switches,BITFLAG_SINGLE_BLOCK)) { plan_synchronize(); // Finish all remaining buffered motions. Program paused when complete. sys.auto_start = false; // Disable auto cycle start. Forces pause until cycle start issued. diff --git a/gcode.h b/gcode.h index f993d43..c780c41 100755 --- a/gcode.h +++ b/gcode.h @@ -62,8 +62,19 @@ #define NON_MODAL_SET_COORDINATE_OFFSET 7 // G92 #define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1 +// Define bit flag masks for gc.switches. (8 flag limit) +#define BITFLAG_CHECK_GCODE bit(0) +#define BITFLAG_DRY_RUN bit(1) +#define BITFLAG_BLOCK_DELETE bit(2) +#define BITFLAG_SINGLE_BLOCK bit(3) +#define BITFLAG_OPT_STOP bit(4) +// #define bit(5) +// #define bit(6) +// #define bit(7) + typedef struct { uint8_t status_code; // Parser status for current block + uint8_t switches; // Handles non-gcode switches modes. Set externally by protocol. Default off uint8_t motion_mode; // {G0, G1, G2, G3, G80} uint8_t inverse_feed_rate_mode; // {G93, G94} uint8_t inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21} diff --git a/limits.c b/limits.c index 6dea453..f34ffbd 100755 --- a/limits.c +++ b/limits.c @@ -33,7 +33,6 @@ #include "limits.h" #include "report.h" -#define MICROSECONDS_PER_ACCELERATION_TICK (1000000/ACCELERATION_TICKS_PER_SECOND) void limits_init() { @@ -63,7 +62,7 @@ ISR(LIMIT_INT_vect) // Kill all processes upon hard limit event. if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) { mc_alarm(); // Initiate system kill. - report_status_message(STATUS_HARD_LIMIT); // Print ok in interrupt since system killed. + sys.state = STATE_LIMIT; // Set system state to indicate event. } } } diff --git a/limits.h b/limits.h index 0281ef4..59f9008 100755 --- a/limits.h +++ b/limits.h @@ -22,6 +22,7 @@ #define limits_h #define LIMIT_MASK ((1< +#include +#include +#include #include "settings.h" #include "config.h" #include "gcode.h" #include "motion_control.h" #include "spindle_control.h" #include "coolant_control.h" -#include -#include -#include #include "nuts_bolts.h" #include "stepper.h" #include "planner.h" @@ -61,18 +61,28 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat do { protocol_execute_runtime(); // Check for any run-time commands if (sys.abort) { return; } // Bail, if system abort. - } while ( plan_check_full_buffer() ); - plan_buffer_line(x, y, z, feed_rate, invert_feed_rate); - - // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During - // a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start - // runtime command. - // NOTE: This is allows the user to decide to exclusively use the cycle start runtime command to - // begin motion or let grbl auto-start it for them. This is useful when: manually cycle-starting - // when the buffer is completely full and primed; auto-starting, if there was only one g-code - // command sent during manual operation; or if a system is prone to buffer starvation, auto-start - // helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going. - if (sys.auto_start) { st_cycle_start(); } + } while ( plan_check_full_buffer() ); + + // If in check gcode mode, prevent motion by blocking planner. + if (bit_isfalse(gc.switches,BITFLAG_CHECK_GCODE)) { + plan_buffer_line(x, y, z, feed_rate, invert_feed_rate); + + // Indicate to the system there is now a planned block in the buffer ready to cycle start. + // NOTE: If homing cycles are enabled, a position lost state will lock out all motions, + // until a homing cycle has been completed. This is a safety feature to help prevent + // the machine from crashing. + if (!sys.state) { sys.state = STATE_QUEUED; } + + // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During + // a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start + // runtime command. + // NOTE: This is allows the user to decide to exclusively use the cycle start runtime command to + // begin motion or let grbl auto-start it for them. This is useful when: manually cycle-starting + // when the buffer is completely full and primed; auto-starting, if there was only one g-code + // command sent during manual operation; or if a system is prone to buffer starvation, auto-start + // helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going. + if (sys.auto_start) { st_cycle_start(); } + } } @@ -195,14 +205,19 @@ void mc_dwell(float seconds) } -// Execute homing cycle to locate and set machine zero. +// Perform homing cycle to locate and set machine zero. Only '$H' executes this command. +// NOTE: There should be no motions in the buffer and Grbl must be in an idle state before +// executing the homing cycle. This prevents incorrect buffered plans after homing. void mc_go_home() { - plan_synchronize(); // Empty all motions in buffer before homing. + sys.state = STATE_HOMING; // Set system state variable PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt - plan_clear_position(); - + limits_go_home(); // Perform homing routine. + if (sys.abort) { + sys.state = STATE_LOST; // Homing routine did not complete. + return; + } // The machine should now be homed and machine zero has been located. Upon completion, // reset planner and system internal position vectors, but not gcode parser position yet. @@ -227,6 +242,7 @@ void mc_go_home() // If hard limits feature enabled, re-enable hard limits interrupt after homing cycle. if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); } + sys.state = STATE_IDLE; // Finished! } diff --git a/motion_control.h b/motion_control.h index 4d71848..cd35f70 100755 --- a/motion_control.h +++ b/motion_control.h @@ -40,7 +40,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8 // Dwell for a specific number of seconds void mc_dwell(float seconds); -// Send the tool home (not implemented) +// Perform homing cycle to locate machine zero. Requires limit switches. void mc_go_home(); // Kills all motion and sets system alarm diff --git a/nuts_bolts.c b/nuts_bolts.c index 324b043..dbd1788 100755 --- a/nuts_bolts.c +++ b/nuts_bolts.c @@ -20,8 +20,6 @@ */ #include "nuts_bolts.h" -#include -#include #include #define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float) diff --git a/nuts_bolts.h b/nuts_bolts.h index 2eb0525..b894441 100755 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -66,36 +66,29 @@ // #define bit(6) // bitmask 01000000 // #define bit(7) // bitmask 10000000 -// Define bit flag masks for sys.switches. (8 flag limit) -#define BITFLAG_BLOCK_DELETE bit(0) -#define BITFLAG_SINGLE_BLOCK bit(1) -#define BITFLAG_OPT_STOP bit(2) -// #define bit(3) -// #define bit(4) -// #define bit(5) -// #define bit(6) -// #define bit(7) - -// Define Grbl system states for sys.state - -// Define position lost in states? - +// Define system state bit map. The state variable primarily tracks the individual functions +// of Grbl to manage each without overlapping. It is also used as a messaging flag for +// critical events. +#define STATE_IDLE 0 // Must be zero. +#define STATE_QUEUED 1 // Indicates buffered blocks, awaiting cycle start. +#define STATE_CYCLE 2 // Cycle is running +#define STATE_HOLD 3 // Executing feed hold +#define STATE_HOMING 4 // Performing homing cycle +#define STATE_JOG 5 // Jogging mode is unique like homing. +#define STATE_ALARM 6 // In alarm state. Locks out all but reset +#define STATE_LOST 7 // Used to message position may be lost upon startup or event +#define STATE_LIMIT 8 // Used to message hard limit triggered. // Define global system variables typedef struct { uint8_t abort; // System abort flag. Forces exit back to main loop for reset. - uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume. - uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings. - uint8_t switches; // Switches state bitflag variable. For features not governed by g-code. - -// uint8_t state; // Tracks the current state of Grbl. -// TODO: This may replace the functionality of the feed_hold and cycle_start variables. Need to -// make sure that overall processes don't change. - - volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program. + uint8_t state; // Tracks the current state of Grbl. volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks. int32_t position[3]; // Real-time machine (aka home) position vector in steps. // NOTE: This may need to be a volatile variable, if problems arise. + uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings. +// uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume. +// volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program. } system_t; extern system_t sys; diff --git a/planner.c b/planner.c index ffdf22e..fac89bf 100755 --- a/planner.c +++ b/planner.c @@ -22,10 +22,8 @@ /* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */ -#include -#include +#include #include - #include "planner.h" #include "nuts_bolts.h" #include "stepper.h" @@ -33,9 +31,6 @@ #include "config.h" #include "protocol.h" -// The number of linear motions that can be in the plan at any give time -#define BLOCK_BUFFER_SIZE 18 - static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions static volatile uint8_t block_buffer_head; // Index of the next block to be pushed static volatile uint8_t block_buffer_tail; // Index of the block to process now @@ -335,7 +330,7 @@ uint8_t plan_check_full_buffer() // Block until all buffered steps are executed. void plan_synchronize() { - while (plan_get_current_block() || sys.cycle_start) { + while (plan_get_current_block()) { protocol_execute_runtime(); // Check and execute run-time commands if (sys.abort) { return; } // Check for system abort } diff --git a/planner.h b/planner.h index 9c77f90..a326084 100755 --- a/planner.h +++ b/planner.h @@ -22,7 +22,8 @@ #ifndef planner_h #define planner_h -#include +// The number of linear motions that can be in the plan at any give time +#define BLOCK_BUFFER_SIZE 18 // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in // the source g-code and may never actually be reached if acceleration management is active. diff --git a/print.c b/print.c index 7aa710c..2f820d5 100755 --- a/print.c +++ b/print.c @@ -23,7 +23,6 @@ used to be a part of the Arduino project. */ -#include #include #include "config.h" #include "serial.h" @@ -109,6 +108,8 @@ void printInteger(long n) // Convert float to string by immediately converting to a long integer, which contains // more digits than a float. Number of decimal places, which are tracked by a counter, // may be set by the user. The integer is then efficiently converted to a string. +// NOTE: AVR '%' and '/' integer operations are very efficient. Bitshifting speed-up +// techniques are actually just slightly slower. Found this out the hard way. void printFloat(float n) { if (n < 0) { diff --git a/protocol.c b/protocol.c index 864351e..5c21d73 100755 --- a/protocol.c +++ b/protocol.c @@ -26,11 +26,8 @@ #include "print.h" #include "settings.h" #include "config.h" -#include #include "nuts_bolts.h" -#include #include "stepper.h" -#include "planner.h" #include "report.h" #include "motion_control.h" @@ -43,8 +40,24 @@ void protocol_init() { char_counter = 0; // Reset line input iscomment = false; + report_init_message(); // Welcome message } +// Executes user startup script, if stored. +void protocol_execute_startup() +{ + uint8_t n; + for (n=0; n < N_STARTUP_LINE; n++) { + if (!(settings_read_startup_line(n, line))) { + report_status_message(STATUS_SETTING_READ_FAIL); + } else { + if (line[0] != 0) { + printString(line); // Echo startup line to indicate execution. + report_status_message(gc_execute_line(line)); + } + } + } +} // Executes run-time commands, when required. This is called from various check points in the main // program, primarily where there may be a while loop waiting for a buffer to clear space or any @@ -65,7 +78,16 @@ void protocol_execute_runtime() // System alarm. Something has gone wrong. Disable everything by entering an infinite // loop until system reset/abort. if (rt_exec & EXEC_ALARM) { - if (bit_isfalse(rt_exec,EXEC_RESET)) { // Ignore loop if reset is already issued + // Report the cause of the alarm here in the main program. + if (sys.state == STATE_LIMIT) { report_status_message(STATUS_HARD_LIMIT); } + if (sys.state == STATE_CYCLE) { // Pick up abort during active cycle. + report_status_message(STATUS_ABORT_CYCLE); + sys.state = STATE_LOST; + } + // Ignore loop if reset is already issued. In other words, a normal system abort/reset + // will not enter this loop, only a critical event not controlled by the user will. + if (bit_isfalse(rt_exec,EXEC_RESET)) { + sys.state = STATE_ALARM; report_feedback_message(MESSAGE_SYSTEM_ALARM); while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); } } @@ -74,15 +96,7 @@ void protocol_execute_runtime() // System abort. Steppers have already been force stopped. if (rt_exec & EXEC_RESET) { - sys.abort = true; - - // If the cycle is active before killing the motion, the event will likely caused a loss - // of position since there is no controlled deceleration(feed hold) to a stop. - // TODO: Add force home option upon position lost. Need to verify that cycle start isn't - // set false by anything but the stepper module. Also, need to look at a better place for - // this. Main.c? - // if (sys.cycle_start) { protocol_feedback_message(MESSAGE_POSITION_LOST); } - + sys.abort = true; return; // Nothing else to do but exit. } @@ -98,7 +112,7 @@ void protocol_execute_runtime() bit_false(sys.execute,EXEC_FEED_HOLD); } - // Reinitializes the stepper module running flags and re-plans the buffer after a feed hold. + // Reinitializes the stepper module running state and, if a feed hold, re-plans the buffer. // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes. if (rt_exec & EXEC_CYCLE_STOP) { st_cycle_reinitialize(); @@ -133,6 +147,7 @@ uint8_t protocol_execute_line(char *line) if(line[0] == '$') { uint8_t char_counter = 1; + uint8_t helper_var = 0; // Helper variable float parameter, value; switch( line[char_counter] ) { case 0 : report_grbl_help(); break; @@ -149,8 +164,11 @@ uint8_t protocol_execute_line(char *line) else { report_gcode_modes(); } break; case 'H' : // Perform homing cycle - if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { mc_go_home(); } - else { return(STATUS_SETTING_DISABLED); } + if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { + // Only perform homing if Grbl is idle or lost. + if ( sys.state==STATE_IDLE || sys.state==STATE_LOST ) { mc_go_home(); } + else { return(STATUS_HOMING_ERROR); } + } else { return(STATUS_SETTING_DISABLED); } break; // case 'J' : break; // Jogging methods // TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be @@ -164,41 +182,62 @@ uint8_t protocol_execute_line(char *line) // handled by the planner. It would be possible for the jog subprogram to insert blocks into the // block buffer without having the planner plan them. It would need to manage de/ac-celerations // on its own carefully. This approach could be effective and possibly size/memory efficient. -// case 'N' : // Start up blocks -// if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } -// if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } -// // Extract startup block, execute, and store. -// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) { -// line[char_counter] = line[char_counter+3]; -// } -// uint8_t status = gc_execute_line(line); -// if (status) { return(status); } -// else { settings_store_startup_block(line); } -// break; - case 'B' : // Toggle block delete - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - sys.switches ^= BITFLAG_BLOCK_DELETE; - if (bit_istrue(sys.switches,BITFLAG_BLOCK_DELETE)) { report_feedback_message(MESSAGE_SWITCH_ON); } - else { report_feedback_message(MESSAGE_SWITCH_OFF); } + case 'S' : // Switch modes + // Set helper_var as switch bitmask or clearing flag + switch (line[++char_counter]) { + case 0 : helper_var = 0; break; + case '0' : helper_var = BITFLAG_CHECK_GCODE; break; + case '1' : helper_var = BITFLAG_DRY_RUN; break; + case '2' : helper_var = BITFLAG_BLOCK_DELETE; break; + case '3' : helper_var = BITFLAG_SINGLE_BLOCK; break; + case '4' : helper_var = BITFLAG_OPT_STOP; break; + default : return(STATUS_INVALID_STATEMENT); + } + if (helper_var) { + if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } + gc.switches ^= helper_var; + if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_SWITCH_ON); } + else { report_feedback_message(MESSAGE_SWITCH_OFF); } + } else { + gc.switches = helper_var; // Clear all switches + report_feedback_message(MESSAGE_SWITCHES_CLEARED); + } break; - case 'S' : // Toggle single block mode - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - sys.switches ^= BITFLAG_SINGLE_BLOCK; - if (bit_istrue(sys.switches,BITFLAG_SINGLE_BLOCK)) { report_feedback_message(MESSAGE_SWITCH_ON); } - else { report_feedback_message(MESSAGE_SWITCH_OFF); } - break; - case 'O' : // Toggle optional stop - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - sys.switches ^= BITFLAG_OPT_STOP; - if (bit_istrue(sys.switches,BITFLAG_OPT_STOP)) { report_feedback_message(MESSAGE_SWITCH_ON); } - else { report_feedback_message(MESSAGE_SWITCH_OFF); } - break; - default : // Store global setting + case 'N' : // Startup lines. + if ( line[++char_counter] == 0 ) { // Print startup lines + for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { + if (!(settings_read_startup_line(helper_var, line))) { + report_status_message(STATUS_SETTING_READ_FAIL); + } else { + report_startup_line(helper_var,line); + } + } + break; + } else { // Store startup line + helper_var = true; // Set helper_var to flag storing method. + // No break. Continues into default: to read remaining command characters. + } + default : // Storing setting methods if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } - if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } - if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } - return(settings_store_global_setting(parameter, value)); + if (helper_var) { // Store startup line + // Prepare sending gcode block to gcode parser by shifting all characters + helper_var = char_counter; // Set helper variable as counter to start of gcode block + do { + line[char_counter-helper_var] = line[char_counter]; + } while (line[char_counter++] != 0); + // Execute gcode block to ensure block is valid. + helper_var = gc_execute_line(line); // Set helper_var to returned status code. + if (helper_var) { return(helper_var); } + else { + helper_var = trunc(parameter); // Set helper_var to int value of parameter + settings_store_startup_line(helper_var,line); + } + } else { // Store global setting. + if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } + if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } + return(settings_store_global_setting(parameter, value)); + } } return(STATUS_OK); // If '$' command makes it to here, then everything's ok. @@ -249,7 +288,7 @@ void protocol_process() // Throw away whitepace and control characters } else if (c == '/') { // Disable block delete and throw away characters. Will ignore until EOL. - if (bit_istrue(sys.switches,BITFLAG_BLOCK_DELETE)) { + if (bit_istrue(gc.switches,BITFLAG_BLOCK_DELETE)) { iscomment = true; } } else if (c == '(') { diff --git a/protocol.h b/protocol.h index f176fd5..83c4c0d 100755 --- a/protocol.h +++ b/protocol.h @@ -21,6 +21,8 @@ #ifndef protocol_h #define protocol_h +#include + // Line buffer size from the serial input stream to be executed. // NOTE: Not a problem except for extreme cases, but the line buffer size can be too small // and g-code blocks can get truncated. Officially, the g-code standards support up to 256 @@ -42,4 +44,7 @@ uint8_t protocol_execute_line(char *line); // Checks and executes a runtime command at various stop points in main program void protocol_execute_runtime(); +// Execute the startup script lines stored in EEPROM upon initialization +void protocol_execute_startup(); + #endif diff --git a/readme.textile b/readme.textile index 3c5fde6..2acf3e8 100755 --- a/readme.textile +++ b/readme.textile @@ -9,25 +9,26 @@ It accepts standards-compliant G-code and has been tested with the output of sev Grbl includes full acceleration management with look ahead. That means the controller will look up to 18 motions into the future and plan its velocities ahead to deliver smooth acceleration and jerk-free cornering. *Changelog for v0.8 from v0.7:* - - *BETA status: _Under development. Code state may significantly change with each push as new features are integrated._* - - Major structural overhaul to allow for multi-tasking events and new feature sets - - New run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting + - *BETA status: _Under development but nearing completion. Code state may change with each push as new features are integrated or when bugs are squashed._* + - Major structural overhaul to allow for multi-tasking events and new feature sets. + - Run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting - Controlled feed hold with deceleration to ensure no skipped steps and loss of location. - After feed hold, cycle accelerations are re-planned and may be resumed. - - Advanced homing cycle with direction and speed configuration options. (Requires limit switches.) - - Limit pins are held normal high with an internal pull-up resister. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.) + - Advanced homing cycle with direction and speed configuration options. (Requires limit switches.) When enabled, homing is required before use to ensure safety. + - Limit pins are held normal high with internal pull-up resistors. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.) - Hard limits option and plays nice with homing cycle, so switches can be used for both homing and hard limits. + - New switch commands: Dry-run, block delete, single block mode, optional stop. A check g-code switch has also been added to allow users to error check their programs. This feature can also be used as a "program restart" by enabling the check g-code switch, begin streaming, and disable the check g-code switch at the desired point with minimal additional g-code. - Re-factored g-code parser with robust error-checking. - - 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work systems are stored in EEPROM and persistent. + - 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work coordinate systems are stored in EEPROM and persistent. - G10 L2 and L20 work coordinate settings support. L2 sets one or more axes values. L20 sets the current machine position to the specified work origin. - - Program stop(M0,M1*,M2,M30) initial support. Optional stop to do. + - Program stop(M0,M1,M2,M30) initial support. - Coolant control(M7*,M8,M9) support. (M7 is a compile-time option). - System reset re-initializes grbl without resetting the Arduino and retains machine/home position and work coordinates. - - Restructured planner and stepper modules to become independent and ready for future features. - - Settings re-factoring to allow configuration without compiling of most features. (Still in progress). + - Settings overhauled and dozens of new settings and internal commands are now available, when most were compile-time only. + - New startup line setting. Allows users to store a custom g-code block into Grbl's startup routine. Executes immediately upon startup or reset. May be used to set g-code defaults like G20. - Misc bug fixes and removed deprecated acceleration enabled code. - - Planned features: Axis acceleration and max speed individual settings, full-featured status reporting, runtime settings such as toggling block delete. - - Advanced compile-time options: Up to 6 work coordinate systems(G54-G59), XON/XOFF flow control (limited support), direction and step pulse time delay. + - Planned features: Axis acceleration and max speed individual settings, full-featured status reporting. + - Advanced compile-time options: XON/XOFF flow control (limited support), direction and step pulse time delay, and up to 5 startup lines. *Important note for Atmega 168 users:* Going forward, support for Atmega 168 will be dropped due to its limited memory and speed. However, legacy Grbl v0.51 "in the branch called 'v0_51' is still available for use. diff --git a/report.c b/report.c index 2383695..a036820 100644 --- a/report.c +++ b/report.c @@ -26,14 +26,11 @@ methods to accomodate their needs. */ -#include -#include "print.h" -#include "settings.h" -#include -#include "nuts_bolts.h" #include #include "report.h" -#include "protocol.h" +#include "print.h" +#include "settings.h" +#include "nuts_bolts.h" #include "gcode.h" #include "coolant_control.h" @@ -75,6 +72,10 @@ void report_status_message(uint8_t status_code) printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break; case STATUS_SETTING_READ_FAIL: printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break; + case STATUS_HOMING_ERROR: + printPgmString(PSTR("Grbl must be idle to home")); break; + case STATUS_ABORT_CYCLE: + printPgmString(PSTR("Abort during cycle")); break; } printPgmString(PSTR("\r\n")); } @@ -84,78 +85,91 @@ void report_status_message(uint8_t status_code) // Prints feedback messages. This serves as a centralized method to provide additional // user feedback for things that are not of the status message response protocol. These // are messages such as setup warnings and how to exit alarms. -// NOTE: For interfaces, messages are always placed within chevrons. And if silent mode +// NOTE: For interfaces, messages are always placed within brackets. And if silent mode // is installed, the message number codes are less than zero. // TODO: Install silence feedback messages option in settings void report_feedback_message(int8_t message_code) { - printPgmString(PSTR("<")); + printPgmString(PSTR("[")); switch(message_code) { case MESSAGE_SYSTEM_ALARM: printPgmString(PSTR("ALARM: Check and reset Grbl")); break; case MESSAGE_POSITION_LOST: - printPgmString(PSTR("warning: Position may be lost")); break; + printPgmString(PSTR("Position unknown. '$H' to home")); break; case MESSAGE_HOMING_ENABLE: - printPgmString(PSTR("'$H' to home. Ensure all limit switches are installed")); break; + printPgmString(PSTR("WARNING: All limit switches must be installed before homing")); break; case MESSAGE_SWITCH_ON: printPgmString(PSTR("Switch enabled")); break; case MESSAGE_SWITCH_OFF: printPgmString(PSTR("Switch disabled")); break; + case MESSAGE_SWITCHES_CLEARED: + printPgmString(PSTR("Switches cleared")); break; } - printPgmString(PSTR(">\r\n")); + printPgmString(PSTR("]\r\n")); } + // Welcome message void report_init_message() { printPgmString(PSTR("\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n")); } - +// Grbl help message void report_grbl_help() { -// char st_line[LINE_BUFFER_SIZE]; -// printPgmString(PSTR("\r\n\r\n Startup\r\n$100 = ")); printString(settings_read_startup(st_line,0)); -// printPgmString(PSTR("\r\n$101 = ")); printString(settings_read_startup(st_line,1)); - -// char buf[4]; -// settings_startup_string((char *)buf); -// printPgmString(PSTR("\r\n Startup: ")); printString(buf); - - printPgmString(PSTR("$ (help)\r\n$$ (print Grbl settings)\r\n$# (print gcode parameters)\r\n$G (print gcode parser state)")); - printPgmString(PSTR("\r\n$x=value (store Grbl setting)\r\n$Nx=line (store startup block)\r\n$H (run homing cycle, if enabled)")); - printPgmString(PSTR("\r\n$B (toggle block delete)\r\n$S (toggle single block mode)\r\n$O (toggle opt stop)")); - printPgmString(PSTR("\r\n~ (cycle start)\r\n! (feed hold)\r\n? (current position)\r\n^x (reset Grbl)\r\n")); + printPgmString(PSTR("$ (help)\r\n" + "$$ (print Grbl settings)\r\n" + "$# (print gcode parameters)\r\n" + "$G (print gcode parser state)\r\n" + "$N (print startup blocks)\r\n" + "$x=value (store Grbl setting)\r\n" + "$Nx=line (store startup block)\r\n" + "$H (perform homing cycle)\r\n" + "$S (clear all switches)\r\n" + "$S0 (toggle check gcode)\r\n" + "$S1 (toggle dry run)\r\n" + "$S2 (toggle block delete)\r\n" + "$S3 (toggle single block)\r\n" + "$S4 (toggle optional stop)\r\n" + "~ (cycle start)\r\n" + "! (feed hold)\r\n" + "? (current position)\r\n" + "^x (reset Grbl)\r\n")); } +// Grbl global settings print out. +// NOTE: The numbering scheme here must correlate to storing in settings.c void report_grbl_settings() { - printPgmString(PSTR("$0 = ")); printFloat(settings.steps_per_mm[X_AXIS]); - printPgmString(PSTR(" (x axis, steps/mm)\r\n$1 = ")); printFloat(settings.steps_per_mm[Y_AXIS]); - printPgmString(PSTR(" (y axis, steps/mm)\r\n$2 = ")); printFloat(settings.steps_per_mm[Z_AXIS]); - printPgmString(PSTR(" (z axis, steps/mm)\r\n$3 = ")); printInteger(settings.pulse_microseconds); - printPgmString(PSTR(" (step pulse, usec)\r\n$4 = ")); printFloat(settings.default_feed_rate); - printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5 = ")); printFloat(settings.default_seek_rate); - printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6 = ")); printFloat(settings.mm_per_arc_segment); - printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7 = ")); printInteger(settings.invert_mask); - printPgmString(PSTR(" (step port invert mask, int:binary = ")); print_uint8_base2(settings.invert_mask); - printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability - printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation); - printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); - printPgmString(PSTR(" (status report inches, bool)\r\n$11 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); - printPgmString(PSTR(" (auto start enable, bool)\r\n$12 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); - printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); - printPgmString(PSTR(" (hard limit enable, bool)\r\n$14 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); - printPgmString(PSTR(" (homing enable, bool)\r\n$15 = ")); printInteger(settings.homing_dir_mask); - printPgmString(PSTR(" (homing direction mask, int:binary = ")); print_uint8_base2(settings.homing_dir_mask); - printPgmString(PSTR(")\r\n$16 = ")); printFloat(settings.homing_feed_rate); - printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17 = ")); printFloat(settings.homing_seek_rate); - printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18 = ")); printInteger(settings.homing_debounce_delay); - printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19 = ")); printFloat(settings.homing_pulloff); - printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20 = ")); printInteger(settings.stepper_idle_lock_time); - printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21 = ")); printInteger(settings.decimal_places); - printPgmString(PSTR(" (decimal places, int)\r\n$22 = ")); printInteger(settings.n_arc_correction); + printPgmString(PSTR("$0=")); printFloat(settings.steps_per_mm[X_AXIS]); + printPgmString(PSTR(" (x axis, steps/mm)\r\n$1=")); printFloat(settings.steps_per_mm[Y_AXIS]); + printPgmString(PSTR(" (y axis, steps/mm)\r\n$2=")); printFloat(settings.steps_per_mm[Z_AXIS]); + printPgmString(PSTR(" (z axis, steps/mm)\r\n$3=")); printInteger(settings.pulse_microseconds); + printPgmString(PSTR(" (step pulse, usec)\r\n$4=")); printFloat(settings.default_feed_rate); + printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5=")); printFloat(settings.default_seek_rate); + printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6=")); printFloat(settings.mm_per_arc_segment); + printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7=")); printInteger(settings.invert_mask); + printPgmString(PSTR(" (step port invert mask, int:binary=")); print_uint8_base2(settings.invert_mask); + printPgmString(PSTR(")\r\n$8=")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability + printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9=")); printFloat(settings.junction_deviation); + printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); + printPgmString(PSTR(" (report inches, bool)\r\n$11=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START)); + printPgmString(PSTR(" (auto start enable, bool)\r\n$12=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); + printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); + printPgmString(PSTR(" (hard limit enable, bool)\r\n$14=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); + printPgmString(PSTR(" (homing enable, bool)\r\n$15=")); printInteger(settings.homing_dir_mask); + printPgmString(PSTR(" (homing dir invert mask, int:binary=")); print_uint8_base2(settings.homing_dir_mask); + printPgmString(PSTR(")\r\n$16=")); printFloat(settings.homing_feed_rate); + printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17=")); printFloat(settings.homing_seek_rate); + printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18=")); printInteger(settings.homing_debounce_delay); + printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19=")); printFloat(settings.homing_pulloff); + printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20=")); printInteger(settings.stepper_idle_lock_time); + printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21=")); printInteger(settings.decimal_places); + printPgmString(PSTR(" (decimal places, int)\r\n$22=")); printInteger(settings.n_arc_correction); printPgmString(PSTR(" (n arc correction, int)\r\n")); } + +// Prints gcode coordinate offset parameters void report_gcode_parameters() { float coord_data[N_AXIS]; @@ -174,7 +188,7 @@ void report_gcode_parameters() case 5: printPgmString(PSTR("G59")); break; case 6: printPgmString(PSTR("G28")); break; case 7: printPgmString(PSTR("G30")); break; - // case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 currently not supported. + // case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 not supported. Hence not stored. } printPgmString(PSTR(":[")); for (i=0; i -#include #include "serial.h" #include "config.h" #include "motion_control.h" -#include "nuts_bolts.h" #include "protocol.h" -#define RX_BUFFER_SIZE 128 -#define TX_BUFFER_SIZE 64 - uint8_t rx_buffer[RX_BUFFER_SIZE]; uint8_t rx_buffer_head = 0; uint8_t rx_buffer_tail = 0; @@ -42,14 +37,6 @@ uint8_t tx_buffer_head = 0; volatile uint8_t tx_buffer_tail = 0; #ifdef ENABLE_XONXOFF - #define RX_BUFFER_FULL 96 // XOFF high watermark - #define RX_BUFFER_LOW 64 // XON low watermark - #define SEND_XOFF 1 - #define SEND_XON 2 - #define XOFF_SENT 3 - #define XON_SENT 4 - #define XOFF_CHAR 0x13 - #define XON_CHAR 0x11 volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable // Returns the number of bytes in the RX buffer. This replaces a typical byte counter to prevent diff --git a/serial.h b/serial.h index 3e1cc77..3ea56c0 100755 --- a/serial.h +++ b/serial.h @@ -25,8 +25,23 @@ #ifndef serial_h #define serial_h +#include "nuts_bolts.h" + +#define RX_BUFFER_SIZE 128 +#define TX_BUFFER_SIZE 64 #define SERIAL_NO_DATA 0xff +#ifdef ENABLE_XONXOFF + #define RX_BUFFER_FULL 96 // XOFF high watermark + #define RX_BUFFER_LOW 64 // XON low watermark + #define SEND_XOFF 1 + #define SEND_XON 2 + #define XOFF_SENT 3 + #define XON_SENT 4 + #define XOFF_CHAR 0x13 + #define XON_CHAR 0x11 +#endif + void serial_init(long baud); void serial_write(uint8_t data); diff --git a/settings.c b/settings.c index a2e02d1..1deb732 100644 --- a/settings.c +++ b/settings.c @@ -20,15 +20,12 @@ */ #include -#include +#include "protocol.h" +#include "report.h" +#include "stepper.h" #include "nuts_bolts.h" #include "settings.h" #include "eeprom.h" -#include "print.h" -#include -#include "protocol.h" -#include "config.h" -#include "report.h" settings_t settings; @@ -45,49 +42,29 @@ typedef struct { float junction_deviation; } settings_v4_t; -// Default settings (used when resetting eeprom-settings) -#define MICROSTEPS 8 -#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS) -#define DEFAULT_STEP_PULSE_MICROSECONDS 30 -#define DEFAULT_MM_PER_ARC_SEGMENT 0.1 -#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min -#define DEFAULT_FEEDRATE 500.0 -#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2 -#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm -#define DEFAULT_STEPPING_INVERT_MASK ((1< -#include #include "nuts_bolts.h" #define GRBL_VERSION "0.8c" @@ -45,7 +44,7 @@ // developments. #define EEPROM_ADDR_GLOBAL 1 #define EEPROM_ADDR_PARAMETERS 512 -#define EEPROM_ADDR_STARTUP_SCRIPT 768 +#define EEPROM_ADDR_STARTUP_BLOCK 768 // Define EEPROM address indexing for coordinate parameters #define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1) @@ -85,12 +84,16 @@ void settings_init(); // A helper method to set new settings from command line uint8_t settings_store_global_setting(int parameter, float value); +// Stores the protocol line variable as a startup line in EEPROM +void settings_store_startup_line(uint8_t n, char *line); + +// Reads an EEPROM startup line to the protocol line variable +uint8_t settings_read_startup_line(uint8_t n, char *line); + // Writes selected coordinate data to EEPROM void settings_write_coord_data(uint8_t coord_select, float *coord_data); // Reads selected coordinate data from EEPROM uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data); -// int8_t settings_execute_startup(); - #endif diff --git a/spindle_control.c b/spindle_control.c index 1d65f41..5bfe621 100755 --- a/spindle_control.c +++ b/spindle_control.c @@ -19,14 +19,9 @@ along with Grbl. If not, see . */ -#include "spindle_control.h" #include "settings.h" -#include "motion_control.h" -#include "config.h" +#include "spindle_control.h" #include "planner.h" -#include "stepper.h" - -#include static uint8_t current_direction; diff --git a/stepper.c b/stepper.c index 97e6e4b..56350cc 100755 --- a/stepper.c +++ b/stepper.c @@ -22,19 +22,12 @@ /* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith and Philipp Tiefenbacher. */ +#include #include "stepper.h" #include "config.h" #include "settings.h" -#include -#include -#include -#include "nuts_bolts.h" -#include #include "planner.h" -// Some useful constants -#define TICKS_PER_MICROSECOND (F_CPU/1000000) -#define CYCLES_PER_ACCELERATION_TICK ((TICKS_PER_MICROSECOND*1000000)/ACCELERATION_TICKS_PER_SECOND) // Stepper state variable. Contains running data and trapezoid variables. typedef struct { @@ -94,7 +87,7 @@ void st_wake_up() } else { STEPPERS_DISABLE_PORT &= ~(1<initial_rate; set_step_events_per_minute(st.trapezoid_adjusted_rate); // Initialize cycles_per_step_event @@ -190,7 +183,6 @@ ISR(TIMER1_COMPA_vect) st.step_events_completed = 0; } else { st_go_idle(); - sys.cycle_start = false; bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program for cycle end } } @@ -224,7 +216,7 @@ ISR(TIMER1_COMPA_vect) // While in block steps, check for de/ac-celeration events and execute them accordingly. if (st.step_events_completed < current_block->step_event_count) { - if (sys.feed_hold) { + if (sys.state == STATE_HOLD) { // Check for and execute feed hold by enforcing a steady deceleration from the moment of // execution. The rate of deceleration is limited by rate_delta and will never decelerate // faster or slower than in normal operation. If the distance required for the feed hold @@ -240,7 +232,6 @@ ISR(TIMER1_COMPA_vect) // remain intact to ensure the stepper path is exactly the same. Feed hold is still // active and is released after the buffer has been reinitialized. st_go_idle(); - sys.cycle_start = false; bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program that feed hold is complete. } else { st.trapezoid_adjusted_rate -= current_block->rate_delta; @@ -430,24 +421,18 @@ static void set_step_events_per_minute(uint32_t steps_per_minute) // variable will manage all of Grbl's processes and keep them separate. void st_cycle_start() { - if (!sys.cycle_start) { - if (!sys.feed_hold) { - if (bit_isfalse(sys.execute,EXEC_ALARM)) { - sys.cycle_start = true; // Only place this variable is set true. - st_wake_up(); - } - } + if (sys.state == STATE_QUEUED) { + sys.state = STATE_CYCLE; + st_wake_up(); } } // Execute a feed hold with deceleration, only during cycle. Called by main program. void st_feed_hold() { - if (!sys.feed_hold) { - if (sys.cycle_start) { - sys.auto_start = false; // Disable planner auto start upon feed hold. - sys.feed_hold = true; - } + if (sys.state == STATE_CYCLE) { + sys.state = STATE_HOLD; + sys.auto_start = false; // Disable planner auto start upon feed hold. } } @@ -466,6 +451,8 @@ void st_cycle_reinitialize() set_step_events_per_minute(st.trapezoid_adjusted_rate); st.trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule. st.step_events_completed = 0; + sys.state = STATE_QUEUED; + } else { + sys.state = STATE_IDLE; } - sys.feed_hold = false; // Release feed hold. Cycle is ready to re-start. } diff --git a/stepper.h b/stepper.h index 1c7977a..a72546f 100755 --- a/stepper.h +++ b/stepper.h @@ -23,7 +23,6 @@ #define stepper_h #include -#include // Some useful constants #define STEP_MASK ((1<