diff --git a/config.h b/config.h
index 211c34b..6fe5620 100755
--- a/config.h
+++ b/config.h
@@ -69,9 +69,9 @@
#define COOLANT_FLOOD_PORT PORTC
#define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3
-// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
// a later date if flash and memory space allows.
+// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
#ifdef ENABLE_M7
#define COOLANT_MIST_DDR DDRC
#define COOLANT_MIST_PORT PORTC
@@ -158,6 +158,18 @@
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
+// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
+// the user to perform the homing cycle (or override the locks) before doing anything else. This is
+// mainly a safety feature to remind the user to home, since position is unknown to Grbl.
+#define HOMING_INIT_LOCK // Comment to disable
+
+// The homing cycle seek and feed rates will adjust so all axes independently move at the homing
+// seek and feed rates regardless of how many axes are in motion simultaneously. If disabled, rates
+// are point-to-point rates, as done in normal operation. For example in an XY diagonal motion, the
+// diagonal motion moves at the intended rate, but the individual axes move at 70% speed. This option
+// just moves them all at 100% speed.
+#define HOMING_RATE_ADJUST // Comment to disable
+
// Number of homing cycles performed after when the machine initially jogs to limit switches.
// This help in preventing overshoot and should improve repeatability. This value should be one or
// greater.
@@ -167,7 +179,7 @@
// and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may
// be stored and executed in order. These startup blocks would typically be used to set the g-code
// parser state depending on user preferences.
-#define N_STARTUP_LINE 3 // Integer (1-5)
+#define N_STARTUP_LINE 2 // Integer (1-5)
// ---------------------------------------------------------------------------------------
// FOR ADVANCED USERS ONLY:
diff --git a/gcode.c b/gcode.c
index 029e022..9f145a2 100755
--- a/gcode.c
+++ b/gcode.c
@@ -84,6 +84,11 @@ static float to_millimeters(float value)
// internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively.
uint8_t gc_execute_line(char *line)
{
+
+ // If in alarm state, don't process. Immediately return with error.
+ // NOTE: Might not be right place for this, but also prevents $N storing during alarm.
+ if (sys.state == STATE_ALARM) { return(STATUS_ALARM_LOCK); }
+
uint8_t char_counter = 0;
char letter;
float value;
@@ -545,7 +550,7 @@ uint8_t gc_execute_line(char *line)
// If complete, reset to reload defaults (G92.2,G54,G17,G90,G94,M48,G40,M5,M9). Otherwise,
// re-enable program flow after pause complete, where cycle start will resume the program.
- if (gc.program_flow == PROGRAM_FLOW_COMPLETED) { sys.execute |= EXEC_RESET; }
+ if (gc.program_flow == PROGRAM_FLOW_COMPLETED) { mc_reset(); }
else { gc.program_flow = PROGRAM_FLOW_RUNNING; }
}
diff --git a/limits.c b/limits.c
index bc0cf40..2548cd4 100755
--- a/limits.c
+++ b/limits.c
@@ -41,30 +41,41 @@ void limits_init()
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
- LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
- PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
+ LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
+ PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
+ } else {
+ LIMIT_PCMSK &= ~LIMIT_MASK; // Disable
+ PCICR &= ~(1 << LIMIT_INT);
}
}
-// This is the Limit Pin Change Interrupt, which handles the hard limit feature.
+// This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing
+// limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
+// If a switch is triggered at all, something bad has happened and treat it as such, regardless
+// if a limit switch is being disengaged. It's impossible to reliably tell the state of a
+// bouncing pin without a debouncing method.
// NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during
// homing cycles and will not respond correctly. Upon user request or need, there may be a
// special pinout for an e-stop, but it is generally recommended to just directly connect
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
-// TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
-// interrupt without adding too much to it. All it would need is some way to stop one axis
-// when its limit is triggered and continue the others. This may reduce some of the code, but
-// would make Grbl a little harder to read and understand down road. Holding off on this until
-// we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
ISR(LIMIT_INT_vect)
{
- // Only enter if the system alarm is not active.
- if (bit_isfalse(sys.execute,EXEC_ALARM)) {
- // Kill all processes upon hard limit event.
- if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
- mc_alarm(); // Initiate system kill.
- sys.state = STATE_LIMIT; // Set system state to indicate event.
- }
+ // TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
+ // interrupt without adding too much to it. All it would need is some way to stop one axis
+ // when its limit is triggered and continue the others. This may reduce some of the code, but
+ // would make Grbl a little harder to read and understand down road. Holding off on this until
+ // we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
+
+ // Ignore limit switches if already in an alarm state or in-process of executing an alarm.
+ // When in the alarm state, Grbl should have been reset or will force a reset, so any pending
+ // moves in the planner and serial buffers are all cleared and newly sent blocks will be
+ // locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
+ // limit setting if their limits are constantly triggering after a reset and move their axes.
+ if (sys.state != STATE_ALARM) {
+ if (bit_isfalse(sys.execute,EXEC_ALARM)) {
+ mc_reset(); // Initiate system kill.
+ sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
+ }
}
}
@@ -104,6 +115,11 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
// Compute the adjusted step rate change with each acceleration tick. (in step/min/acceleration_tick)
uint32_t delta_rate = ceil( ds*settings.acceleration/(60*ACCELERATION_TICKS_PER_SECOND));
+ #ifdef HOMING_RATE_ADJUST
+ // Adjust homing rate so a multiple axes moves all at the homing rate independently.
+ homing_rate *= sqrt(x_axis+y_axis+z_axis);
+ #endif
+
// Nominal and initial time increment per step. Nominal should always be greater then 3
// usec, since they are based on the same parameters as the main stepper routine. Initial
// is based on the MINIMUM_STEPS_PER_MINUTE config. Since homing feed can be very slow,
@@ -191,12 +207,13 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
void limits_go_home()
{
- // Enable only the steppers, not the cycle. Cycle should be complete.
+ // Enable only the steppers, not the cycle. Cycle should be inactive/complete.
st_wake_up();
// Jog all axes toward home to engage their limit switches at faster homing seek rate.
- homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // First jog the z axis
- homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // Then jog the x and y axis
+ // First jog z-axis to clear workspace, then jog the x and y axis.
+ homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // z-axis
+ homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // xy-axes
delay_ms(settings.homing_debounce_delay); // Delay to debounce signal
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles
diff --git a/main.c b/main.c
index 9174d52..c03735f 100755
--- a/main.c
+++ b/main.c
@@ -45,14 +45,14 @@ system_t sys;
int main(void)
{
// Initialize system
- serial_init(BAUD_RATE); // Setup serial baud rate and interrupts
+ serial_init(); // Setup serial baud rate and interrupts
settings_init(); // Load grbl settings from EEPROM
st_init(); // Setup stepper pins and interrupt timers
sei(); // Enable interrupts
memset(&sys, 0, sizeof(sys)); // Clear all system variables
sys.abort = true; // Set abort to complete initialization
- sys.state = STATE_ALARM; // Set alarm state to indicate unknown initial position
+ sys.state = STATE_INIT; // Set alarm state to indicate unknown initial position
for(;;) {
@@ -60,7 +60,6 @@ int main(void)
// Once here, it is safe to re-initialize the system. At startup, the system will automatically
// reset to finish the initialization process.
if (sys.abort) {
-
// Reset system.
serial_reset_read_buffer(); // Clear serial read buffer
plan_init(); // Clear block buffer and planner variables
@@ -72,28 +71,33 @@ int main(void)
st_reset(); // Clear stepper subsystem variables.
// Sync cleared gcode and planner positions to current system position, which is only
- // cleared upon startup, not a reset/abort. If Grbl does not know or can ensure its
- // position, a feedback message will be sent back to the user to let them know. Also,
- // if position is lost and homing is enabled, the axes motions will be locked, and
- // user must either perform the homing cycle '$H' or purge the system locks '$P' to
- // resume.
+ // cleared upon startup, not a reset/abort.
sys_sync_current_position();
// Reset system variables.
sys.abort = false;
sys.execute = 0;
- if (sys.state == STATE_ALARM && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
- // Position has either been lost from a critical event or a power cycle reboot. If
- // homing is enabled, force user to home to get machine position. Otherwise, let the
- // user manage position on their own.
- report_feedback_message(MESSAGE_HOMING_ALARM);
- } else {
- sys.state = STATE_IDLE;
- }
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
-
- // Execute user startup script
- protocol_execute_startup();
+
+ // Check for power-up and set system alarm if homing is enabled to force homing cycle
+ // by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
+ // startup scripts, but allows access to settings and internal commands. Only a homing
+ // cycle '$H' or kill alarm locks '$X' will disable the alarm.
+ // NOTE: The startup script will run after successful completion of the homing cycle, but
+ // not after disabling the alarm locks. Prevents motion startup blocks from crashing into
+ // things uncontrollably. Very bad.
+ #ifdef HOMING_INIT_LOCK
+ if (sys.state == STATE_INIT && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; }
+ #endif
+
+ // Check for and report alarm state after a reset, error, or an initial power up.
+ if (sys.state == STATE_ALARM) {
+ report_feedback_message(MESSAGE_ALARM_LOCK);
+ } else {
+ // All systems go. Set system to ready and execute startup script.
+ sys.state = STATE_IDLE;
+ protocol_execute_startup();
+ }
}
protocol_execute_runtime();
diff --git a/motion_control.c b/motion_control.c
index c80e557..6cc000f 100755
--- a/motion_control.c
+++ b/motion_control.c
@@ -67,10 +67,8 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat
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 idle, indicate to the system there is now a planned block in the buffer ready to cycle
+ // start. Otherwise ignore and continue on.
if (!sys.state) { sys.state = STATE_QUEUED; }
// Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
@@ -214,13 +212,10 @@ void mc_dwell(float seconds)
void mc_go_home()
{
sys.state = STATE_HOMING; // Set system state variable
- PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt
+ LIMIT_PCMSK &= ~LIMIT_MASK; // Disable hard limits pin change register for cycle duration
limits_go_home(); // Perform homing routine.
- if (sys.abort) {
- sys.state = STATE_ALARM; // Homing routine did not complete.
- return;
- }
+ if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
// The machine should now be homed and machine zero has been located. Upon completion,
// reset system position and sync internal position vectors.
@@ -237,32 +232,42 @@ void mc_go_home()
if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = 1; }
mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
- z_dir*settings.homing_pulloff, settings.homing_feed_rate, false);
+ z_dir*settings.homing_pulloff, settings.homing_seek_rate, false);
st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes.
// The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors.
sys_sync_current_position();
- // 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); }
+ // If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
+ if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { LIMIT_PCMSK |= LIMIT_MASK; }
// Finished!
}
-// Method to immediately kill all motion and set system alarm. Used by system abort, hard limits,
-// and upon g-code parser error (when installed).
-void mc_alarm()
+// Method to ready the system to reset by setting the runtime reset command and killing any
+// active processes in the system. This also checks if a system reset is issued while Grbl
+// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
+// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
+// runtime abort command and hard limits. So, keep to a minimum.
+void mc_reset()
{
- // Only this function can set the system alarm. This is done to prevent multiple kill calls
- // by different processes.
- if (bit_isfalse(sys.execute, EXEC_ALARM)) {
- // Set system alarm flag to have the main program check for anything wrong with shutting
- // down the system.
- sys.execute |= EXEC_ALARM;
- // Immediately force stepper, spindle, and coolant to stop.
- st_go_idle();
+ // Only this function can set the system reset. Helps prevent multiple kill calls.
+ if (bit_isfalse(sys.execute, EXEC_RESET)) {
+ sys.execute |= EXEC_RESET;
+
+ // Kill spindle and coolant.
spindle_stop();
coolant_stop();
+
+ // Kill steppers only if in any motion state, i.e. cycle, feed hold, homing, or jogging
+ // NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
+ // the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
+ // violated, by which, all bets are off.
+ switch (sys.state) {
+ case STATE_CYCLE: case STATE_HOLD: case STATE_HOMING: // case STATE_JOG:
+ sys.execute |= EXEC_ALARM; // Execute alarm state.
+ st_go_idle(); // Execute alarm force kills steppers. Position likely lost.
+ }
}
}
diff --git a/motion_control.h b/motion_control.h
index cd35f70..20ecf08 100755
--- a/motion_control.h
+++ b/motion_control.h
@@ -43,7 +43,7 @@ void mc_dwell(float seconds);
// Perform homing cycle to locate machine zero. Requires limit switches.
void mc_go_home();
-// Kills all motion and sets system alarm
-void mc_alarm();
+// Performs system reset. If in motion state, kills all motion and sets system alarm.
+void mc_reset();
#endif
diff --git a/nuts_bolts.c b/nuts_bolts.c
index 921ac9a..a244bfb 100755
--- a/nuts_bolts.c
+++ b/nuts_bolts.c
@@ -140,7 +140,7 @@ void delay_us(uint32_t us)
}
}
-
+// Syncs all internal position vectors to the current system position.
void sys_sync_current_position()
{
plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
diff --git a/nuts_bolts.h b/nuts_bolts.h
index 7b00210..1f588ca 100755
--- a/nuts_bolts.h
+++ b/nuts_bolts.h
@@ -63,31 +63,29 @@
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
-// #define bit(6) // bitmask 01000000
+#define EXEC_CRIT_EVENT bit(6) // bitmask 01000000
// #define bit(7) // bitmask 10000000
// 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 g-code processes and messages position lost
-#define STATE_LIMIT 7 // Used to message hard limit triggered.
+#define STATE_INIT 1 // Initial power up state.
+#define STATE_QUEUED 2 // Indicates buffered blocks, awaiting cycle start.
+#define STATE_CYCLE 3 // Cycle is running
+#define STATE_HOLD 4 // Executing feed hold
+#define STATE_HOMING 5 // Performing homing cycle
+#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes. Allows settings access.
+// #define STATE_JOG 7 // Jogging mode is unique like homing.
// Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
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.
+ int32_t position[N_AXIS]; // 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/protocol.c b/protocol.c
index 8152aa9..9ece210 100755
--- a/protocol.c
+++ b/protocol.c
@@ -74,8 +74,7 @@ ISR(PINOUT_INT_vect)
// Enter only if any pinout pin is actively low.
if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) {
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
- mc_alarm();
- sys.execute |= EXEC_RESET; // Set as true
+ mc_reset();
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
sys.execute |= EXEC_FEED_HOLD;
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) {
@@ -93,36 +92,41 @@ ISR(PINOUT_INT_vect)
// define more computationally-expensive volatile variables. This also provides a controlled way to
// execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override.
-// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted,
-// but may be set by any process, such as a switch pin change interrupt when pinouts are installed.
+// NOTE: The sys.execute variable flags are set by any process, step or serial interrupts, pinouts,
+// limit switches, or the main program.
void protocol_execute_runtime()
{
if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
- // System alarm. Everything has shutdown by either something that has gone wrong or issuing
- // the Grbl soft-reset/abort. Check the system states to report any critical error found.
- // If critical, disable Grbl by entering an infinite loop until system reset/abort.
- // NOTE: The system alarm state is also used to set
- if (rt_exec & EXEC_ALARM) {
- // Limit switch critical event. Lock out Grbl until reset.
- if (sys.state == STATE_LIMIT) {
- report_status_message(STATUS_HARD_LIMIT);
- sys.state = STATE_ALARM;
+ // System alarm. Everything has shutdown by something that has gone severely wrong. Report
+ // the source of the error to the user. If critical, Grbl disables by entering an infinite
+ // loop until system reset/abort.
+ if (rt_exec & (EXEC_ALARM | EXEC_CRIT_EVENT)) {
+ sys.state = STATE_ALARM; // Set system alarm state
+
+ // Critical event. Only hard limit qualifies. Update this as new critical events surface.
+ if (rt_exec & EXEC_CRIT_EVENT) {
+ report_alarm_message(ALARM_HARD_LIMIT);
report_feedback_message(MESSAGE_CRITICAL_EVENT);
- while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
+ bit_false(sys.execute,EXEC_RESET); // Disable any existing reset
+ do {
+ // Nothing. Block EVERYTHING until user issues reset or power cycles. Hard limits
+ // typically occur while unattended or not paying attention. Gives the user time
+ // to do what is needed before resetting, like killing the incoming stream.
+ } while (bit_isfalse(sys.execute,EXEC_RESET));
+
+ // Standard alarm event. Only abort during motion qualifies.
+ } else {
+ // Runtime abort command issued during a cycle, feed hold, or homing cycle. Message the
+ // user that position may have been lost and set alarm state to enable the alarm lockout
+ // to indicate the possible severity of the problem.
+ report_alarm_message(ALARM_ABORT_CYCLE);
}
-
- // Check if a runtime abort command was issued during a cycle. If so, message the user
- // that position may have been lost and set alarm state to force re-homing, if enabled.
- if (sys.state == STATE_CYCLE) {
- report_status_message(STATUS_ABORT_CYCLE);
- sys.state = STATE_ALARM;
- }
- bit_false(sys.execute,EXEC_ALARM);
+ bit_false(sys.execute,(EXEC_ALARM | EXEC_CRIT_EVENT));
}
- // System abort. Steppers have already been force stopped.
+ // Execute system abort.
if (rt_exec & EXEC_RESET) {
sys.abort = true; // Only place this is set true.
return; // Nothing else to do but exit.
@@ -194,8 +198,10 @@ uint8_t protocol_execute_line(char *line)
case 'H' : // Perform homing cycle
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_ALARM ) { mc_go_home(); }
- else { return(STATUS_IDLE_ERROR); }
+ if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) {
+ mc_go_home();
+ if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
+ } else { return(STATUS_IDLE_ERROR); }
} else { return(STATUS_SETTING_DISABLED); }
break;
// case 'J' : break; // Jogging methods
@@ -224,20 +230,19 @@ uint8_t protocol_execute_line(char *line)
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of homing locks. This is mainly to keep things
// simple and consistent.
- if ( bit_istrue(gc.switches,helper_var) ) { sys.execute |= EXEC_RESET; }
+ if ( bit_istrue(gc.switches,helper_var) ) { mc_reset(); }
else if (sys.state) { return(STATUS_IDLE_ERROR); }
}
gc.switches ^= helper_var;
if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); }
else { report_feedback_message(MESSAGE_DISABLED); }
break;
- case 'X' : // Disable homing lock
+ case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
- report_feedback_message(MESSAGE_HOMING_UNLOCK);
+ report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
- } else {
- return(STATUS_SETTING_DISABLED);
+ // Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
case 'N' : // Startup lines.
@@ -279,17 +284,7 @@ uint8_t protocol_execute_line(char *line)
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else {
-
- // If homing is enabled and position is lost, lock out all g-code commands.
- if (sys.state != STATE_ALARM) {
- return(gc_execute_line(line)); // Everything else is gcode
- // TODO: Install option to set system alarm upon any error code received back from the
- // the g-code parser. This is a common safety feature on CNCs to help prevent crashes
- // if the g-code doesn't perform as intended.
- } else {
- return(STATUS_HOMING_LOCK);
- }
-
+ return(gc_execute_line(line)); // Everything else is gcode
}
}
diff --git a/report.c b/report.c
index f5dd4f6..485d240 100644
--- a/report.c
+++ b/report.c
@@ -62,8 +62,6 @@ void report_status_message(uint8_t status_code)
printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break;
- case STATUS_HARD_LIMIT:
- printPgmString(PSTR("Hard limit. MPos lost?")); break;
case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Setting disabled")); break;
case STATUS_SETTING_VALUE_NEG:
@@ -73,37 +71,47 @@ void report_status_message(uint8_t status_code)
case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("EEPROM read fail. Using defaults")); break;
case STATUS_IDLE_ERROR:
- printPgmString(PSTR("Busy or locked")); break;
- case STATUS_ABORT_CYCLE:
- printPgmString(PSTR("Abort during cycle. MPos lost?")); break;
- case STATUS_HOMING_LOCK:
- printPgmString(PSTR("Locked until homed")); break;
+ printPgmString(PSTR("Busy or queued")); break;
+ case STATUS_ALARM_LOCK:
+ printPgmString(PSTR("Alarm lock")); break;
}
printPgmString(PSTR("\r\n"));
}
}
+// Prints alarm messages.
+void report_alarm_message(int8_t alarm_code)
+{
+ printPgmString(PSTR("ALARM: "));
+ switch (alarm_code) {
+ case ALARM_HARD_LIMIT:
+ printPgmString(PSTR("Hard limit")); break;
+ case ALARM_ABORT_CYCLE:
+ printPgmString(PSTR("Abort during cycle")); break;
+ }
+ printPgmString(PSTR(". MPos?\r\n"));
+}
// 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.
+// user feedback for things that are not of the status/alarm message protocol. These are
+// messages such as setup warnings, switch toggling, and how to exit alarms.
// 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)
+void report_feedback_message(uint8_t message_code)
{
printPgmString(PSTR("["));
switch(message_code) {
case MESSAGE_CRITICAL_EVENT:
- printPgmString(PSTR("ALARM: Check and reset")); break;
- case MESSAGE_HOMING_ALARM:
- printPgmString(PSTR("'$H' to home and unlock")); break;
+ printPgmString(PSTR("Reset to continue")); break;
+ case MESSAGE_ALARM_LOCK:
+ printPgmString(PSTR("'$H'|'$X' to unlock")); break;
+ case MESSAGE_ALARM_UNLOCK:
+ printPgmString(PSTR("Caution: Unlocked")); break;
case MESSAGE_ENABLED:
printPgmString(PSTR("Enabled")); break;
case MESSAGE_DISABLED:
printPgmString(PSTR("Disabled")); break;
- case MESSAGE_HOMING_UNLOCK:
- printPgmString(PSTR("Unlocked. MPos lost?")); break;
}
printPgmString(PSTR("]\r\n"));
}
@@ -127,7 +135,7 @@ void report_grbl_help() {
"$S1 (toggle blk del)\r\n"
"$S2 (toggle single blk)\r\n"
"$S3 (toggle opt stop)\r\n"
- "$X (kill homing lock)\r\n"
+ "$X (kill alarm lock)\r\n"
"$H (run homing cycle)\r\n"
"~ (cycle start)\r\n"
"! (feed hold)\r\n"
@@ -287,37 +295,39 @@ void report_startup_line(uint8_t n, char *line)
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status()
{
- // **Under construction** Bare-bones status report. Provides real-time machine position relative to
- // the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). Eventually
- // to be added are distance to go on block, processed block id, and feed rate. Also a settings bitmask
- // for a user to select the desired real-time data.
- uint8_t i;
- int32_t current_position[3]; // Copy current state of the system position variable
- memcpy(current_position,sys.position,sizeof(sys.position));
- float print_position[3];
-
- // Report machine position
- printPgmString(PSTR("MPos:["));
- for (i=0; i<= 2; i++) {
- print_position[i] = current_position[i]/settings.steps_per_mm[i];
- if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
- printFloat(print_position[i]);
- if (i < 2) { printPgmString(PSTR(",")); }
- else { printPgmString(PSTR("]")); }
- }
+ // **Under construction** Bare-bones status report. Provides real-time machine position relative to
+ // the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). Eventually
+ // to be added are distance to go on block, processed block id, and feed rate. Also a settings bitmask
+ // for a user to select the desired real-time data.
+ uint8_t i;
+ int32_t current_position[3]; // Copy current state of the system position variable
+ memcpy(current_position,sys.position,sizeof(sys.position));
+ float print_position[3];
- // Report work position
- printPgmString(PSTR(",WPos:["));
- for (i=0; i<= 2; i++) {
- if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
- print_position[i] -= (gc.coord_system[i]+gc.coord_offset[i])*INCH_PER_MM;
- } else {
- print_position[i] -= gc.coord_system[i]+gc.coord_offset[i];
- }
- printFloat(print_position[i]);
- if (i < 2) { printPgmString(PSTR(",")); }
- else { printPgmString(PSTR("]")); }
- }
-
- printPgmString(PSTR("\r\n"));
+ // TODO: Add Grbl state feedback, i.e. IDLE, RUN, HOLD, HOME, etc.
+
+ // Report machine position
+ printPgmString(PSTR("MPos:["));
+ for (i=0; i<= 2; i++) {
+ print_position[i] = current_position[i]/settings.steps_per_mm[i];
+ if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
+ printFloat(print_position[i]);
+ if (i < 2) { printPgmString(PSTR(",")); }
+ else { printPgmString(PSTR("]")); }
+ }
+
+ // Report work position
+ printPgmString(PSTR(",WPos:["));
+ for (i=0; i<= 2; i++) {
+ if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
+ print_position[i] -= (gc.coord_system[i]+gc.coord_offset[i])*INCH_PER_MM;
+ } else {
+ print_position[i] -= gc.coord_system[i]+gc.coord_offset[i];
+ }
+ printFloat(print_position[i]);
+ if (i < 2) { printPgmString(PSTR(",")); }
+ else { printPgmString(PSTR("]")); }
+ }
+
+ printPgmString(PSTR("\r\n"));
}
diff --git a/report.h b/report.h
index b79e1af..885114f 100644
--- a/report.h
+++ b/report.h
@@ -29,27 +29,32 @@
#define STATUS_ARC_RADIUS_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6
-#define STATUS_HARD_LIMIT 7
-#define STATUS_SETTING_DISABLED 8
-#define STATUS_SETTING_VALUE_NEG 9
-#define STATUS_SETTING_STEP_PULSE_MIN 10
-#define STATUS_SETTING_READ_FAIL 11
-#define STATUS_IDLE_ERROR 12
-#define STATUS_ABORT_CYCLE 13
-#define STATUS_HOMING_LOCK 14
+#define STATUS_SETTING_DISABLED 7
+#define STATUS_SETTING_VALUE_NEG 8
+#define STATUS_SETTING_STEP_PULSE_MIN 9
+#define STATUS_SETTING_READ_FAIL 10
+#define STATUS_IDLE_ERROR 11
+#define STATUS_ALARM_LOCK 12
-// Define Grbl feedback message codes. Less than zero to distinguish message from error.
-#define MESSAGE_CRITICAL_EVENT -1
-#define MESSAGE_HOMING_ALARM -2
-#define MESSAGE_ENABLED -3
-#define MESSAGE_DISABLED -4
-#define MESSAGE_HOMING_UNLOCK -5
+// Define Grbl alarm codes. Less than zero to distinguish alarm error from status error.
+#define ALARM_HARD_LIMIT -1
+#define ALARM_ABORT_CYCLE -2
+
+// Define Grbl feedback message codes.
+#define MESSAGE_CRITICAL_EVENT 1
+#define MESSAGE_ALARM_LOCK 2
+#define MESSAGE_ALARM_UNLOCK 3
+#define MESSAGE_ENABLED 4
+#define MESSAGE_DISABLED 5
// Prints system status messages.
void report_status_message(uint8_t status_code);
+// Prints system alarm messages.
+void report_alarm_message(int8_t alarm_code);
+
// Prints miscellaneous feedback messages.
-void report_feedback_message(int8_t message_code);
+void report_feedback_message(uint8_t message_code);
// Prints welcome message
void report_init_message();
diff --git a/serial.c b/serial.c
index ee22333..69fa717 100755
--- a/serial.c
+++ b/serial.c
@@ -49,19 +49,19 @@ volatile uint8_t tx_buffer_tail = 0;
}
#endif
-static void set_baud_rate(long baud) {
- uint16_t UBRR0_value = ((F_CPU / 16 + baud / 2) / baud - 1);
+void serial_init()
+{
+ // Set baud rate
+ #if BAUD_RATE < 57600
+ uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
+ UCSR0A &= ~(1 << U2X0); // baud doubler off - Only needed on Uno XXX
+ #else
+ uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1)/2;
+ UCSR0A |= (1 << U2X0); // baud doubler on for high baud rates, i.e. 115200
+ #endif
UBRR0H = UBRR0_value >> 8;
UBRR0L = UBRR0_value;
-}
-
-void serial_init(long baud)
-{
- set_baud_rate(baud);
-
- /* baud doubler off - Only needed on Uno XXX */
- UCSR0A &= ~(1 << U2X0);
-
+
// enable rx and tx
UCSR0B |= 1<.
-*/
-
-#include
-#include "protocol.h"
-#include "report.h"
-#include "stepper.h"
-#include "nuts_bolts.h"
-#include "settings.h"
-#include "eeprom.h"
-
-settings_t settings;
-
-// Version 4 outdated settings record
-typedef struct {
- float steps_per_mm[3];
- uint8_t microsteps;
- uint8_t pulse_microseconds;
- float default_feed_rate;
- float default_seek_rate;
- uint8_t invert_mask;
- float mm_per_arc_segment;
- float acceleration;
- float junction_deviation;
-} settings_v4_t;
-
-
-// Method to store startup lines into EEPROM
-void settings_store_startup_line(uint8_t n, char *line)
-{
- uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
- memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
-}
-
-// Method to store coord data parameters into EEPROM
-void settings_write_coord_data(uint8_t coord_select, float *coord_data)
-{
- uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
- memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
-}
-
-// Method to store Grbl global settings struct and version number into EEPROM
-void write_global_settings()
-{
- eeprom_put_char(0, SETTINGS_VERSION);
- memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
-}
-
-// Method to reset Grbl global settings back to defaults.
-void settings_reset(bool reset_all) {
- // Reset all settings or only the migration settings to the new version.
- if (reset_all) {
- settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
- settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
- settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
- settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
- settings.default_feed_rate = DEFAULT_FEEDRATE;
- settings.default_seek_rate = DEFAULT_RAPID_FEEDRATE;
- settings.acceleration = DEFAULT_ACCELERATION;
- settings.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT;
- settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK;
- settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
- }
- // New settings since last version
- settings.flags = 0;
- if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
- if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
- if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
- if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
- if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
- settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
- settings.homing_feed_rate = DEFAULT_HOMING_FEEDRATE;
- settings.homing_seek_rate = DEFAULT_HOMING_RAPID_FEEDRATE;
- settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
- settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
- settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
- settings.decimal_places = DEFAULT_DECIMAL_PLACES;
- settings.n_arc_correction = DEFAULT_N_ARC_CORRECTION;
- write_global_settings();
-}
-
-// Reads startup line from EEPROM. Updated pointed line string data.
-uint8_t settings_read_startup_line(uint8_t n, char *line)
-{
- uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
- if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
- // Reset line with default value
- line[0] = 0;
- settings_store_startup_line(n, line);
- return(false);
- } else {
- return(true);
- }
-}
-
-// Read selected coordinate data from EEPROM. Updates pointed coord_data value.
-uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
-{
- uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
- if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
- // Reset with default zero vector
- clear_vector_float(coord_data);
- settings_write_coord_data(coord_select,coord_data);
- return(false);
- } else {
- return(true);
- }
-}
-
-// Reads Grbl global settings struct from EEPROM.
-uint8_t read_global_settings() {
- // Check version-byte of eeprom
- uint8_t version = eeprom_get_char(0);
-
- if (version == SETTINGS_VERSION) {
- // Read settings-record and check checksum
- if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
- return(false);
- }
- } else {
- if (version <= 4) {
- // Migrate from settings version 4 to current version.
- if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
- return(false);
- }
- settings_reset(false); // Old settings ok. Write new settings only.
- } else {
- return(false);
- }
- }
- return(true);
-}
-
-
-// A helper method to set settings from command line
-uint8_t settings_store_global_setting(int parameter, float value) {
- switch(parameter) {
- case 0: case 1: case 2:
- if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
- settings.steps_per_mm[parameter] = value; break;
- case 3:
- if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
- settings.pulse_microseconds = round(value); break;
- case 4: settings.default_feed_rate = value; break;
- case 5: settings.default_seek_rate = value; break;
- case 6: settings.invert_mask = trunc(value); break;
- case 7: settings.stepper_idle_lock_time = round(value); break;
- case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
- case 9: settings.junction_deviation = fabs(value); break;
- case 10: settings.mm_per_arc_segment = value; break;
- case 11: settings.n_arc_correction = round(value); break;
- case 12: settings.decimal_places = round(value); break;
- case 13:
- if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
- else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
- break;
- case 14: // Reboot to ensure change
- if (value) { settings.flags |= BITFLAG_AUTO_START; }
- else { settings.flags &= ~BITFLAG_AUTO_START; }
- break;
- case 15: // Reboot to ensure change
- if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
- else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
- break;
- case 16: // Reboot to ensure change
- if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
- else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
- break;
- case 17:
- if (value) {
- settings.flags |= BITFLAG_HOMING_ENABLE;
- sys.state = STATE_ALARM;
- report_feedback_message(MESSAGE_HOMING_ALARM);
- } else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
- break;
- case 18: settings.homing_dir_mask = trunc(value); break;
- case 19: settings.homing_feed_rate = value; break;
- case 20: settings.homing_seek_rate = value; break;
- case 21: settings.homing_debounce_delay = round(value); break;
- case 22: settings.homing_pulloff = value; break;
- default:
- return(STATUS_INVALID_STATEMENT);
- }
- write_global_settings();
- return(STATUS_OK);
-}
-
-// Initialize the config subsystem
-void settings_init() {
- if(!read_global_settings()) {
- report_status_message(STATUS_SETTING_READ_FAIL);
- settings_reset(true);
- report_grbl_settings();
- }
- // Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing.
- float coord_data[N_AXIS];
- uint8_t i;
- for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
- if (!settings_read_coord_data(i, coord_data)) {
- report_status_message(STATUS_SETTING_READ_FAIL);
- }
- }
- // NOTE: Startup lines are handled and called by main.c at the end of initialization.
-}
+/*
+ settings.c - eeprom configuration handling
+ Part of Grbl
+
+ Copyright (c) 2009-2011 Simen Svale Skogsrud
+ Copyright (c) 2011-2012 Sungeun K. Jeon
+
+ Grbl is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Grbl is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grbl. If not, see .
+*/
+
+#include
+#include "protocol.h"
+#include "report.h"
+#include "stepper.h"
+#include "nuts_bolts.h"
+#include "settings.h"
+#include "eeprom.h"
+#include "limits.h"
+
+settings_t settings;
+
+// Version 4 outdated settings record
+typedef struct {
+ float steps_per_mm[3];
+ uint8_t microsteps;
+ uint8_t pulse_microseconds;
+ float default_feed_rate;
+ float default_seek_rate;
+ uint8_t invert_mask;
+ float mm_per_arc_segment;
+ float acceleration;
+ float junction_deviation;
+} settings_v4_t;
+
+
+// Method to store startup lines into EEPROM
+void settings_store_startup_line(uint8_t n, char *line)
+{
+ uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
+ memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
+}
+
+// Method to store coord data parameters into EEPROM
+void settings_write_coord_data(uint8_t coord_select, float *coord_data)
+{
+ uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
+ memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
+}
+
+// Method to store Grbl global settings struct and version number into EEPROM
+void write_global_settings()
+{
+ eeprom_put_char(0, SETTINGS_VERSION);
+ memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
+}
+
+// Method to reset Grbl global settings back to defaults.
+void settings_reset(bool reset_all) {
+ // Reset all settings or only the migration settings to the new version.
+ if (reset_all) {
+ settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
+ settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
+ settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
+ settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
+ settings.default_feed_rate = DEFAULT_FEEDRATE;
+ settings.default_seek_rate = DEFAULT_RAPID_FEEDRATE;
+ settings.acceleration = DEFAULT_ACCELERATION;
+ settings.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT;
+ settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK;
+ settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
+ }
+ // New settings since last version
+ settings.flags = 0;
+ if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
+ if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
+ if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
+ if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
+ if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
+ settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
+ settings.homing_feed_rate = DEFAULT_HOMING_FEEDRATE;
+ settings.homing_seek_rate = DEFAULT_HOMING_RAPID_FEEDRATE;
+ settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
+ settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
+ settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
+ settings.decimal_places = DEFAULT_DECIMAL_PLACES;
+ settings.n_arc_correction = DEFAULT_N_ARC_CORRECTION;
+ write_global_settings();
+}
+
+// Reads startup line from EEPROM. Updated pointed line string data.
+uint8_t settings_read_startup_line(uint8_t n, char *line)
+{
+ uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
+ if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
+ // Reset line with default value
+ line[0] = 0;
+ settings_store_startup_line(n, line);
+ return(false);
+ } else {
+ return(true);
+ }
+}
+
+// Read selected coordinate data from EEPROM. Updates pointed coord_data value.
+uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
+{
+ uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
+ if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
+ // Reset with default zero vector
+ clear_vector_float(coord_data);
+ settings_write_coord_data(coord_select,coord_data);
+ return(false);
+ } else {
+ return(true);
+ }
+}
+
+// Reads Grbl global settings struct from EEPROM.
+uint8_t read_global_settings() {
+ // Check version-byte of eeprom
+ uint8_t version = eeprom_get_char(0);
+
+ if (version == SETTINGS_VERSION) {
+ // Read settings-record and check checksum
+ if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
+ return(false);
+ }
+ } else {
+ if (version <= 4) {
+ // Migrate from settings version 4 to current version.
+ if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
+ return(false);
+ }
+ settings_reset(false); // Old settings ok. Write new settings only.
+ } else {
+ return(false);
+ }
+ }
+ return(true);
+}
+
+
+// A helper method to set settings from command line
+uint8_t settings_store_global_setting(int parameter, float value) {
+ switch(parameter) {
+ case 0: case 1: case 2:
+ if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
+ settings.steps_per_mm[parameter] = value; break;
+ case 3:
+ if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
+ settings.pulse_microseconds = round(value); break;
+ case 4: settings.default_feed_rate = value; break;
+ case 5: settings.default_seek_rate = value; break;
+ case 6: settings.invert_mask = trunc(value); break;
+ case 7: settings.stepper_idle_lock_time = round(value); break;
+ case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
+ case 9: settings.junction_deviation = fabs(value); break;
+ case 10: settings.mm_per_arc_segment = value; break;
+ case 11: settings.n_arc_correction = round(value); break;
+ case 12: settings.decimal_places = round(value); break;
+ case 13:
+ if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
+ else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
+ break;
+ case 14: // Reset to ensure change. Immediate re-init may cause problems.
+ if (value) { settings.flags |= BITFLAG_AUTO_START; }
+ else { settings.flags &= ~BITFLAG_AUTO_START; }
+ break;
+ case 15: // Reset to ensure change. Immediate re-init may cause problems.
+ if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
+ else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
+ break;
+ case 16:
+ if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
+ else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
+ limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
+ break;
+ case 17:
+ if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
+ else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
+ break;
+ case 18: settings.homing_dir_mask = trunc(value); break;
+ case 19: settings.homing_feed_rate = value; break;
+ case 20: settings.homing_seek_rate = value; break;
+ case 21: settings.homing_debounce_delay = round(value); break;
+ case 22: settings.homing_pulloff = value; break;
+ default:
+ return(STATUS_INVALID_STATEMENT);
+ }
+ write_global_settings();
+ return(STATUS_OK);
+}
+
+// Initialize the config subsystem
+void settings_init() {
+ if(!read_global_settings()) {
+ report_status_message(STATUS_SETTING_READ_FAIL);
+ settings_reset(true);
+ report_grbl_settings();
+ }
+ // Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing.
+ float coord_data[N_AXIS];
+ uint8_t i;
+ for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
+ if (!settings_read_coord_data(i, coord_data)) {
+ report_status_message(STATUS_SETTING_READ_FAIL);
+ }
+ }
+ // NOTE: Startup lines are handled and called by main.c at the end of initialization.
+}