Lots of re-organization and cleaning-up. Some bug fixes.

- Added a new source and header file called system. These files contain
the system commands and variables, as well as all of the system headers
and standard libraries Grbl uses. Centralizing some of the code.

- Re-organized the include headers throughout the source code.

- ENABLE_M7 define was missing from config.h. Now there.

- SPINDLE_MAX_RPM and SPINDLE_MIN_RPM now defined in config.h. No
uncommenting to prevent user issues. Minimum spindle RPM now provides
the lower, near 0V, scale adjustment, i.e. some spindles can go really
slow so why use up our 256 voltage bins for them?

- Remove some persistent variables from coolant and spindle control.
They were redundant.

- Removed a VARIABLE_SPINDLE define in cpu_map.h that shouldn’t have
been there.

- Changed the DEFAULT_ARC_TOLERANCE to 0.002mm to improve arc tracing.
Before we had issues with performance, no longer.

- Fixed a bug with the hard limits and the software debounce feature
enabled. The invert limit pin setting wasn’t honored.

- Fixed a bug with the homing direction mask. Now is like it used to
be. At least for now.

- Re-organized main.c to serve as only as the reset/initialization
routine. Makes things a little bit clearer in terms of execution
procedures.

- Re-organized protocol.c as the overall master control unit for
execution procedures. Not quite there yet, but starting to make a
little more sense in how things are run.

- Removed updating of old settings records. So many new settings have
been added that it’s not worth adding the code to migrate old user
settings.

- Tweaked spindle_control.c a bit and made it more clear and consistent
with other parts of Grbl.

- Tweaked the stepper disable bit code in stepper.c. Requires less
flash memory.
This commit is contained in:
Sonny Jeon 2014-01-10 20:22:10 -07:00
parent 7a85ab896d
commit cc9afdc195
31 changed files with 636 additions and 583 deletions

View File

@ -33,7 +33,7 @@ CLOCK = 16000000
PROGRAMMER ?= -c avrisp2 -P usb PROGRAMMER ?= -c avrisp2 -P usb
OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \ OBJECTS = main.o motion_control.o gcode.o spindle_control.o coolant_control.o serial.o \
protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \ protocol.o stepper.o eeprom.o settings.o planner.o nuts_bolts.o limits.o \
print.o report.o print.o report.o system.o
# FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m # FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
# update that line with this when programmer is back up: # update that line with this when programmer is back up:

View File

@ -79,6 +79,11 @@
// parser state depending on user preferences. // parser state depending on user preferences.
#define N_STARTUP_LINE 2 // Integer (1-3) #define N_STARTUP_LINE 2 // Integer (1-3)
// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
// analog pin 5. Only use this option if you require a second control pin.
// NOTE: The M8 flood coolant control pin on analog pin 4 will still be functional regardless.
// #define ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable.
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// ADVANCED CONFIGURATION OPTIONS: // ADVANCED CONFIGURATION OPTIONS:
@ -103,7 +108,14 @@
// NOTE: IMPORTANT for Arduino Unos! When enabled, the Z-limit pin D11 and spindle enable pin D12 switch! // NOTE: IMPORTANT for Arduino Unos! When enabled, the Z-limit pin D11 and spindle enable pin D12 switch!
// The hardware PWM output on pin D11 is required for variable spindle output voltages. // The hardware PWM output on pin D11 is required for variable spindle output voltages.
// #define VARIABLE_SPINDLE // Default disabled. Uncomment to enable. // #define VARIABLE_SPINDLE // Default disabled. Uncomment to enable.
// #define SPINDLE_MAX_RPM 1000 // Max spindle RPM. This value is equal to 100% Duty Cycle on the PWM.
// Use by the variable spindle output only. These parameters set the maximum and minimum spindle speed
// "S" g-code values to correspond to the maximum and minimum pin voltages. There are 256 discrete and
// equally divided voltage bins between the maximum and minimum spindle speeds. So for a 5V pin, 1000
// max rpm, and 250 min rpm, the spindle output voltage would be set for the following "S" commands:
// "S1000" @ 5V, "S250" @ 0.02V, and "S625" @ 2.5V (mid-range). The pin outputs 0V when disabled.
#define SPINDLE_MAX_RPM 1000.0 // Max spindle RPM. This value is equal to 100% duty cycle on the PWM.
#define SPINDLE_MIN_RPM 0.0 // Min spindle RPM. This value is equal to (1/256) duty cycle on the PWM.
// Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at // Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at
// every buffer block junction, except for starting from rest and end of the buffer, which are always // every buffer block junction, except for starting from rest and end of the buffer, which are always
@ -182,12 +194,13 @@
// case, please report any successes to grbl administrators! // case, please report any successes to grbl administrators!
// #define ENABLE_XONXOFF // Default disabled. Uncomment to enable. // #define ENABLE_XONXOFF // Default disabled. Uncomment to enable.
// A simple software debouncing feature for hard limit switches. When enabled, the interrupt monitoring // A simple software debouncing feature for hard limit switches. When enabled, the interrupt
// the hard limit switch pins will enable the Arduino's watchdog timer to re-check the limit pin state // monitoring the hard limit switch pins will enable the Arduino's watchdog timer to re-check
// after a delay of about 32msec. This can help with CNC machines with problematic false triggering of // the limit pin state after a delay of about 32msec. This can help with CNC machines with
// their hard limit switches, but it WILL NOT fix issues with electrical interference on the signal // problematic false triggering of their hard limit switches, but it WILL NOT fix issues with
// cables from external sources. It's recommended to first use shielded signal cables that are grounded // electrical interference on the signal cables from external sources. It's recommended to first
// (old USB/computer cables work well) and wire in a low-pass circuit into each limit pin. // use shielded signal cables with their shielding connected to ground (old USB/computer cables
// work well and are cheap to find) and wire in a low-pass circuit into each limit pin.
// #define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable. // #define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------

View File

@ -18,19 +18,13 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "system.h"
#include "coolant_control.h" #include "coolant_control.h"
#include "settings.h"
#include "config.h"
#include "planner.h" #include "planner.h"
#include <avr/io.h>
static uint8_t current_coolant_mode;
void coolant_init() void coolant_init()
{ {
current_coolant_mode = COOLANT_DISABLE;
COOLANT_FLOOD_DDR |= (1 << COOLANT_FLOOD_BIT); COOLANT_FLOOD_DDR |= (1 << COOLANT_FLOOD_BIT);
#ifdef ENABLE_M7 #ifdef ENABLE_M7
COOLANT_MIST_DDR |= (1 << COOLANT_MIST_BIT); COOLANT_MIST_DDR |= (1 << COOLANT_MIST_BIT);
@ -50,8 +44,6 @@ void coolant_stop()
void coolant_run(uint8_t mode) void coolant_run(uint8_t mode)
{ {
if (mode != current_coolant_mode)
{
plan_synchronize(); // Ensure coolant turns on when specified in program. plan_synchronize(); // Ensure coolant turns on when specified in program.
if (mode == COOLANT_FLOOD_ENABLE) { if (mode == COOLANT_FLOOD_ENABLE) {
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT); COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
@ -64,6 +56,4 @@ void coolant_run(uint8_t mode)
} else { } else {
coolant_stop(); coolant_stop();
} }
current_coolant_mode = mode;
}
} }

View File

@ -21,12 +21,12 @@
#ifndef coolant_control_h #ifndef coolant_control_h
#define coolant_control_h #define coolant_control_h
#include <avr/io.h>
#define COOLANT_MIST_ENABLE 2 #define COOLANT_MIST_ENABLE 2
#define COOLANT_FLOOD_ENABLE 1 #define COOLANT_FLOOD_ENABLE 1
#define COOLANT_DISABLE 0 // Must be zero. #define COOLANT_DISABLE 0 // Must be zero.
void coolant_init(); void coolant_init();
void coolant_stop(); void coolant_stop();
void coolant_run(uint8_t mode); void coolant_run(uint8_t mode);

View File

@ -36,9 +36,6 @@
#define SERIAL_RX USART_RX_vect #define SERIAL_RX USART_RX_vect
#define SERIAL_UDRE USART_UDRE_vect #define SERIAL_UDRE USART_UDRE_vect
// Start of PWM & Stepper Enabled Spindle
// #define VARIABLE_SPINDLE // comment this out to disable PWM & Stepper on the spindle
// Define step pulse output pins. NOTE: All step bit pins must be on the same port. // Define step pulse output pins. NOTE: All step bit pins must be on the same port.
#define STEPPING_DDR DDRD #define STEPPING_DDR DDRD
#define STEPPING_PORT PORTD #define STEPPING_PORT PORTD

View File

@ -47,7 +47,7 @@
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
@ -87,7 +87,7 @@
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_REPORT_INCHES 0 // true #define DEFAULT_REPORT_INCHES 0 // true
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
@ -98,7 +98,7 @@
#define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_ENABLE 0 // false
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
#define DEFAULT_HOMING_FEED_RATE 50.0 // mm/min #define DEFAULT_HOMING_FEED_RATE 50.0 // mm/min
#define DEFAULT_HOMING_SEEK_RATE 500.0 // mm/min #define DEFAULT_HOMING_SEEK_RATE 635.0 // mm/min
#define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k) #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
#define DEFAULT_HOMING_PULLOFF 1.0 // mm #define DEFAULT_HOMING_PULLOFF 1.0 // mm
#endif #endif
@ -130,7 +130,7 @@
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
@ -172,7 +172,7 @@
#define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #define DEFAULT_STEPPING_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true
@ -213,7 +213,7 @@
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)) #define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.005 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_REPORT_INCHES 0 // false #define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true #define DEFAULT_AUTO_START 1 // true

15
gcode.c
View File

@ -22,16 +22,13 @@
/* This code is inspired by the Arduino GCode Interpreter by Mike Ellery and the NIST RS274/NGC Interpreter /* This code is inspired by the Arduino GCode Interpreter by Mike Ellery and the NIST RS274/NGC Interpreter
by Kramer, Proctor and Messina. */ by Kramer, Proctor and Messina. */
#include "gcode.h" #include "system.h"
#include <string.h>
#include "nuts_bolts.h"
#include <math.h>
#include "settings.h" #include "settings.h"
#include "gcode.h"
#include "planner.h"
#include "motion_control.h" #include "motion_control.h"
#include "spindle_control.h" #include "spindle_control.h"
#include "coolant_control.h" #include "coolant_control.h"
#include "errno.h"
#include "protocol.h"
#include "report.h" #include "report.h"
// Declare gc extern struct // Declare gc extern struct
@ -186,9 +183,9 @@ uint8_t gc_execute_line(char *line)
case 0: gc.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause case 0: gc.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause
case 1: break; // Optional stop not supported. Ignore. case 1: break; // Optional stop not supported. Ignore.
case 2: case 30: gc.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset case 2: case 30: gc.program_flow = PROGRAM_FLOW_COMPLETED; break; // Program end and reset
case 3: gc.spindle_direction = 1; break; case 3: gc.spindle_direction = SPINDLE_ENABLE_CW; break;
case 4: gc.spindle_direction = -1; break; case 4: gc.spindle_direction = SPINDLE_ENABLE_CCW; break;
case 5: gc.spindle_direction = 0; break; case 5: gc.spindle_direction = SPINDLE_DISABLE; break;
#ifdef ENABLE_M7 #ifdef ENABLE_M7
case 7: gc.coolant_mode = COOLANT_MIST_ENABLE; break; case 7: gc.coolant_mode = COOLANT_MIST_ENABLE; break;
#endif #endif

10
gcode.h
View File

@ -21,8 +21,8 @@
#ifndef gcode_h #ifndef gcode_h
#define gcode_h #define gcode_h
#include <avr/io.h>
#include "nuts_bolts.h" #include "system.h"
// Define modal group internal numbers for checking multiple command violations and tracking the // Define modal group internal numbers for checking multiple command violations and tracking the
// type of command that is called in the block. A modal group is a group of g-code commands that are // type of command that is called in the block. A modal group is a group of g-code commands that are
@ -70,12 +70,12 @@ typedef struct {
uint8_t inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21} uint8_t inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21}
uint8_t absolute_mode; // 0 = relative motion, 1 = absolute motion {G90, G91} uint8_t absolute_mode; // 0 = relative motion, 1 = absolute motion {G90, G91}
uint8_t program_flow; // {M0, M1, M2, M30} uint8_t program_flow; // {M0, M1, M2, M30}
int8_t spindle_direction; // 1 = CW, -1 = CCW, 0 = Stop {M3, M4, M5} uint8_t coolant_mode; // 0 = Disable, 1 = Flood Enable, 2 = Mist Enable {M8, M9}
uint8_t coolant_mode; // 0 = Disable, 1 = Flood Enable {M8, M9} int8_t spindle_direction; // 1 = CW, 2 = CCW, 0 = Stop {M3, M4, M5}
float spindle_speed; // RPM
float feed_rate; // Millimeters/min float feed_rate; // Millimeters/min
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
uint8_t tool; uint8_t tool;
uint16_t spindle_speed; // RPM
uint8_t plane_axis_0, uint8_t plane_axis_0,
plane_axis_1, plane_axis_1,
plane_axis_2; // The axes of the selected plane plane_axis_2; // The axes of the selected plane

View File

@ -19,18 +19,12 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <util/delay.h> #include "system.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include "stepper.h"
#include "settings.h" #include "settings.h"
#include "nuts_bolts.h"
#include "config.h"
#include "spindle_control.h"
#include "motion_control.h"
#include "planner.h"
#include "protocol.h" #include "protocol.h"
#include "planner.h"
#include "stepper.h"
#include "motion_control.h"
#include "limits.h" #include "limits.h"
#include "report.h" #include "report.h"
@ -88,11 +82,9 @@ void limits_disable()
// limit setting if their limits are constantly triggering after a reset and move their axes. // limit setting if their limits are constantly triggering after a reset and move their axes.
if (sys.state != STATE_ALARM) { if (sys.state != STATE_ALARM) {
if (bit_isfalse(sys.execute,EXEC_ALARM)) { if (bit_isfalse(sys.execute,EXEC_ALARM)) {
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH uint8_t bits = LIMIT_PIN;
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) { if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { bits ^= LIMIT_MASK; }
#else if (bits & LIMIT_MASK) {
if (LIMIT_PIN & LIMIT_MASK) {
#endif
mc_reset(); // Initiate system kill. mc_reset(); // Initiate system kill.
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
} }
@ -151,9 +143,9 @@ void limits_go_home(uint8_t cycle_mask, bool approach, float homing_rate)
target[i] = 0.0; target[i] = 0.0;
} }
} }
if (bit_istrue(settings.homing_dir_mask,(1<<X_LIMIT_BIT))) { target[X_AXIS] = -target[X_AXIS]; } if (bit_istrue(settings.homing_dir_mask,(1<<X_DIRECTION_BIT))) { target[X_AXIS] = -target[X_AXIS]; }
if (bit_istrue(settings.homing_dir_mask,(1<<Y_LIMIT_BIT))) { target[Y_AXIS] = -target[Y_AXIS]; } if (bit_istrue(settings.homing_dir_mask,(1<<Y_DIRECTION_BIT))) { target[Y_AXIS] = -target[Y_AXIS]; }
if (bit_istrue(settings.homing_dir_mask,(1<<Z_LIMIT_BIT))) { target[Z_AXIS] = -target[Z_AXIS]; } if (bit_istrue(settings.homing_dir_mask,(1<<Z_DIRECTION_BIT))) { target[Z_AXIS] = -target[Z_AXIS]; }
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate. homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
// Setup homing axis locks based on cycle mask. // Setup homing axis locks based on cycle mask.
@ -172,15 +164,15 @@ void limits_go_home(uint8_t cycle_mask, bool approach, float homing_rate)
// Check limit state. Lock out cycle axes when they change. // Check limit state. Lock out cycle axes when they change.
limit_state = LIMIT_PIN; limit_state = LIMIT_PIN;
if (invert_pin) { limit_state ^= LIMIT_MASK; } if (invert_pin) { limit_state ^= LIMIT_MASK; }
// if (axislock & (1<<X_STEP_BIT)) { if (axislock & (1<<X_STEP_BIT)) {
if (limit_state & (1<<X_LIMIT_BIT)) { axislock &= ~(1<<X_STEP_BIT); } if (limit_state & (1<<X_LIMIT_BIT)) { axislock &= ~(1<<X_STEP_BIT); }
// } }
// if (axislock & (1<<Y_STEP_BIT)) { if (axislock & (1<<Y_STEP_BIT)) {
if (limit_state & (1<<Y_LIMIT_BIT)) { axislock &= ~(1<<Y_STEP_BIT); } if (limit_state & (1<<Y_LIMIT_BIT)) { axislock &= ~(1<<Y_STEP_BIT); }
// } }
// if (axislock & (1<<Z_STEP_BIT)) { if (axislock & (1<<Z_STEP_BIT)) {
if (limit_state & (1<<Z_LIMIT_BIT)) { axislock &= ~(1<<Z_STEP_BIT); } if (limit_state & (1<<Z_LIMIT_BIT)) { axislock &= ~(1<<Z_STEP_BIT); }
// } }
sys.homing_axis_lock = axislock; sys.homing_axis_lock = axislock;
st_prep_buffer(); // Check and prep one segment. NOTE: Should take no longer than 200us. st_prep_buffer(); // Check and prep one segment. NOTE: Should take no longer than 200us.
if (sys.execute & EXEC_RESET) { return; } if (sys.execute & EXEC_RESET) { return; }

View File

@ -22,6 +22,7 @@
#ifndef limits_h #ifndef limits_h
#define limits_h #define limits_h
// Initialize the limits module // Initialize the limits module
void limits_init(); void limits_init();

57
main.c
View File

@ -19,35 +19,32 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* A big thanks to Alden Hart of Synthetos, supplier of grblshield and TinyG, who has #include "system.h"
been integral throughout the development of the higher level details of Grbl, as well #include "serial.h"
as being a consistent sounding board for the future of accessible and free CNC. */ #include "settings.h"
#include "protocol.h"
#include <avr/interrupt.h> #include "gcode.h"
#include "config.h"
#include "planner.h" #include "planner.h"
#include "nuts_bolts.h"
#include "stepper.h" #include "stepper.h"
#include "spindle_control.h" #include "spindle_control.h"
#include "coolant_control.h" #include "coolant_control.h"
#include "motion_control.h" #include "motion_control.h"
#include "gcode.h"
#include "protocol.h"
#include "limits.h" #include "limits.h"
#include "report.h" #include "report.h"
#include "settings.h"
#include "serial.h"
// Declare system global variable structure // Declare system global variable structure
system_t sys; system_t sys;
int main(void) int main(void)
{ {
// Initialize system // Initialize system upon power-up.
serial_init(); // 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 stepper_init(); // Configure stepper pins and interrupt timers
sei(); // Enable interrupts system_init(); // Configure pinout pins and pin-change interrupt
sei();
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
@ -65,22 +62,16 @@ int main(void)
for(;;) { for(;;) {
// Execute system reset upon a system abort, where the main program will return to this loop. // Reset the system primary functionality.
// 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 serial_reset_read_buffer(); // Clear serial read buffer
gc_init(); // Set g-code parser to default state gc_init(); // Set g-code parser to default state
protocol_init(); // Clear incoming line data and execute startup lines
spindle_init(); spindle_init();
coolant_init(); coolant_init();
limits_init(); limits_init();
plan_reset(); // Clear block buffer and planner variables plan_reset(); // Clear block buffer and planner variables
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.
// cleared upon startup, not a reset/abort.
plan_sync_position(); plan_sync_position();
gc_sync_position(); gc_sync_position();
@ -90,24 +81,10 @@ int main(void)
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
else { sys.auto_start = false; } else { sys.auto_start = false; }
// Check for and report alarm state after a reset, error, or an initial power up. // Start main loop. Processes inputs and executes them.
if (sys.state == STATE_ALARM) { // NOTE: Upon a system abort, the main loop returns and re-initializes the system.
report_feedback_message(MESSAGE_ALARM_LOCK); protocol_process();
} else {
// All systems go. Set system to ready and execute startup script.
sys.state = STATE_IDLE; // Clear all state flags.
protocol_execute_startup();
}
}
protocol_execute_runtime();
// When the serial protocol returns, there are no more characters in the serial read buffer to
// be processed and executed. This indicates that individual commands are being issued or
// streaming is finished. In either case, auto-cycle start, if enabled, any queued moves.
mc_auto_cycle_start();
protocol_process(); // ... process the serial protocol
} }
return 0; /* never reached */ return 0; /* Never reached */
} }

View File

@ -20,21 +20,17 @@
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 "system.h"
#include <util/delay.h>
#include <math.h>
#include <stdlib.h>
#include "settings.h" #include "settings.h"
#include "config.h" #include "protocol.h"
#include "gcode.h" #include "gcode.h"
#include "planner.h"
#include "stepper.h"
#include "motion_control.h" #include "motion_control.h"
#include "spindle_control.h" #include "spindle_control.h"
#include "coolant_control.h" #include "coolant_control.h"
#include "nuts_bolts.h"
#include "stepper.h"
#include "planner.h"
#include "limits.h" #include "limits.h"
#include "protocol.h"
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second // Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in // unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
@ -112,8 +108,8 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// Computes: mm_per_arc_segment = sqrt(4*arc_tolerance*(2*radius-arc_tolerance)), // Computes: mm_per_arc_segment = sqrt(4*arc_tolerance*(2*radius-arc_tolerance)),
// segments = millimeters_of_travel/mm_per_arc_segment // segments = millimeters_of_travel/mm_per_arc_segment
float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel)); float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
uint16_t segments = floor(millimeters_of_travel/ uint16_t segments = floor(0.5*millimeters_of_travel/
sqrt(4*settings.arc_tolerance*(2*radius - settings.arc_tolerance)) ); sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
if (segments) { if (segments) {
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated // Multiply inverse feed_rate to compensate for the fact that this movement is approximated

View File

@ -22,8 +22,6 @@
#ifndef motion_control_h #ifndef motion_control_h
#define motion_control_h #define motion_control_h
#include <avr/io.h>
#include "planner.h"
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second // Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in // unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in

View File

@ -19,10 +19,8 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <util/delay.h> #include "system.h"
#include "nuts_bolts.h"
#include "gcode.h"
#include "planner.h"
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float) #define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)

View File

@ -22,13 +22,6 @@
#ifndef nuts_bolts_h #ifndef nuts_bolts_h
#define nuts_bolts_h #define nuts_bolts_h
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "config.h"
#include "defaults.h"
#include "cpu_map.h"
#define false 0 #define false 0
#define true 1 #define true 1
@ -57,44 +50,6 @@
#define bit_istrue(x,mask) ((x & mask) != 0) #define bit_istrue(x,mask) ((x & mask) != 0)
#define bit_isfalse(x,mask) ((x & mask) == 0) #define bit_isfalse(x,mask) ((x & mask) == 0)
// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
// which notifies the main program to execute the specified runtime command asynchronously.
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
// flags are always false, so the runtime protocol only needs to check for a non-zero value to
// know when there is a runtime command to execute.
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
#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. No flags.
#define STATE_QUEUED bit(0) // Indicates buffered blocks, awaiting cycle start.
#define STATE_CYCLE bit(1) // Cycle is running
#define STATE_HOLD bit(2) // Executing feed hold
#define STATE_HOMING bit(3) // Performing homing cycle
#define STATE_ALARM bit(4) // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_CHECK_MODE bit(5) // G-code check mode. Locks out planner and motion only.
// #define STATE_JOG bit(6) // 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.
uint8_t homing_axis_lock;
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.
} system_t;
extern system_t sys;
// Read a floating point value from a string. Line points to the input buffer, char_counter // Read a floating point value from a string. Line points to the input buffer, char_counter
// is the indexer pointing to the current character of the line, while float_ptr is // is the indexer pointing to the current character of the line, while float_ptr is
// a pointer to the result variable. Returns true when it succeeds // a pointer to the result variable. Returns true when it succeeds

View File

@ -22,14 +22,12 @@
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */ /* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
#include <inttypes.h> #include "system.h"
#include <stdlib.h>
#include "planner.h" #include "planner.h"
#include "nuts_bolts.h" #include "protocol.h"
#include "stepper.h" #include "stepper.h"
#include "settings.h" #include "settings.h"
#include "config.h"
#include "protocol.h"
#define SOME_LARGE_VALUE 1.0E+38 // Used by rapids and acceleration maximization calculations. Just needs #define SOME_LARGE_VALUE 1.0E+38 // Used by rapids and acceleration maximization calculations. Just needs
// to be larger than any feasible (mm/min)^2 or mm/sec^2 value. // to be larger than any feasible (mm/min)^2 or mm/sec^2 value.

View File

@ -21,7 +21,8 @@
#ifndef planner_h #ifndef planner_h
#define planner_h #define planner_h
#include "nuts_bolts.h"
#include "system.h"
// The number of linear motions that can be in the plan at any give time // The number of linear motions that can be in the plan at any give time
#ifndef BLOCK_BUFFER_SIZE #ifndef BLOCK_BUFFER_SIZE

View File

@ -22,12 +22,11 @@
/* This code was initially inspired by the wiring_serial module by David A. Mellis which /* This code was initially inspired by the wiring_serial module by David A. Mellis which
used to be a part of the Arduino project. */ used to be a part of the Arduino project. */
#include "system.h"
#include <avr/pgmspace.h>
#include "config.h"
#include "serial.h" #include "serial.h"
#include "settings.h" #include "settings.h"
void printString(const char *s) void printString(const char *s)
{ {
while (*s) while (*s)

View File

@ -1,5 +1,5 @@
/* /*
protocol.c - the serial protocol master control unit protocol.c - controls Grbl execution procedures
Part of Grbl Part of Grbl
Copyright (c) 2011-2014 Sungeun K. Jeon Copyright (c) 2011-2014 Sungeun K. Jeon
@ -19,78 +19,19 @@
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 "system.h"
#include <avr/interrupt.h> #include "serial.h"
#include "settings.h"
#include "protocol.h" #include "protocol.h"
#include "gcode.h" #include "gcode.h"
#include "serial.h"
#include "print.h"
#include "settings.h"
#include "config.h"
#include "nuts_bolts.h"
#include "stepper.h" #include "stepper.h"
#include "report.h"
#include "motion_control.h" #include "motion_control.h"
#include "report.h"
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated. static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
static uint8_t char_counter; // Last character counter in line variable.
static uint8_t iscomment; // Comment/block delete flag for processor to ignore comment characters.
static void protocol_reset_line_buffer()
{
char_counter = 0;
iscomment = false;
}
void protocol_init()
{
protocol_reset_line_buffer(); // Reset line input
report_init_message(); // Welcome message
PINOUT_DDR &= ~(PINOUT_MASK); // Set as input pins
PINOUT_PORT |= PINOUT_MASK; // Enable internal pull-up resistors. Normal high operation.
PINOUT_PCMSK |= PINOUT_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << PINOUT_INT); // Enable Pin Change Interrupt
}
// Executes user startup script, if stored.
void protocol_execute_startup()
{
uint8_t n;
for (n=0; n < N_STARTUP_LINE; n++) {
if (!(settings_read_startup_line(n, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
if (line[0] != 0) {
printString(line); // Echo startup line to indicate execution.
report_status_message(gc_execute_line(line));
}
}
}
}
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the runtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based runtime commands when picked off
// directly from the incoming serial data stream.
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_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))) {
sys.execute |= EXEC_CYCLE_START;
}
}
}
// Executes run-time commands, when required. This is called from various check points in the main // Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any // program, primarily where there may be a while loop waiting for a buffer to clear space or any
// point where the execution time from the last check point may be more than a fraction of a second. // point where the execution time from the last check point may be more than a fraction of a second.
@ -181,163 +122,73 @@ void protocol_execute_runtime()
// Directs and executes one line of formatted input from protocol_process. While mostly // Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as // incoming streaming g-code blocks, this also directs and executes Grbl internal commands,
// settings, initiating the homing cycle, and toggling switch states. This differs from // such as settings, initiating the homing cycle, and toggling switch states.
// the runtime command module by being susceptible to when Grbl is ready to execute the // TODO: Eventually re-organize this function to more cleanly organize order of operations,
// next line during a cycle, so for switches like block delete, the switch only effects // which will hopefully reduce some of the current spaghetti logic and dynamic memory usage.
// the lines that are processed afterward, not necessarily real-time during a cycle, static void protocol_execute_line(char *line)
// since there are motions already stored in the buffer. However, this 'lag' should not
// be an issue, since these commands are not typically used during a cycle.
uint8_t protocol_execute_line(char *line)
{ {
// Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help protocol_execute_runtime(); // Runtime command check point.
if(line[0] == '$') { if (sys.abort) { return; } // Bail to calling function upon system abort
uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable uint8_t status;
float parameter, value; if (line[0] == 0) {
switch( line[char_counter] ) { // Empty or comment line. Send status message for syncing purposes.
case '#' : // Print gcode parameters status = STATUS_OK;
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_parameters(); } } else if (line[0] == '$') {
break; // Grbl '$' system command
case 'G' : // Prints gcode parser state status = system_execute_line(line);
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_modes(); }
break;
// case 'J' : break; // Jogging methods
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
// susceptible to other runtime commands except for e-stop. The jogging function is intended to
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// handled by the planner. It would be possible for the jog subprogram to insert blocks into the
// block buffer without having the planner plan them. It would need to manage de/ac-celerations
// on its own carefully. This approach could be effective and possibly size/memory efficient.
default :
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
case '$' : // Prints Grbl settings
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_grbl_settings(); }
break;
case 'C' : // Set check g-code mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent.
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else {
if (sys.state) { return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
}
break;
case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
// Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or alarm.
mc_homing_cycle();
if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
} else { return(STATUS_SETTING_DISABLED); }
break;
case 'I' : // Print or store build info.
if ( line[++char_counter] == 0 ) {
if (!(settings_read_build_info(line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_build_info(line);
}
} else { // Store startup line
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
helper_var = char_counter; // Set helper variable as counter to start of user info line.
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
settings_store_build_info(line);
}
break;
case 'N' : // Startup lines.
if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_startup_line(helper_var,line);
}
}
break;
} else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
default : // Storing setting methods
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
}
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else { } else {
return(gc_execute_line(line)); // Everything else is gcode // Everything else is gcode. Send to g-code parser!
// TODO: Separate the parsing from the g-code execution. Need to re-write the parser
// completely to do this. First parse the line completely, checking for modal group
// errors and storing all of the g-code words. Then, send the stored g-code words to
// a separate g-code executor. This will be more in-line with actual g-code protocol.
status = gc_execute_line(line);
} }
report_status_message(status);
} }
// Process and report status one line of incoming serial data. Performs an initial filtering
// by removing spaces and comments and capitalizing all letters.
void protocol_process() void protocol_process()
{ {
// ------------------------------------------------------------
// Complete initialization procedures upon a power-up or reset.
// ------------------------------------------------------------
// Print welcome message
report_init_message();
// 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!
sys.state = STATE_IDLE; // Set system to ready. Clear all state flags.
system_execute_startup(line); // Execute startup script.
}
// ------------------------------------------------------------------------------
// Main loop! Upon a system abort, this exits back to main() to reset the system.
// ------------------------------------------------------------------------------
uint8_t iscomment = false;
uint8_t char_counter = 0;
uint8_t c; uint8_t c;
for (;;) {
// Process one line of incoming serial data, as the data becomes available. Performs an
// initial filtering by removing spaces and comments and capitalizing all letters.
while((c = serial_read()) != SERIAL_NO_DATA) { while((c = serial_read()) != SERIAL_NO_DATA) {
if ((c == '\n') || (c == '\r')) { // End of line reached if ((c == '\n') || (c == '\r')) { // End of line reached
line[char_counter] = 0; // Set string termination character.
// Runtime command check point before executing line. Prevent any furthur line executions. protocol_execute_line(line); // Line is complete. Execute it!
// NOTE: If there is no line, this function should quickly return to the main program when iscomment = false;
// the buffer empties of non-executable data. char_counter = 0;
protocol_execute_runtime();
if (sys.abort) { return; } // Bail to main program upon system abort
if (char_counter > 0) {// Line is complete. Then execute!
line[char_counter] = 0; // Terminate string
report_status_message(protocol_execute_line(line));
} else {
// Empty or comment line. Skip block.
report_status_message(STATUS_OK); // Send status message for syncing purposes.
}
protocol_reset_line_buffer();
} else { } else {
if (iscomment) { if (iscomment) {
// Throw away all comment characters // Throw away all comment characters
@ -356,7 +207,8 @@ void protocol_process()
} else if (char_counter >= LINE_BUFFER_SIZE-1) { } else if (char_counter >= LINE_BUFFER_SIZE-1) {
// Detect line buffer overflow. Report error and reset line buffer. // Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW); report_status_message(STATUS_OVERFLOW);
protocol_reset_line_buffer(); iscomment = false;
char_counter = 0;
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase } else if (c >= 'a' && c <= 'z') { // Upcase lowercase
line[char_counter++] = c-'a'+'A'; line[char_counter++] = c-'a'+'A';
} else { } else {
@ -365,4 +217,16 @@ void protocol_process()
} }
} }
} }
protocol_execute_runtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to main() program loop to reset system.
// If there are no more characters in the serial read buffer to be processed and executed,
// this indicates that g-code streaming has either filled the planner buffer or has
// completed. In either case, auto-cycle start, if enabled, any queued moves.
mc_auto_cycle_start();
}
return; /* Never reached */
} }

View File

@ -1,5 +1,5 @@
/* /*
protocol.h - the serial protocol master control unit protocol.h - controls Grbl execution procedures
Part of Grbl Part of Grbl
Copyright (c) 2011-2014 Sungeun K. Jeon Copyright (c) 2011-2014 Sungeun K. Jeon
@ -21,32 +21,21 @@
#ifndef protocol_h #ifndef protocol_h
#define protocol_h #define protocol_h
#include <avr/sleep.h>
// Line buffer size from the serial input stream to be executed. // Line buffer size from the serial input stream to be executed.
// NOTE: Not a problem except for extreme cases, but the line buffer size can be too small // NOTE: Not a problem except for extreme cases, but the line buffer size can be too small
// and g-code blocks can get truncated. Officially, the g-code standards support up to 256 // and g-code blocks can get truncated. Officially, the g-code standards support up to 256
// characters. In future versions, this will be increased, when we know how much extra // characters. In future versions, this will be increased, when we know how much extra
// memory space we can invest into here or we re-write the g-code parser not to have his // memory space we can invest into here or we re-write the g-code parser not to have this
// buffer. // buffer.
#ifndef LINE_BUFFER_SIZE #ifndef LINE_BUFFER_SIZE
#define LINE_BUFFER_SIZE 70 #define LINE_BUFFER_SIZE 70
#endif #endif
// Initialize the serial protocol
void protocol_init();
// Read command lines from the serial port and execute them as they
// come in. Blocks until the serial buffer is emptied.
void protocol_process();
// Executes one line of input according to protocol
uint8_t protocol_execute_line(char *line);
// Checks and executes a runtime command at various stop points in main program // Checks and executes a runtime command at various stop points in main program
void protocol_execute_runtime(); void protocol_execute_runtime();
// Execute the startup script lines stored in EEPROM upon initialization // Starts Grbl main loop. It handles all incoming characters from the serial port and executes
void protocol_execute_startup(); // them as they complete. It is also responsible for finishing the initialization procedures.
void protocol_process();
#endif #endif

View File

@ -26,11 +26,10 @@
methods to accomodate their needs. methods to accomodate their needs.
*/ */
#include <avr/pgmspace.h> #include "system.h"
#include "report.h" #include "report.h"
#include "print.h" #include "print.h"
#include "settings.h" #include "settings.h"
#include "nuts_bolts.h"
#include "gcode.h" #include "gcode.h"
#include "coolant_control.h" #include "coolant_control.h"
@ -163,9 +162,9 @@ void report_grbl_settings() {
printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); printInteger(settings.pulse_microseconds); printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); printFloat(settings.default_feed_rate); printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.step_invert_mask); printPgmString(PSTR(" (default feed, mm/min)\r\n$14=")); printInteger(settings.step_invert_mask);
printPgmString(PSTR(" (step port invert mask, int:")); print_uint8_base2(settings.step_invert_mask); printPgmString(PSTR(" (step port invert mask:")); print_uint8_base2(settings.step_invert_mask);
printPgmString(PSTR(")\r\n$15=")); printInteger(settings.dir_invert_mask); printPgmString(PSTR(")\r\n$15=")); printInteger(settings.dir_invert_mask);
printPgmString(PSTR(" (dir port invert mask, int:")); print_uint8_base2(settings.dir_invert_mask); printPgmString(PSTR(" (dir port invert mask:")); print_uint8_base2(settings.dir_invert_mask);
printPgmString(PSTR(")\r\n$16=")); printInteger(settings.stepper_idle_lock_time); printPgmString(PSTR(")\r\n$16=")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (step idle delay, msec)\r\n$17=")); printFloat(settings.junction_deviation); printPgmString(PSTR(" (step idle delay, msec)\r\n$17=")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (junction deviation, mm)\r\n$18=")); printFloat(settings.arc_tolerance); printPgmString(PSTR(" (junction deviation, mm)\r\n$18=")); printFloat(settings.arc_tolerance);
@ -178,7 +177,7 @@ void report_grbl_settings() {
printPgmString(PSTR(" (soft limits, bool)\r\n$25=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); printPgmString(PSTR(" (soft limits, bool)\r\n$25=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$26=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); printPgmString(PSTR(" (hard limits, bool)\r\n$26=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$27=")); printInteger(settings.homing_dir_mask); printPgmString(PSTR(" (homing cycle, bool)\r\n$27=")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing dir invert mask, int:")); print_uint8_base2(settings.homing_dir_mask); printPgmString(PSTR(" (homing dir invert mask:")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$28=")); printFloat(settings.homing_feed_rate); printPgmString(PSTR(")\r\n$28=")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$29=")); printFloat(settings.homing_seek_rate); printPgmString(PSTR(" (homing feed, mm/min)\r\n$29=")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$30=")); printInteger(settings.homing_debounce_delay); printPgmString(PSTR(" (homing seek, mm/min)\r\n$30=")); printInteger(settings.homing_debounce_delay);

View File

@ -23,11 +23,12 @@
used to be a part of the Arduino project. */ used to be a part of the Arduino project. */
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include "system.h"
#include "serial.h" #include "serial.h"
#include "config.h"
#include "motion_control.h" #include "motion_control.h"
#include "protocol.h" #include "protocol.h"
uint8_t rx_buffer[RX_BUFFER_SIZE]; uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_buffer_head = 0; uint8_t rx_buffer_head = 0;
volatile uint8_t rx_buffer_tail = 0; volatile uint8_t rx_buffer_tail = 0;
@ -36,6 +37,7 @@ uint8_t tx_buffer[TX_BUFFER_SIZE];
uint8_t tx_buffer_head = 0; uint8_t tx_buffer_head = 0;
volatile uint8_t tx_buffer_tail = 0; volatile uint8_t tx_buffer_tail = 0;
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
@ -49,6 +51,7 @@ volatile uint8_t tx_buffer_tail = 0;
} }
#endif #endif
void serial_init() void serial_init()
{ {
// Set baud rate // Set baud rate
@ -72,6 +75,7 @@ void serial_init()
// defaults to 8-bit, no parity, 1 stop bit // defaults to 8-bit, no parity, 1 stop bit
} }
void serial_write(uint8_t data) { void serial_write(uint8_t data) {
// Calculate next head // Calculate next head
uint8_t next_head = tx_buffer_head + 1; uint8_t next_head = tx_buffer_head + 1;
@ -90,6 +94,7 @@ void serial_write(uint8_t data) {
UCSR0B |= (1 << UDRIE0); UCSR0B |= (1 << UDRIE0);
} }
// Data Register Empty Interrupt handler // Data Register Empty Interrupt handler
ISR(SERIAL_UDRE) ISR(SERIAL_UDRE)
{ {
@ -119,6 +124,7 @@ ISR(SERIAL_UDRE)
if (tail == tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); } if (tail == tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
} }
uint8_t serial_read() uint8_t serial_read()
{ {
uint8_t tail = rx_buffer_tail; // Temporary rx_buffer_tail (to optimize for volatile) uint8_t tail = rx_buffer_tail; // Temporary rx_buffer_tail (to optimize for volatile)
@ -142,6 +148,7 @@ uint8_t serial_read()
} }
} }
ISR(SERIAL_RX) ISR(SERIAL_RX)
{ {
uint8_t data = UDR0; uint8_t data = UDR0;
@ -174,6 +181,7 @@ ISR(SERIAL_RX)
} }
} }
void serial_reset_read_buffer() void serial_reset_read_buffer()
{ {
rx_buffer_tail = rx_buffer_head; rx_buffer_tail = rx_buffer_head;

View File

@ -25,7 +25,6 @@
#ifndef serial_h #ifndef serial_h
#define serial_h #define serial_h
#include "nuts_bolts.h"
#ifndef RX_BUFFER_SIZE #ifndef RX_BUFFER_SIZE
#define RX_BUFFER_SIZE 128 #define RX_BUFFER_SIZE 128

View File

@ -19,29 +19,15 @@
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 "system.h"
#include "protocol.h"
#include "report.h"
#include "stepper.h"
#include "nuts_bolts.h"
#include "settings.h" #include "settings.h"
#include "eeprom.h" #include "eeprom.h"
#include "protocol.h"
#include "report.h"
#include "limits.h" #include "limits.h"
settings_t settings; settings_t settings;
// Version 4 outdated settings record
typedef struct {
float steps_per_mm[N_AXIS];
uint8_t microsteps;
uint8_t pulse_microseconds;
float default_feed_rate;
uint8_t invert_mask;
float mm_per_arc_segment;
float acceleration;
float junction_deviation;
} settings_v4_t;
// Method to store startup lines into EEPROM // Method to store startup lines into EEPROM
void settings_store_startup_line(uint8_t n, char *line) void settings_store_startup_line(uint8_t n, char *line)
@ -50,12 +36,14 @@ void settings_store_startup_line(uint8_t n, char *line)
memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE); memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
} }
// Method to store build info into EEPROM // Method to store build info into EEPROM
void settings_store_build_info(char *line) void settings_store_build_info(char *line)
{ {
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_BUILD_INFO,(char*)line, LINE_BUFFER_SIZE); memcpy_to_eeprom_with_checksum(EEPROM_ADDR_BUILD_INFO,(char*)line, LINE_BUFFER_SIZE);
} }
// Method to store coord data parameters into EEPROM // Method to store coord data parameters into EEPROM
void settings_write_coord_data(uint8_t coord_select, float *coord_data) void settings_write_coord_data(uint8_t coord_select, float *coord_data)
{ {
@ -63,6 +51,7 @@ void settings_write_coord_data(uint8_t coord_select, float *coord_data)
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS); 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 // Method to store Grbl global settings struct and version number into EEPROM
void write_global_settings() void write_global_settings()
{ {
@ -70,10 +59,9 @@ void write_global_settings()
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t)); memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
} }
// Method to reset Grbl global settings back to defaults. // Method to reset Grbl global settings back to defaults.
void settings_reset(bool reset_all) { void settings_reset() {
// Reset all settings or only the migration settings to the new version.
if (reset_all) {
settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM; settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM; settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM; settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
@ -89,8 +77,6 @@ void settings_reset(bool reset_all) {
settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK; settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK;
settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK; settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK;
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
}
// New settings since last version
settings.flags = 0; settings.flags = 0;
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; } if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; } if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
@ -112,13 +98,14 @@ void settings_reset(bool reset_all) {
write_global_settings(); write_global_settings();
} }
// Reads startup line from EEPROM. Updated pointed line string data. // Reads startup line from EEPROM. Updated pointed line string data.
uint8_t settings_read_startup_line(uint8_t n, char *line) uint8_t settings_read_startup_line(uint8_t n, char *line)
{ {
uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK; uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) { if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
// Reset line with default value // Reset line with default value
line[0] = 0; line[0] = 0; // Empty line
settings_store_startup_line(n, line); settings_store_startup_line(n, line);
return(false); return(false);
} else { } else {
@ -126,12 +113,13 @@ uint8_t settings_read_startup_line(uint8_t n, char *line)
} }
} }
// Reads startup line from EEPROM. Updated pointed line string data. // Reads startup line from EEPROM. Updated pointed line string data.
uint8_t settings_read_build_info(char *line) uint8_t settings_read_build_info(char *line)
{ {
if (!(memcpy_from_eeprom_with_checksum((char*)line, EEPROM_ADDR_BUILD_INFO, LINE_BUFFER_SIZE))) { if (!(memcpy_from_eeprom_with_checksum((char*)line, EEPROM_ADDR_BUILD_INFO, LINE_BUFFER_SIZE))) {
// Reset line with default value // Reset line with default value
line[0] = 0; line[0] = 0; // Empty line
settings_store_build_info(line); settings_store_build_info(line);
return(false); return(false);
} else { } else {
@ -139,6 +127,7 @@ uint8_t settings_read_build_info(char *line)
} }
} }
// Read selected coordinate data from EEPROM. Updates pointed coord_data value. // Read selected coordinate data from EEPROM. Updates pointed coord_data value.
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data) uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
{ {
@ -153,36 +142,28 @@ uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
} }
} }
// Reads Grbl global settings struct from EEPROM. // Reads Grbl global settings struct from EEPROM.
uint8_t read_global_settings() { uint8_t read_global_settings() {
// Check version-byte of eeprom // Check version-byte of eeprom
uint8_t version = eeprom_get_char(0); uint8_t version = eeprom_get_char(0);
if (version == SETTINGS_VERSION) { if (version == SETTINGS_VERSION) {
// Read settings-record and check checksum // Read settings-record and check checksum
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) { if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
return(false); return(false);
} }
} else { } else {
if (version <= 4) {
// Migrate from settings version 4 to current version.
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v4_t)))) {
return(false); return(false);
} }
settings_reset(false); // Old settings ok. Write new settings only.
} else {
return(false);
}
}
return(true); return(true);
} }
// A helper method to set settings from command line // A helper method to set settings from command line
uint8_t settings_store_global_setting(int parameter, float value) { uint8_t settings_store_global_setting(int parameter, float value) {
if (value < 0.0) { return(STATUS_SETTING_VALUE_NEG); }
switch(parameter) { switch(parameter) {
case 0: case 1: case 2: case 0: case 1: case 2:
if (value <= 0.0) { return(STATUS_SETTING_VALUE_NEG); }
settings.steps_per_mm[parameter] = value; break; settings.steps_per_mm[parameter] = value; break;
case 3: settings.max_rate[X_AXIS] = value; break; case 3: settings.max_rate[X_AXIS] = value; break;
case 4: settings.max_rate[Y_AXIS] = value; break; case 4: settings.max_rate[Y_AXIS] = value; break;
@ -249,11 +230,12 @@ uint8_t settings_store_global_setting(int parameter, float value) {
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();
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.

View File

@ -22,15 +22,15 @@
#ifndef settings_h #ifndef settings_h
#define settings_h #define settings_h
#include <math.h> #include "system.h"
#include "nuts_bolts.h"
#define GRBL_VERSION "0.9c" #define GRBL_VERSION "0.9c"
#define GRBL_VERSION_BUILD "20131231" #define GRBL_VERSION_BUILD "20140110"
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl // Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl
// when firmware is upgraded. Always stored in byte 0 of eeprom // when firmware is upgraded. Always stored in byte 0 of eeprom
#define SETTINGS_VERSION 57 #define SETTINGS_VERSION 6
// Define bit flag masks for the boolean settings in settings.flag. // Define bit flag masks for the boolean settings in settings.flag.
#define BITFLAG_REPORT_INCHES bit(0) #define BITFLAG_REPORT_INCHES bit(0)

View File

@ -19,17 +19,13 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "settings.h" #include "system.h"
#include "spindle_control.h" #include "spindle_control.h"
#include "planner.h" #include "planner.h"
static uint8_t current_direction;
static uint16_t current_rpm;
void spindle_init() void spindle_init()
{ {
current_direction = 0;
SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT);
// On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin. // On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin.
@ -60,22 +56,31 @@ void spindle_stop()
} }
void spindle_run(int8_t direction, uint16_t rpm) void spindle_run(uint8_t direction, float rpm)
{ {
if ((direction != current_direction) || (rpm != current_rpm)) { // Empty planner buffer to ensure spindle is set when programmed.
plan_synchronize(); // Empty planner buffer to ensure spindle is updated as programmed. plan_synchronize();
if (direction) {
if (direction > 0) { // Halt or set spindle direction and rpm.
if (direction == SPINDLE_DISABLE) {
spindle_stop();
} else {
if (direction == SPINDLE_ENABLE_CW) {
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT); SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
} else { } else {
SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT); SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
} }
#ifdef VARIABLE_SPINDLE #ifdef VARIABLE_SPINDLE
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER); TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
if (rpm > SPINDLE_MAX_RPM) { rpm = SPINDLE_MAX_RPM; } // Prevent overflow. rpm -= SPINDLE_MIN_RPM;
uint8_t current_pwm = floor((((float) rpm / (float) SPINDLE_MAX_RPM ) * 255.0) + 0.5); if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow
uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5);
OCR_REGISTER = current_pwm; OCR_REGISTER = current_pwm;
#ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared. #ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared.
@ -85,10 +90,5 @@ void spindle_run(int8_t direction, uint16_t rpm)
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif #endif
} else {
spindle_stop();
}
current_direction = direction;
current_rpm = rpm;
} }
} }

View File

@ -22,13 +22,17 @@
#ifndef spindle_control_h #ifndef spindle_control_h
#define spindle_control_h #define spindle_control_h
#include <avr/io.h>
#define SPINDLE_DISABLE 0 // Must be zero.
#define SPINDLE_ENABLE_CW 1
#define SPINDLE_ENABLE_CCW 2
// Initializes spindle pins and hardware PWM, if enabled. // Initializes spindle pins and hardware PWM, if enabled.
void spindle_init(); void spindle_init();
// Sets spindle direction and spindle rpm via PWM, if enabled. // Sets spindle direction and spindle rpm via PWM, if enabled.
void spindle_run(int8_t direction, uint16_t rpm); void spindle_run(uint8_t direction, float rpm);
// Kills spindle. // Kills spindle.
void spindle_stop(); void spindle_stop();

View File

@ -19,12 +19,11 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <avr/interrupt.h> #include "system.h"
#include "nuts_bolts.h"
#include "stepper.h" #include "stepper.h"
#include "config.h"
#include "settings.h" #include "settings.h"
#include "planner.h" #include "planner.h"
#include "nuts_bolts.h"
// Some useful constants. // Some useful constants.
@ -43,7 +42,7 @@
// NOTE: Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead // NOTE: Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead
// and timer accuracy. Do not alter these settings unless you know what you are doing. // and timer accuracy. Do not alter these settings unless you know what you are doing.
#define MAX_AMASS_LEVEL 3 #define MAX_AMASS_LEVEL 3
// AMASS_LEVEL0: Normal operation. No AMASS. No upper cutoff frequency. // AMASS_LEVEL0: Normal operation. No AMASS. No upper cutoff frequency. Starts at LEVEL1 cutoff frequency.
#define AMASS_LEVEL1 (F_CPU/8000) // Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz) #define AMASS_LEVEL1 (F_CPU/8000) // Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz)
#define AMASS_LEVEL2 (F_CPU/4000) // Over-drives ISR (x4) #define AMASS_LEVEL2 (F_CPU/4000) // Over-drives ISR (x4)
#define AMASS_LEVEL3 (F_CPU/2000) // Over-drives ISR (x8) #define AMASS_LEVEL3 (F_CPU/2000) // Over-drives ISR (x8)
@ -182,12 +181,10 @@ static st_prep_t prep;
// enabled. Startup init and limits call this function but shouldn't start the cycle. // enabled. Startup init and limits call this function but shouldn't start the cycle.
void st_wake_up() void st_wake_up()
{ {
// Enable steppers by resetting the stepper disable port // Enable stepper drivers.
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }
} else {
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
}
if (sys.state & (STATE_CYCLE | STATE_HOMING)){ if (sys.state & (STATE_CYCLE | STATE_HOMING)){
// Initialize stepper output bits // Initialize stepper output bits
st.dir_outbits = settings.dir_invert_mask; st.dir_outbits = settings.dir_invert_mask;
@ -218,17 +215,17 @@ void st_go_idle()
TIMSK1 &= ~(1<<OCIE1A); TIMSK1 &= ~(1<<OCIE1A);
busy = false; busy = false;
// Disable steppers only upon system alarm activated or by user setting to not be kept enabled. // Set stepper driver idle state, disabled or enabled, depending on settings and circumstances.
bool pin_state = false;
if (((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) && sys.state != STATE_HOMING) { if (((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) && sys.state != STATE_HOMING) {
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete // Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
// stop and not drift from residual inertial forces at the end of the last movement. // stop and not drift from residual inertial forces at the end of the last movement.
delay_ms(settings.stepper_idle_lock_time); delay_ms(settings.stepper_idle_lock_time);
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = true;
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
} else {
STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
}
} }
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = !pin_state; }
if (pin_state) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }
else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }
} }
@ -429,11 +426,14 @@ void st_reset()
segment_buffer_head = 0; // empty = tail segment_buffer_head = 0; // empty = tail
segment_next_head = 1; segment_next_head = 1;
busy = false; busy = false;
// Initialize stepper driver idle state.
st_go_idle();
} }
// Initialize and start the stepper motor subsystem // Initialize and start the stepper motor subsystem
void st_init() void stepper_init()
{ {
// Configure step and direction interface pins // Configure step and direction interface pins
STEPPING_DDR |= STEP_MASK; STEPPING_DDR |= STEP_MASK;
@ -450,6 +450,7 @@ void st_init()
TCCR1A &= ~(3<<COM1A0); // output mode = 00 (disconnected) TCCR1A &= ~(3<<COM1A0); // output mode = 00 (disconnected)
TCCR1A &= ~(3<<COM1B0); TCCR1A &= ~(3<<COM1B0);
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (1<<CS10); TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (1<<CS10);
// TIMSK1 &= ~(1<<OCIE1A); // Timer 1 disabled in st_go_idle().
// Configure Timer 0: Stepper Port Reset Interrupt // Configure Timer 0: Stepper Port Reset Interrupt
TIMSK0 &= ~(1<<TOIE0); TIMSK0 &= ~(1<<TOIE0);
@ -459,10 +460,6 @@ void st_init()
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
TIMSK0 |= (1<<OCIE0A); // Enable Timer0 Compare Match A interrupt TIMSK0 |= (1<<OCIE0A); // Enable Timer0 Compare Match A interrupt
#endif #endif
// Start in the idle state, but first wake up to check for keep steppers enabled option.
st_wake_up();
st_go_idle();
} }
@ -666,8 +663,8 @@ void st_prep_buffer()
the end of planner block (typical) or mid-block at the end of a forced deceleration, the end of planner block (typical) or mid-block at the end of a forced deceleration,
such as from a feed hold. such as from a feed hold.
*/ */
float dt_max = DT_SEGMENT; float dt_max = DT_SEGMENT; // Set maximum segment time
float dt = 0.0; float dt = 0.0; // Initialize segment time
float mm_remaining = pl_block->millimeters; float mm_remaining = pl_block->millimeters;
float time_var = dt_max; // Time worker variable float time_var = dt_max; // Time worker variable
float mm_var; // mm-Distance worker variable float mm_var; // mm-Distance worker variable
@ -676,8 +673,8 @@ void st_prep_buffer()
switch (prep.ramp_type) { switch (prep.ramp_type) {
case RAMP_ACCEL: case RAMP_ACCEL:
// NOTE: Acceleration ramp only computes during first do-while loop. // NOTE: Acceleration ramp only computes during first do-while loop.
speed_var = pl_block->acceleration*dt_max; speed_var = pl_block->acceleration*time_var;
mm_remaining -= dt_max*(prep.current_speed + 0.5*speed_var); mm_remaining -= time_var*(prep.current_speed + 0.5*speed_var);
if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp. if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp.
// Acceleration-cruise, acceleration-deceleration ramp junction, or end of block. // Acceleration-cruise, acceleration-deceleration ramp junction, or end of block.
mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB
@ -718,10 +715,14 @@ void st_prep_buffer()
} }
dt += time_var; // Add computed ramp time to total segment time. dt += time_var; // Add computed ramp time to total segment time.
if (dt < dt_max) { time_var = dt_max - dt; } // **Incomplete** At ramp junction. if (dt < dt_max) { time_var = dt_max - dt; } // **Incomplete** At ramp junction.
else if (mm_remaining > prep.minimum_mm) { // Check for slow segments with zero steps. else {
if (mm_remaining > prep.minimum_mm) { // Check for slow segments with zero steps.
dt_max += DT_SEGMENT; // Increase segment time to ensure at least one step in segment. dt_max += DT_SEGMENT; // Increase segment time to ensure at least one step in segment.
time_var = dt_max - dt; time_var = dt_max - dt;
} else { break; } // **Complete** Exit loop. Segment execution time maxed. } else {
break; // **Complete** Exit loop. Segment execution time maxed.
}
}
} while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete. } while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete.
/* ----------------------------------------------------------------------------------- /* -----------------------------------------------------------------------------------
@ -745,7 +746,7 @@ void st_prep_buffer()
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
// Compute step timing and multi-axis smoothing level. // Compute step timing and multi-axis smoothing level.
// NOTE: Only one prescalar is required with AMASS enabled. // NOTE: AMASS overdrives the timer with each level, so only one prescalar is required.
if (cycles < AMASS_LEVEL1) { prep_segment->amass_level = 0; } if (cycles < AMASS_LEVEL1) { prep_segment->amass_level = 0; }
else { else {
if (cycles < AMASS_LEVEL2) { prep_segment->amass_level = 1; } if (cycles < AMASS_LEVEL2) { prep_segment->amass_level = 1; }

View File

@ -27,7 +27,7 @@
#endif #endif
// Initialize and setup the stepper motor subsystem // Initialize and setup the stepper motor subsystem
void st_init(); void stepper_init();
// Enable steppers, but cycle does not start unless called by motion control or runtime command. // Enable steppers, but cycle does not start unless called by motion control or runtime command.
void st_wake_up(); void st_wake_up();
@ -47,7 +47,7 @@ void st_cycle_reinitialize();
// Initiates a feed hold of the running program // Initiates a feed hold of the running program
void st_feed_hold(); void st_feed_hold();
// Reloads step segment buffer. Called continuously by runtime execution protocol. // Reloads step segment buffer. Called continuously by runtime execution system.
void st_prep_buffer(); void st_prep_buffer();
// Called by planner_recalculate() when the executing block is updated by the new plan. // Called by planner_recalculate() when the executing block is updated by the new plan.

200
system.c Normal file
View File

@ -0,0 +1,200 @@
/*
system.c - Handles system level commands and real-time processes
Part of Grbl
Copyright (c) 2014 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "settings.h"
#include "gcode.h"
#include "motion_control.h"
#include "report.h"
#include "print.h"
void system_init()
{
PINOUT_DDR &= ~(PINOUT_MASK); // Set as input pins
PINOUT_PORT |= PINOUT_MASK; // Enable internal pull-up resistors. Normal high operation.
PINOUT_PCMSK |= PINOUT_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << PINOUT_INT); // Enable Pin Change Interrupt
}
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the runtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based runtime commands when picked off
// directly from the incoming serial data stream.
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_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))) {
sys.execute |= EXEC_CYCLE_START;
}
}
}
// Executes user startup script, if stored.
void system_execute_startup(char *line)
{
uint8_t n;
for (n=0; n < N_STARTUP_LINE; n++) {
if (!(settings_read_startup_line(n, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
if (line[0] != 0) {
printString(line); // Echo startup line to indicate execution.
report_status_message(gc_execute_line(line));
}
}
}
}
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
// the runtime command module by being susceptible to when Grbl is ready to execute the
// next line during a cycle, so for switches like block delete, the switch only effects
// the lines that are processed afterward, not necessarily real-time during a cycle,
// since there are motions already stored in the buffer. However, this 'lag' should not
// be an issue, since these commands are not typically used during a cycle.
uint8_t system_execute_line(char *line)
{
uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable
float parameter, value;
switch( line[char_counter] ) {
case '#' : // Print gcode parameters
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_parameters(); }
break;
case 'G' : // Prints gcode parser state
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_gcode_modes(); }
break;
// case 'J' : break; // Jogging methods
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
// susceptible to other runtime commands except for e-stop. The jogging function is intended to
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// handled by the planner. It would be possible for the jog subprogram to insert blocks into the
// block buffer without having the planner plan them. It would need to manage de/ac-celerations
// on its own carefully. This approach could be effective and possibly size/memory efficient.
default :
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
case '$' : // Prints Grbl settings
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
else { report_grbl_settings(); }
break;
case 'C' : // Set check g-code mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
// Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent.
if ( sys.state == STATE_CHECK_MODE ) {
mc_reset();
report_feedback_message(MESSAGE_DISABLED);
} else {
if (sys.state) { return(STATUS_IDLE_ERROR); }
sys.state = STATE_CHECK_MODE;
report_feedback_message(MESSAGE_ENABLED);
}
break;
case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
// Don't run startup script. Prevents stored moves in startup from causing accidents.
}
break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost.
mc_homing_cycle();
if (!sys.abort) { system_execute_startup(line); } // Execute startup scripts after successful homing.
} else { return(STATUS_SETTING_DISABLED); }
break;
case 'I' : // Print or store build info.
if ( line[++char_counter] == 0 ) {
if (!(settings_read_build_info(line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_build_info(line);
}
} else { // Store startup line
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
helper_var = char_counter; // Set helper variable as counter to start of user info line.
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
settings_store_build_info(line);
}
break;
case 'N' : // Startup lines.
if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_startup_line(helper_var,line);
}
}
break;
} else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
default : // Storing setting methods
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
}
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
}

95
system.h Normal file
View File

@ -0,0 +1,95 @@
/*
system.h - Header for system level commands and real-time processes
Part of Grbl
Copyright (c) 2014 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef system_h
#define system_h
// Define system header files and standard libraries used by Grbl
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <math.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
// Define Grbl configuration and shared header files
#include "config.h"
#include "defaults.h"
#include "cpu_map.h"
#include "nuts_bolts.h"
// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
// which notifies the main program to execute the specified runtime command asynchronously.
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
// flags are always false, so the runtime protocol only needs to check for a non-zero value to
// know when there is a runtime command to execute.
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
#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. No flags.
#define STATE_QUEUED bit(0) // Indicates buffered blocks, awaiting cycle start.
#define STATE_CYCLE bit(1) // Cycle is running
#define STATE_HOLD bit(2) // Executing feed hold
#define STATE_HOMING bit(3) // Performing homing cycle
#define STATE_ALARM bit(4) // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_CHECK_MODE bit(5) // G-code check mode. Locks out planner and motion only.
// #define STATE_JOG bit(6) // 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.
uint8_t homing_axis_lock;
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.
} system_t;
extern system_t sys;
// Initialize the serial protocol
void system_init();
// Executes an internal system command, defined as a string starting with a '$'
uint8_t system_execute_line(char *line);
// Checks and executes a runtime command at various stop points in main program
void system_execute_runtime();
// Execute the startup script lines stored in EEPROM upon initialization
void system_execute_startup(char *line);
#endif