Re-factored system states and alarm management. Serial baud support greater than 57600.

- Refactored system states to be more clear and concise. Alarm locks
processes when position is unknown to indicate to user something has
gone wrong.

- Changed mc_alarm to mc_reset, which now manages the system reset
function. Centralizes it.

- Renamed '$X' kill homing lock to kill alarm lock.

- Created an alarm error reporting method to clear up what is an alarm:
message vs a status error: message. For GUIs mainly. Alarm codes are
negative. Status codes are positive.

- Serial baud support upto 115200. Previous baudrate calc was unstable
for 57600 and above.

- Alarm state locks out all g-code blocks, including startup scripts,
but allows user to access settings and internal commands. For example,
to disable hard limits, if they are problematic.

- Hard limits do not respond in an alarm state.

- Fixed a problem with the hard limit interrupt during the homing
cycle. The interrupt register is still active during the homing cycle
and still signal the interrupt to trigger when re-enabled. Instead,
just disabled the register.

- Homing rate adjusted. All axes move at homing seek rate, regardless
of how many axes move at the same time. This is unlike how the stepper
module does it as a point to point rate.

- New config.h settings to disable the homing rate adjustment and the
force homing upon powerup.

- Reduced the number of startup lines back down to 2 from 3. This
discourages users from placing motion block in there, which can be very
dangerous.

- Startup blocks now run only after an alarm-free reset or after a
homing cycle. Does not run when $X kill is called. For satefy reasons
This commit is contained in:
Sonny Jeon 2012-11-14 17:36:29 -07:00
parent e6ad15b548
commit 559feb97e2
14 changed files with 466 additions and 420 deletions

View File

@ -69,9 +69,9 @@
#define COOLANT_FLOOD_PORT PORTC #define COOLANT_FLOOD_PORT PORTC
#define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3 #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 // 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. // a later date if flash and memory space allows.
// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
#ifdef ENABLE_M7 #ifdef ENABLE_M7
#define COOLANT_MIST_DDR DDRC #define COOLANT_MIST_DDR DDRC
#define COOLANT_MIST_PORT PORTC #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. // 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) #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. // 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 // This help in preventing overshoot and should improve repeatability. This value should be one or
// greater. // greater.
@ -167,7 +179,7 @@
// and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may // 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 // be stored and executed in order. These startup blocks would typically be used to set the g-code
// parser state depending on user preferences. // 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: // FOR ADVANCED USERS ONLY:

View File

@ -84,6 +84,11 @@ static float to_millimeters(float value)
// internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively. // internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively.
uint8_t gc_execute_line(char *line) 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; uint8_t char_counter = 0;
char letter; char letter;
float value; 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, // 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. // 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; } else { gc.program_flow = PROGRAM_FLOW_RUNNING; }
} }

View File

@ -41,30 +41,41 @@ void limits_init()
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation. LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << LIMIT_INT); // Enable 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 // 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 // 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 // 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. // 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) ISR(LIMIT_INT_vect)
{ {
// Only enter if the system alarm is not active. // TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
if (bit_isfalse(sys.execute,EXEC_ALARM)) { // interrupt without adding too much to it. All it would need is some way to stop one axis
// Kill all processes upon hard limit event. // when its limit is triggered and continue the others. This may reduce some of the code, but
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) { // would make Grbl a little harder to read and understand down road. Holding off on this until
mc_alarm(); // Initiate system kill. // we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
sys.state = STATE_LIMIT; // Set system state to indicate event.
} // 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) // 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)); 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 // 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 // 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, // 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() 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(); st_wake_up();
// Jog all axes toward home to engage their limit switches at faster homing seek rate. // 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 // First jog z-axis to clear workspace, then jog the x and y axis.
homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // 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 delay_ms(settings.homing_debounce_delay); // Delay to debounce signal
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles // Now in proximity of all limits. Carefully leave and approach switches in multiple cycles

42
main.c
View File

@ -45,14 +45,14 @@ system_t sys;
int main(void) int main(void)
{ {
// Initialize system // 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 settings_init(); // Load grbl settings from EEPROM
st_init(); // Setup stepper pins and interrupt timers st_init(); // Setup stepper pins and interrupt timers
sei(); // Enable interrupts sei(); // Enable interrupts
memset(&sys, 0, sizeof(sys)); // Clear all system variables memset(&sys, 0, sizeof(sys)); // Clear all system variables
sys.abort = true; // Set abort to complete initialization 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(;;) { for(;;) {
@ -60,7 +60,6 @@ int main(void)
// Once here, it is safe to re-initialize the system. At startup, the system will automatically // Once here, it is safe to re-initialize the system. At startup, the system will automatically
// reset to finish the initialization process. // reset to finish the initialization process.
if (sys.abort) { if (sys.abort) {
// Reset system. // Reset system.
serial_reset_read_buffer(); // Clear serial read buffer serial_reset_read_buffer(); // Clear serial read buffer
plan_init(); // Clear block buffer and planner variables plan_init(); // Clear block buffer and planner variables
@ -72,28 +71,33 @@ int main(void)
st_reset(); // Clear stepper subsystem variables. st_reset(); // Clear stepper subsystem variables.
// Sync cleared gcode and planner positions to current system position, which is only // 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 // cleared upon startup, not a reset/abort.
// 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.
sys_sync_current_position(); sys_sync_current_position();
// Reset system variables. // Reset system variables.
sys.abort = false; sys.abort = false;
sys.execute = 0; 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; } if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
// Execute user startup script // Check for power-up and set system alarm if homing is enabled to force homing cycle
protocol_execute_startup(); // 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(); protocol_execute_runtime();

View File

@ -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)) { if (bit_isfalse(gc.switches,BITFLAG_CHECK_GCODE)) {
plan_buffer_line(x, y, z, feed_rate, invert_feed_rate); 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. // If idle, indicate to the system there is now a planned block in the buffer ready to cycle
// NOTE: If homing cycles are enabled, a position lost state will lock out all motions, // start. Otherwise ignore and continue on.
// 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; } if (!sys.state) { sys.state = STATE_QUEUED; }
// Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During // 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() void mc_go_home()
{ {
sys.state = STATE_HOMING; // Set system state variable 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. limits_go_home(); // Perform homing routine.
if (sys.abort) { if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
sys.state = STATE_ALARM; // Homing routine did not complete.
return;
}
// The machine should now be homed and machine zero has been located. Upon completion, // The machine should now be homed and machine zero has been located. Upon completion,
// reset system position and sync internal position vectors. // 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(Y_DIRECTION_BIT))) { y_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_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, 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. st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes. plan_synchronize(); // Make sure the motion completes.
// The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors. // The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors.
sys_sync_current_position(); sys_sync_current_position();
// If hard limits feature enabled, re-enable hard limits interrupt after homing cycle. // If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); } if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { LIMIT_PCMSK |= LIMIT_MASK; }
// Finished! // Finished!
} }
// Method to immediately kill all motion and set system alarm. Used by system abort, hard limits, // Method to ready the system to reset by setting the runtime reset command and killing any
// and upon g-code parser error (when installed). // active processes in the system. This also checks if a system reset is issued while Grbl
void mc_alarm() // 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 // Only this function can set the system reset. Helps prevent multiple kill calls.
// by different processes. if (bit_isfalse(sys.execute, EXEC_RESET)) {
if (bit_isfalse(sys.execute, EXEC_ALARM)) { sys.execute |= EXEC_RESET;
// Set system alarm flag to have the main program check for anything wrong with shutting
// down the system. // Kill spindle and coolant.
sys.execute |= EXEC_ALARM;
// Immediately force stepper, spindle, and coolant to stop.
st_go_idle();
spindle_stop(); spindle_stop();
coolant_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.
}
} }
} }

View File

@ -43,7 +43,7 @@ void mc_dwell(float seconds);
// Perform homing cycle to locate machine zero. Requires limit switches. // Perform homing cycle to locate machine zero. Requires limit switches.
void mc_go_home(); void mc_go_home();
// Kills all motion and sets system alarm // Performs system reset. If in motion state, kills all motion and sets system alarm.
void mc_alarm(); void mc_reset();
#endif #endif

View File

@ -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() void sys_sync_current_position()
{ {
plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]); plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);

View File

@ -63,31 +63,29 @@
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000 #define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000 #define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000 #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 bit(7) // bitmask 10000000
// Define system state bit map. The state variable primarily tracks the individual functions // 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 // of Grbl to manage each without overlapping. It is also used as a messaging flag for
// critical events. // critical events.
#define STATE_IDLE 0 // Must be zero. #define STATE_IDLE 0 // Must be zero.
#define STATE_QUEUED 1 // Indicates buffered blocks, awaiting cycle start. #define STATE_INIT 1 // Initial power up state.
#define STATE_CYCLE 2 // Cycle is running #define STATE_QUEUED 2 // Indicates buffered blocks, awaiting cycle start.
#define STATE_HOLD 3 // Executing feed hold #define STATE_CYCLE 3 // Cycle is running
#define STATE_HOMING 4 // Performing homing cycle #define STATE_HOLD 4 // Executing feed hold
#define STATE_JOG 5 // Jogging mode is unique like homing. #define STATE_HOMING 5 // Performing homing cycle
#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes and messages position lost #define STATE_ALARM 6 // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_LIMIT 7 // Used to message hard limit triggered. // #define STATE_JOG 7 // Jogging mode is unique like homing.
// Define global system variables // Define global system variables
typedef struct { typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset. uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl. uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks. 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. // 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 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; } system_t;
extern system_t sys; extern system_t sys;

View File

@ -74,8 +74,7 @@ ISR(PINOUT_INT_vect)
// Enter only if any pinout pin is actively low. // Enter only if any pinout pin is actively low.
if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) { if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) {
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) { if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
mc_alarm(); mc_reset();
sys.execute |= EXEC_RESET; // Set as true
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) { } else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
sys.execute |= EXEC_FEED_HOLD; sys.execute |= EXEC_FEED_HOLD;
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) { } 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 // 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 // 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. // recalculating the buffer upon a feedhold or override.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted, // NOTE: The sys.execute variable flags are set by any process, step or serial interrupts, pinouts,
// but may be set by any process, such as a switch pin change interrupt when pinouts are installed. // limit switches, or the main program.
void protocol_execute_runtime() void protocol_execute_runtime()
{ {
if (sys.execute) { // Enter only if any bit flag is true if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times 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 // System alarm. Everything has shutdown by something that has gone severely wrong. Report
// the Grbl soft-reset/abort. Check the system states to report any critical error found. // the source of the error to the user. If critical, Grbl disables by entering an infinite
// If critical, disable Grbl by entering an infinite loop until system reset/abort. // loop until system reset/abort.
// NOTE: The system alarm state is also used to set if (rt_exec & (EXEC_ALARM | EXEC_CRIT_EVENT)) {
if (rt_exec & EXEC_ALARM) { sys.state = STATE_ALARM; // Set system alarm state
// Limit switch critical event. Lock out Grbl until reset.
if (sys.state == STATE_LIMIT) { // Critical event. Only hard limit qualifies. Update this as new critical events surface.
report_status_message(STATUS_HARD_LIMIT); if (rt_exec & EXEC_CRIT_EVENT) {
sys.state = STATE_ALARM; report_alarm_message(ALARM_HARD_LIMIT);
report_feedback_message(MESSAGE_CRITICAL_EVENT); 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);
} }
bit_false(sys.execute,(EXEC_ALARM | EXEC_CRIT_EVENT));
// 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);
} }
// System abort. Steppers have already been force stopped. // Execute system abort.
if (rt_exec & EXEC_RESET) { if (rt_exec & EXEC_RESET) {
sys.abort = true; // Only place this is set true. sys.abort = true; // Only place this is set true.
return; // Nothing else to do but exit. return; // Nothing else to do but exit.
@ -194,8 +198,10 @@ uint8_t protocol_execute_line(char *line)
case 'H' : // Perform homing cycle case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost. // Only perform homing if Grbl is idle or lost.
if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) { mc_go_home(); } if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) {
else { return(STATUS_IDLE_ERROR); } 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); } } else { return(STATUS_SETTING_DISABLED); }
break; break;
// case 'J' : break; // Jogging methods // 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 // 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 // is idle and ready, regardless of homing locks. This is mainly to keep things
// simple and consistent. // 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); } else if (sys.state) { return(STATUS_IDLE_ERROR); }
} }
gc.switches ^= helper_var; gc.switches ^= helper_var;
if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); } if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); }
else { report_feedback_message(MESSAGE_DISABLED); } else { report_feedback_message(MESSAGE_DISABLED); }
break; break;
case 'X' : // Disable homing lock case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) { if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_HOMING_UNLOCK); report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE; sys.state = STATE_IDLE;
} else { // Don't run startup script. Prevents stored moves in startup from causing accidents.
return(STATUS_SETTING_DISABLED);
} }
break; break;
case 'N' : // Startup lines. 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. return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else { } else {
return(gc_execute_line(line)); // Everything else is gcode
// 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);
}
} }
} }

106
report.c
View File

@ -62,8 +62,6 @@ void report_status_message(uint8_t status_code)
printPgmString(PSTR("Modal group violation")); break; printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT: case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break; printPgmString(PSTR("Invalid statement")); break;
case STATUS_HARD_LIMIT:
printPgmString(PSTR("Hard limit. MPos lost?")); break;
case STATUS_SETTING_DISABLED: case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Setting disabled")); break; printPgmString(PSTR("Setting disabled")); break;
case STATUS_SETTING_VALUE_NEG: case STATUS_SETTING_VALUE_NEG:
@ -73,37 +71,47 @@ void report_status_message(uint8_t status_code)
case STATUS_SETTING_READ_FAIL: case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("EEPROM read fail. Using defaults")); break; printPgmString(PSTR("EEPROM read fail. Using defaults")); break;
case STATUS_IDLE_ERROR: case STATUS_IDLE_ERROR:
printPgmString(PSTR("Busy or locked")); break; printPgmString(PSTR("Busy or queued")); break;
case STATUS_ABORT_CYCLE: case STATUS_ALARM_LOCK:
printPgmString(PSTR("Abort during cycle. MPos lost?")); break; printPgmString(PSTR("Alarm lock")); break;
case STATUS_HOMING_LOCK:
printPgmString(PSTR("Locked until homed")); break;
} }
printPgmString(PSTR("\r\n")); 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 // 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 // user feedback for things that are not of the status/alarm message protocol. These are
// are messages such as setup warnings and how to exit alarms. // 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 // NOTE: For interfaces, messages are always placed within brackets. And if silent mode
// is installed, the message number codes are less than zero. // is installed, the message number codes are less than zero.
// TODO: Install silence feedback messages option in settings // 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("[")); printPgmString(PSTR("["));
switch(message_code) { switch(message_code) {
case MESSAGE_CRITICAL_EVENT: case MESSAGE_CRITICAL_EVENT:
printPgmString(PSTR("ALARM: Check and reset")); break; printPgmString(PSTR("Reset to continue")); break;
case MESSAGE_HOMING_ALARM: case MESSAGE_ALARM_LOCK:
printPgmString(PSTR("'$H' to home and unlock")); break; printPgmString(PSTR("'$H'|'$X' to unlock")); break;
case MESSAGE_ALARM_UNLOCK:
printPgmString(PSTR("Caution: Unlocked")); break;
case MESSAGE_ENABLED: case MESSAGE_ENABLED:
printPgmString(PSTR("Enabled")); break; printPgmString(PSTR("Enabled")); break;
case MESSAGE_DISABLED: case MESSAGE_DISABLED:
printPgmString(PSTR("Disabled")); break; printPgmString(PSTR("Disabled")); break;
case MESSAGE_HOMING_UNLOCK:
printPgmString(PSTR("Unlocked. MPos lost?")); break;
} }
printPgmString(PSTR("]\r\n")); printPgmString(PSTR("]\r\n"));
} }
@ -127,7 +135,7 @@ void report_grbl_help() {
"$S1 (toggle blk del)\r\n" "$S1 (toggle blk del)\r\n"
"$S2 (toggle single blk)\r\n" "$S2 (toggle single blk)\r\n"
"$S3 (toggle opt stop)\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" "$H (run homing cycle)\r\n"
"~ (cycle start)\r\n" "~ (cycle start)\r\n"
"! (feed hold)\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). // especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status() void report_realtime_status()
{ {
// **Under construction** Bare-bones status report. Provides real-time machine position relative to // **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 // 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 // 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. // for a user to select the desired real-time data.
uint8_t i; uint8_t i;
int32_t current_position[3]; // Copy current state of the system position variable int32_t current_position[3]; // Copy current state of the system position variable
memcpy(current_position,sys.position,sizeof(sys.position)); memcpy(current_position,sys.position,sizeof(sys.position));
float print_position[3]; 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("]")); }
}
// Report work position // TODO: Add Grbl state feedback, i.e. IDLE, RUN, HOLD, HOME, etc.
printPgmString(PSTR(",WPos:["));
for (i=0; i<= 2; i++) { // Report machine position
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { printPgmString(PSTR("MPos:["));
print_position[i] -= (gc.coord_system[i]+gc.coord_offset[i])*INCH_PER_MM; for (i=0; i<= 2; i++) {
} else { print_position[i] = current_position[i]/settings.steps_per_mm[i];
print_position[i] -= gc.coord_system[i]+gc.coord_offset[i]; if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
} printFloat(print_position[i]);
printFloat(print_position[i]); if (i < 2) { printPgmString(PSTR(",")); }
if (i < 2) { printPgmString(PSTR(",")); } else { printPgmString(PSTR("]")); }
else { printPgmString(PSTR("]")); } }
}
// Report work position
printPgmString(PSTR("\r\n")); 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"));
} }

View File

@ -29,27 +29,32 @@
#define STATUS_ARC_RADIUS_ERROR 4 #define STATUS_ARC_RADIUS_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5 #define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6 #define STATUS_INVALID_STATEMENT 6
#define STATUS_HARD_LIMIT 7 #define STATUS_SETTING_DISABLED 7
#define STATUS_SETTING_DISABLED 8 #define STATUS_SETTING_VALUE_NEG 8
#define STATUS_SETTING_VALUE_NEG 9 #define STATUS_SETTING_STEP_PULSE_MIN 9
#define STATUS_SETTING_STEP_PULSE_MIN 10 #define STATUS_SETTING_READ_FAIL 10
#define STATUS_SETTING_READ_FAIL 11 #define STATUS_IDLE_ERROR 11
#define STATUS_IDLE_ERROR 12 #define STATUS_ALARM_LOCK 12
#define STATUS_ABORT_CYCLE 13
#define STATUS_HOMING_LOCK 14
// Define Grbl feedback message codes. Less than zero to distinguish message from error. // Define Grbl alarm codes. Less than zero to distinguish alarm error from status error.
#define MESSAGE_CRITICAL_EVENT -1 #define ALARM_HARD_LIMIT -1
#define MESSAGE_HOMING_ALARM -2 #define ALARM_ABORT_CYCLE -2
#define MESSAGE_ENABLED -3
#define MESSAGE_DISABLED -4 // Define Grbl feedback message codes.
#define MESSAGE_HOMING_UNLOCK -5 #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. // Prints system status messages.
void report_status_message(uint8_t status_code); void report_status_message(uint8_t status_code);
// Prints system alarm messages.
void report_alarm_message(int8_t alarm_code);
// Prints miscellaneous feedback messages. // Prints miscellaneous feedback messages.
void report_feedback_message(int8_t message_code); void report_feedback_message(uint8_t message_code);
// Prints welcome message // Prints welcome message
void report_init_message(); void report_init_message();

View File

@ -49,19 +49,19 @@ volatile uint8_t tx_buffer_tail = 0;
} }
#endif #endif
static void set_baud_rate(long baud) { void serial_init()
uint16_t UBRR0_value = ((F_CPU / 16 + baud / 2) / baud - 1); {
// 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; UBRR0H = UBRR0_value >> 8;
UBRR0L = UBRR0_value; 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 // enable rx and tx
UCSR0B |= 1<<RXEN0; UCSR0B |= 1<<RXEN0;
UCSR0B |= 1<<TXEN0; UCSR0B |= 1<<TXEN0;
@ -159,11 +159,7 @@ ISR(USART_RX_vect)
case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true
case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
case CMD_RESET: case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
// Immediately force stepper and spindle subsystem idle at an interrupt level.
mc_alarm();
sys.execute |= EXEC_RESET; // Set as true
break;
default: // Write character to buffer default: // Write character to buffer
next_head = rx_buffer_head + 1; next_head = rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE) { next_head = 0; } if (next_head == RX_BUFFER_SIZE) { next_head = 0; }

View File

@ -47,7 +47,7 @@
#define XON_CHAR 0x11 #define XON_CHAR 0x11
#endif #endif
void serial_init(long baud); void serial_init();
void serial_write(uint8_t data); void serial_write(uint8_t data);

View File

@ -1,222 +1,221 @@
/* /*
settings.c - eeprom configuration handling settings.c - eeprom configuration handling
Part of Grbl Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011-2012 Sungeun K. Jeon Copyright (c) 2011-2012 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Grbl is distributed in the hope that it will be useful, Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <avr/io.h> #include <avr/io.h>
#include "protocol.h" #include "protocol.h"
#include "report.h" #include "report.h"
#include "stepper.h" #include "stepper.h"
#include "nuts_bolts.h" #include "nuts_bolts.h"
#include "settings.h" #include "settings.h"
#include "eeprom.h" #include "eeprom.h"
#include "limits.h"
settings_t settings;
settings_t settings;
// Version 4 outdated settings record
typedef struct { // Version 4 outdated settings record
float steps_per_mm[3]; typedef struct {
uint8_t microsteps; float steps_per_mm[3];
uint8_t pulse_microseconds; uint8_t microsteps;
float default_feed_rate; uint8_t pulse_microseconds;
float default_seek_rate; float default_feed_rate;
uint8_t invert_mask; float default_seek_rate;
float mm_per_arc_segment; uint8_t invert_mask;
float acceleration; float mm_per_arc_segment;
float junction_deviation; float acceleration;
} settings_v4_t; float junction_deviation;
} settings_v4_t;
// Method to store startup lines into EEPROM
void settings_store_startup_line(uint8_t n, char *line) // 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); 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) // 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); 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() // 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)); 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) { // Method to reset Grbl global settings back to defaults.
// Reset all settings or only the migration settings to the new version. void settings_reset(bool reset_all) {
if (reset_all) { // Reset all settings or only the migration settings to the new version.
settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM; if (reset_all) {
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM; settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM; settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS; settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
settings.default_feed_rate = DEFAULT_FEEDRATE; settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
settings.default_seek_rate = DEFAULT_RAPID_FEEDRATE; settings.default_feed_rate = DEFAULT_FEEDRATE;
settings.acceleration = DEFAULT_ACCELERATION; settings.default_seek_rate = DEFAULT_RAPID_FEEDRATE;
settings.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; settings.acceleration = DEFAULT_ACCELERATION;
settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK; settings.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT;
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; settings.invert_mask = DEFAULT_STEPPING_INVERT_MASK;
} settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
// New settings since last version }
settings.flags = 0; // New settings since last version
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; } settings.flags = 0;
if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; } if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; } if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK; if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
settings.homing_feed_rate = DEFAULT_HOMING_FEEDRATE; settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
settings.homing_seek_rate = DEFAULT_HOMING_RAPID_FEEDRATE; settings.homing_feed_rate = DEFAULT_HOMING_FEEDRATE;
settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY; settings.homing_seek_rate = DEFAULT_HOMING_RAPID_FEEDRATE;
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF; settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME; settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
settings.decimal_places = DEFAULT_DECIMAL_PLACES; settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
settings.n_arc_correction = DEFAULT_N_ARC_CORRECTION; settings.decimal_places = DEFAULT_DECIMAL_PLACES;
write_global_settings(); 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) // 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))) { uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
// Reset line with default value if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
line[0] = 0; // Reset line with default value
settings_store_startup_line(n, line); line[0] = 0;
return(false); settings_store_startup_line(n, line);
} else { return(false);
return(true); } 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) // 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))) { uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
// Reset with default zero vector if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
clear_vector_float(coord_data); // Reset with default zero vector
settings_write_coord_data(coord_select,coord_data); clear_vector_float(coord_data);
return(false); settings_write_coord_data(coord_select,coord_data);
} else { return(false);
return(true); } else {
} return(true);
} }
}
// Reads Grbl global settings struct from EEPROM.
uint8_t read_global_settings() { // Reads Grbl global settings struct from EEPROM.
// Check version-byte of eeprom uint8_t read_global_settings() {
uint8_t version = eeprom_get_char(0); // Check version-byte of eeprom
uint8_t version = eeprom_get_char(0);
if (version == SETTINGS_VERSION) {
// Read settings-record and check checksum if (version == SETTINGS_VERSION) {
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) { // Read settings-record and check checksum
return(false); if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
} return(false);
} else { }
if (version <= 4) { } else {
// Migrate from settings version 4 to current version. if (version <= 4) {
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) { // Migrate from settings version 4 to current version.
return(false); 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 { settings_reset(false); // Old settings ok. Write new settings only.
return(false); } else {
} return(false);
} }
return(true); }
} return(true);
}
// A helper method to set settings from command line
uint8_t settings_store_global_setting(int parameter, float value) { // A helper method to set settings from command line
switch(parameter) { uint8_t settings_store_global_setting(int parameter, float value) {
case 0: case 1: case 2: switch(parameter) {
if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); } case 0: case 1: case 2:
settings.steps_per_mm[parameter] = value; break; if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
case 3: settings.steps_per_mm[parameter] = value; break;
if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); } case 3:
settings.pulse_microseconds = round(value); break; if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
case 4: settings.default_feed_rate = value; break; settings.pulse_microseconds = round(value); break;
case 5: settings.default_seek_rate = value; break; case 4: settings.default_feed_rate = value; break;
case 6: settings.invert_mask = trunc(value); break; case 5: settings.default_seek_rate = value; break;
case 7: settings.stepper_idle_lock_time = round(value); break; case 6: settings.invert_mask = trunc(value); break;
case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use. case 7: settings.stepper_idle_lock_time = round(value); break;
case 9: settings.junction_deviation = fabs(value); break; case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
case 10: settings.mm_per_arc_segment = value; break; case 9: settings.junction_deviation = fabs(value); break;
case 11: settings.n_arc_correction = round(value); break; case 10: settings.mm_per_arc_segment = value; break;
case 12: settings.decimal_places = round(value); break; case 11: settings.n_arc_correction = round(value); break;
case 13: case 12: settings.decimal_places = round(value); break;
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; } case 13:
else { settings.flags &= ~BITFLAG_REPORT_INCHES; } if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
break; else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
case 14: // Reboot to ensure change break;
if (value) { settings.flags |= BITFLAG_AUTO_START; } case 14: // Reset to ensure change. Immediate re-init may cause problems.
else { settings.flags &= ~BITFLAG_AUTO_START; } if (value) { settings.flags |= BITFLAG_AUTO_START; }
break; else { settings.flags &= ~BITFLAG_AUTO_START; }
case 15: // Reboot to ensure change break;
if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } case 15: // Reset to ensure change. Immediate re-init may cause problems.
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
break; else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
case 16: // Reboot to ensure change break;
if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } case 16:
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
break; else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
case 17: limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
if (value) { break;
settings.flags |= BITFLAG_HOMING_ENABLE; case 17:
sys.state = STATE_ALARM; if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
report_feedback_message(MESSAGE_HOMING_ALARM); else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
} else { settings.flags &= ~BITFLAG_HOMING_ENABLE; } break;
break; case 18: settings.homing_dir_mask = trunc(value); break;
case 18: settings.homing_dir_mask = trunc(value); break; case 19: settings.homing_feed_rate = value; break;
case 19: settings.homing_feed_rate = value; break; case 20: settings.homing_seek_rate = value; break;
case 20: settings.homing_seek_rate = value; break; case 21: settings.homing_debounce_delay = round(value); break;
case 21: settings.homing_debounce_delay = round(value); break; case 22: settings.homing_pulloff = value; break;
case 22: settings.homing_pulloff = value; break; default:
default: return(STATUS_INVALID_STATEMENT);
return(STATUS_INVALID_STATEMENT); }
} write_global_settings();
write_global_settings(); return(STATUS_OK);
return(STATUS_OK); }
}
// Initialize the config subsystem
// Initialize the config subsystem void settings_init() {
void settings_init() { if(!read_global_settings()) {
if(!read_global_settings()) { report_status_message(STATUS_SETTING_READ_FAIL);
report_status_message(STATUS_SETTING_READ_FAIL); settings_reset(true);
settings_reset(true); report_grbl_settings();
report_grbl_settings(); }
} // Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing.
// Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing. float coord_data[N_AXIS];
float coord_data[N_AXIS]; uint8_t i;
uint8_t i; for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
for (i=0; i<=SETTING_INDEX_NCOORD; i++) { if (!settings_read_coord_data(i, coord_data)) {
if (!settings_read_coord_data(i, coord_data)) { report_status_message(STATUS_SETTING_READ_FAIL);
report_status_message(STATUS_SETTING_READ_FAIL); }
} }
} // NOTE: Startup lines are handled and called by main.c at the end of initialization.
// NOTE: Startup lines are handled and called by main.c at the end of initialization. }
}