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:
parent
e6ad15b548
commit
559feb97e2
16
config.h
16
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:
|
||||
|
7
gcode.c
7
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; }
|
||||
}
|
||||
|
||||
|
39
limits.c
39
limits.c
@ -43,27 +43,38 @@ void limits_init()
|
||||
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
|
||||
} 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.
|
||||
ISR(LIMIT_INT_vect)
|
||||
{
|
||||
// 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.
|
||||
|
||||
// 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)) {
|
||||
// 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.
|
||||
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
|
||||
|
38
main.c
38
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,29 +71,34 @@ 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
|
||||
// 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();
|
||||
protocol_process(); // ... process the serial protocol
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
|
20
nuts_bolts.h
20
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;
|
||||
|
||||
|
77
protocol.c
77
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);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
42
report.c
42
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"
|
||||
@ -296,6 +304,8 @@ void report_realtime_status()
|
||||
memcpy(current_position,sys.position,sizeof(sys.position));
|
||||
float print_position[3];
|
||||
|
||||
// TODO: Add Grbl state feedback, i.e. IDLE, RUN, HOLD, HOME, etc.
|
||||
|
||||
// Report machine position
|
||||
printPgmString(PSTR("MPos:["));
|
||||
for (i=0; i<= 2; i++) {
|
||||
|
35
report.h
35
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();
|
||||
|
26
serial.c
26
serial.c
@ -49,18 +49,18 @@ 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<<RXEN0;
|
||||
@ -159,11 +159,7 @@ ISR(USART_RX_vect)
|
||||
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_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
|
||||
case CMD_RESET:
|
||||
// Immediately force stepper and spindle subsystem idle at an interrupt level.
|
||||
mc_alarm();
|
||||
sys.execute |= EXEC_RESET; // Set as true
|
||||
break;
|
||||
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
|
||||
default: // Write character to buffer
|
||||
next_head = rx_buffer_head + 1;
|
||||
if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
|
||||
|
2
serial.h
2
serial.h
@ -47,7 +47,7 @@
|
||||
#define XON_CHAR 0x11
|
||||
#endif
|
||||
|
||||
void serial_init(long baud);
|
||||
void serial_init();
|
||||
|
||||
void serial_write(uint8_t data);
|
||||
|
||||
|
15
settings.c
15
settings.c
@ -26,6 +26,7 @@
|
||||
#include "nuts_bolts.h"
|
||||
#include "settings.h"
|
||||
#include "eeprom.h"
|
||||
#include "limits.h"
|
||||
|
||||
settings_t settings;
|
||||
|
||||
@ -172,24 +173,22 @@ uint8_t settings_store_global_setting(int parameter, float value) {
|
||||
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
|
||||
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
|
||||
break;
|
||||
case 14: // Reboot to ensure change
|
||||
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: // Reboot to ensure change
|
||||
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: // Reboot to ensure change
|
||||
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;
|
||||
sys.state = STATE_ALARM;
|
||||
report_feedback_message(MESSAGE_HOMING_ALARM);
|
||||
} else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user