Major g-code parser overhaul. 100%* compliant. Other related updates.

- Completely overhauled the g-code parser. It’s now 100%* compliant. (*
may have some bugs). Being compliant, here are some of the major
differences.

- SMALLER and JUST AS FAST! A number of optimizations were found that
sped things up and allowed for the more thorough error-checking to be
installed without a speed hit. Trimmed a lot of ‘fat’ in the parser and
still was able to make it significantly smaller than it was.

- No default feed rate setting! Removed completely! This doesn’t exist
in the g-code standard. So, it now errors out whenever it’s undefined
for motions that require it (G1/2/3/38.2).

- Any g-code parser error expunges the ENTIRE block. This means all
information is lost and not passed on to the running state. Before some
of the states would remain, which could have led to some problems.

- If the g-code block passes all of the error-checks, the g-code state
is updated and all motions are executed according to the order of
execution.

- Changes in spindle speed, when already running, will update the
output pin accordingly. This fixes a bug, where it wouldn’t update the
speed.

- Update g-code parser error reporting. Errors now return detailed
information of what exact went wrong. The most common errors return a
short text description. For less common errors, the parser reports
‘Invalid gcode ID:20’, where 20 is a error ID. A list of error code IDs
and their descriptions will be documented for user reference elsewhere
to save flash space.

- Other notable changes:

- Added a print integer routine for uint8 variables. This saved
significant flash space by switching from a heavier universal print
integer routine.

- Saved some flash space with our own short hypotenuse calculation

- Some arc computation flash and memory optimizations.
This commit is contained in:
Sonny Jeon 2014-05-25 16:05:28 -06:00
parent 06432c9de9
commit 532c359a11
22 changed files with 1162 additions and 741 deletions

View File

@ -29,7 +29,7 @@
#define config_h
// Default settings. Used when resetting EEPROM. Change to desired name in defaults.h
#define DEFAULTS_SHERLINE_5400
#define DEFAULTS_GENERIC
// Serial baud rate
#define BAUD_RATE 115200

View File

@ -21,6 +21,7 @@
#include "system.h"
#include "coolant_control.h"
#include "protocol.h"
#include "gcode.h"
void coolant_init()
@ -44,6 +45,8 @@ void coolant_stop()
void coolant_run(uint8_t mode)
{
if (sys.state != STATE_CHECK_MODE) { return; }
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
if (mode == COOLANT_FLOOD_ENABLE) {
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);

View File

@ -22,11 +22,6 @@
#define coolant_control_h
#define COOLANT_MIST_ENABLE 2
#define COOLANT_FLOOD_ENABLE 1
#define COOLANT_DISABLE 0 // Must be zero.
void coolant_init();
void coolant_stop();
void coolant_run(uint8_t mode);

View File

@ -42,7 +42,6 @@
#define DEFAULT_Y_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 250.0 // mm/min
#define DEFAULT_STEPPING_INVERT_MASK 0
#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)
@ -82,7 +81,6 @@
#define DEFAULT_Y_MAX_TRAVEL 125.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 170.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 254.0 // mm/min (10 ipm)
#define DEFAULT_STEPPING_INVERT_MASK 0
#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)
@ -125,7 +123,6 @@
#define DEFAULT_Y_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 250.0
#define DEFAULT_STEPPING_INVERT_MASK 0
#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)
@ -158,17 +155,16 @@
#define DEFAULT_X_STEPS_PER_MM (MICROSTEPS_XY*STEP_REVS_XY/MM_PER_REV_XY)
#define DEFAULT_Y_STEPS_PER_MM (MICROSTEPS_XY*STEP_REVS_XY/MM_PER_REV_XY)
#define DEFAULT_Z_STEPS_PER_MM (MICROSTEPS_Z*STEP_REVS_Z/MM_PER_REV_Z)
#define DEFAULT_X_MAX_RATE 800.0 // mm/min
#define DEFAULT_Y_MAX_RATE 800.0 // mm/min
#define DEFAULT_Z_MAX_RATE 800.0 // mm/min
#define DEFAULT_X_ACCELERATION (15.0*60*60) // 15*60*60 mm/min^2 = 15 mm/sec^2
#define DEFAULT_Y_ACCELERATION (15.0*60*60) // 15*60*60 mm/min^2 = 15 mm/sec^2
#define DEFAULT_Z_ACCELERATION (15.0*60*60) // 15*60*60 mm/min^2 = 15 mm/sec^2
#define DEFAULT_X_MAX_RATE 500.0 // mm/min
#define DEFAULT_Y_MAX_RATE 500.0 // mm/min
#define DEFAULT_Z_MAX_RATE 500.0 // mm/min
#define DEFAULT_X_ACCELERATION (25.0*60*60) // 25*60*60 mm/min^2 = 25 mm/sec^2
#define DEFAULT_Y_ACCELERATION (25.0*60*60) // 25*60*60 mm/min^2 = 25 mm/sec^2
#define DEFAULT_Z_ACCELERATION (25.0*60*60) // 25*60*60 mm/min^2 = 25 mm/sec^2
#define DEFAULT_X_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Y_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 250.0
#define DEFAULT_STEPPING_INVERT_MASK 0
#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)
@ -209,7 +205,6 @@
#define DEFAULT_Y_MAX_TRAVEL 180.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 150.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_FEEDRATE 1000.0 // mm/min
#define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)

1173
gcode.c

File diff suppressed because it is too large Load Diff

167
gcode.h
View File

@ -29,68 +29,151 @@
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
#define MODAL_GROUP_NONE 0
#define MODAL_GROUP_0 1 // [G4,G10,G28,G30,G53,G92,G92.1] Non-modal
#define MODAL_GROUP_1 2 // [G0,G1,G2,G3,G38.2,G80] Motion
#define MODAL_GROUP_2 3 // [G17,G18,G19] Plane selection
#define MODAL_GROUP_3 4 // [G90,G91] Distance mode
#define MODAL_GROUP_4 5 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_5 6 // [G93,G94] Feed rate mode
#define MODAL_GROUP_6 7 // [G20,G21] Units
#define MODAL_GROUP_7 8 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_8 9 // [M7,M8,M9] Coolant control
#define MODAL_GROUP_12 10 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
// NOTE: Modal group define values must be sequential and starting from zero.
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G80] Motion
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
#define MODAL_GROUP_G5 4 // [G93,G94] Feed rate mode
#define MODAL_GROUP_G6 5 // [G20,G21] Units
#define MODAL_GROUP_G12 6 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
#define MODAL_GROUP_M4 7 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_M7 8 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_M8 9 // [M7,M8,M9] Coolant control
#define OTHER_INPUT_F 10
#define OTHER_INPUT_S 11
#define OTHER_INPUT_T 12
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
#define MOTION_MODE_SEEK 0 // G0
#define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3
#define MOTION_MODE_PROBE 4 // G38.x
#define MOTION_MODE_CANCEL 5 // G80
#define PROGRAM_FLOW_RUNNING 0
#define PROGRAM_FLOW_PAUSED 1 // M0, M1
#define PROGRAM_FLOW_COMPLETED 2 // M2, M30
#define NON_MODAL_NONE 0
// Modal Group 0: Non-modal actions
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
#define NON_MODAL_DWELL 1 // G4
#define NON_MODAL_SET_COORDINATE_DATA 2 // G10
#define NON_MODAL_GO_HOME_0 3 // G28
#define NON_MODAL_SET_HOME_0 4 // G28.1
#define NON_MODAL_GO_HOME_1 5 // G30
#define NON_MODAL_SET_HOME_1 6 // G30.1
#define NON_MODAL_SET_COORDINATE_OFFSET 7 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1
#define NON_MODAL_ABSOLUTE_OVERRIDE 7 // G53
#define NON_MODAL_SET_COORDINATE_OFFSET 8 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 9 //G92.1
// Modal Group 1: Motion modes
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
#define MOTION_MODE_LINEAR 1 // G1
#define MOTION_MODE_CW_ARC 2 // G2
#define MOTION_MODE_CCW_ARC 3 // G3
#define MOTION_MODE_PROBE 4 // G38.2
#define MOTION_MODE_NONE 5 // G80
// Modal Group 2: Plane select
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
#define PLANE_SELECT_ZX 1 // G18
#define PLANE_SELECT_YZ 2 // G19
// Modal Group 3: Distance mode
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
#define DISTANCE_MODE_INCREMENTAL 1 // G91
// Modal Group 4: Program flow
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
#define PROGRAM_FLOW_PAUSED 1 // M0, M1
#define PROGRAM_FLOW_COMPLETED 2 // M2, M30
// Modal Group 5: Feed rate mode
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93
// Modal Group 6: Units mode
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
#define UNITS_MODE_INCHES 1 // G20
// Modal Group 7: Spindle control
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
#define SPINDLE_ENABLE_CW 1 // M3
#define SPINDLE_ENABLE_CCW 2 // M4
// Modal Group 8: Coolant control
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
#define COOLANT_MIST_ENABLE 1 // M7
#define COOLANT_FLOOD_ENABLE 2 // M8
// Modal Group 12: Active work coordinate system
// N/A: Stores coordinate system value (54-59) to change to.
#define WORD_F 0
#define WORD_I 1
#define WORD_J 2
#define WORD_K 3
#define WORD_L 4
#define WORD_N 5
#define WORD_P 6
#define WORD_R 7
#define WORD_S 8
#define WORD_T 9
#define WORD_X 10
#define WORD_Y 11
#define WORD_Z 12
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
uint8_t motion; // {G0,G1,G2,G3,G80}
uint8_t feed_rate; // {G93,G94}
uint8_t units; // {G20,G21}
uint8_t distance; // {G90,G91}
uint8_t plane_select; // {G17,G18,G19}
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
uint8_t program_flow; // {M0,M1,M2,M30}
uint8_t coolant; // {M7,M8,M9}
uint8_t spindle; // {M3,M4,M5}
} gc_modal_t;
typedef struct {
uint8_t status_code; // Parser status for current block
uint8_t motion_mode; // {G0, G1, G2, G3, G80}
uint8_t inverse_feed_rate_mode; // {G93, G94}
uint8_t inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21}
uint8_t absolute_mode; // 0 = relative motion, 1 = absolute motion {G90, G91}
uint8_t program_flow; // {M0, M1, M2, M30}
uint8_t coolant_mode; // 0 = Disable, 1 = Flood Enable, 2 = Mist Enable {M8, M9}
uint8_t spindle_direction; // 1 = CW, 2 = CCW, 0 = Stop {M3, M4, M5}
float f; // Feed
float ijk[3]; // I,J,K Axis arc offsets
uint8_t l; // G10 or canned cycles parameters
int32_t n; // Line number
float p; // G10 or dwell parameters
// float q; // G82 peck drilling
float r; // Arc radius
float s; // Spindle speed
// uint8_t t; // Tool selection
float xyz[3]; // X,Y,Z Translational axes
} gc_values_t;
typedef struct {
gc_modal_t modal;
float spindle_speed; // RPM
float feed_rate; // Millimeters/min
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
uint8_t tool;
uint8_t plane_axis_0,
plane_axis_1,
plane_axis_2; // The axes of the selected plane
uint8_t coord_select; // Active work coordinate system number. Default: 0=G54.
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
// position in mm. Loaded from EEPROM when called.
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
float arc_radius;
float arc_offset[N_AXIS];
} parser_state_t;
extern parser_state_t gc;
extern parser_state_t gc_state;
typedef struct {
// uint16_t command_words; // NOTE: If this bitflag variable fills, G and M words can be separated.
// uint16_t value_words;
uint8_t non_modal_command;
gc_modal_t modal;
gc_values_t values;
} parser_block_t;
extern parser_block_t gc_block;
// Initialize the parser
void gc_init();

View File

@ -97,16 +97,15 @@ void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)
// of each segment is configured in settings.arc_tolerance, which is defined to be the maximum normal
// distance from segment to the circle when the end points both lie on the circle.
#ifdef USE_LINE_NUMBERS
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
uint8_t axis_linear, float feed_rate, uint8_t invert_feed_rate, float radius, uint8_t isclockwise, int32_t line_number)
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number)
#else
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
uint8_t axis_linear, float feed_rate, uint8_t invert_feed_rate, float radius, uint8_t isclockwise)
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)
#endif
{
float center_axis0 = position[axis_0] + offset[axis_0];
float center_axis1 = position[axis_1] + offset[axis_1];
float linear_travel = target[axis_linear] - position[axis_linear];
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
float r_axis1 = -offset[axis_1];
float rt_axis0 = target[axis_0] - center_axis0;
@ -114,7 +113,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if (isclockwise) { // Correct atan2 output per direction
if (gc_state.modal.motion == MOTION_MODE_CW_ARC) { // Correct atan2 output per direction
if (angular_travel >= 0) { angular_travel -= 2*M_PI; }
} else {
if (angular_travel <= 0) { angular_travel += 2*M_PI; }
@ -123,10 +122,8 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
// Computes: mm_per_arc_segment = sqrt(4*arc_tolerance*(2*radius-arc_tolerance)),
// segments = millimeters_of_travel/mm_per_arc_segment
float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
uint16_t segments = floor(0.5*millimeters_of_travel/
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
uint16_t segments = floor(fabs(0.5*angular_travel*radius)/
sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
if (segments) {
@ -136,7 +133,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
if (invert_feed_rate) { feed_rate *= segments; }
float theta_per_segment = angular_travel/segments;
float linear_per_segment = linear_travel/segments;
float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments;
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
and phi is the angle of rotation. Solution approach by Jens Geisler.
@ -166,17 +163,13 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
float sin_T = theta_per_segment*0.16666667*(cos_T + 4.0);
cos_T *= 0.5;
float arc_target[N_AXIS];
float sin_Ti;
float cos_Ti;
float r_axisi;
uint16_t i;
uint8_t count = 0;
// Initialize the linear axis
arc_target[axis_linear] = position[axis_linear];
for (i = 1; i<segments; i++) { // Increment (segments-1)
for (i = 1; i<segments; i++) { // Increment (segments-1).
if (count < N_ARC_CORRECTION) {
// Apply vector rotation matrix. ~40 usec
@ -195,14 +188,14 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
}
// Update arc_target location
arc_target[axis_0] = center_axis0 + r_axis0;
arc_target[axis_1] = center_axis1 + r_axis1;
arc_target[axis_linear] += linear_per_segment;
position[axis_0] = center_axis0 + r_axis0;
position[axis_1] = center_axis1 + r_axis1;
position[axis_linear] += linear_per_segment;
#ifdef USE_LINE_NUMBERS
mc_line(arc_target, feed_rate, invert_feed_rate, line_number);
mc_line(position, feed_rate, invert_feed_rate, line_number);
#else
mc_line(arc_target, feed_rate, invert_feed_rate);
mc_line(position, feed_rate, invert_feed_rate);
#endif
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
@ -221,6 +214,8 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// Execute dwell in seconds.
void mc_dwell(float seconds)
{
if (sys.state != STATE_CHECK_MODE) { return; }
uint16_t i = floor(1000/DWELL_TIME_STEP*seconds);
protocol_buffer_synchronize();
delay_ms(floor(1000*seconds-i*DWELL_TIME_STEP)); // Delay millisecond remainder.
@ -290,7 +285,7 @@ void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate)
mc_line(target, feed_rate, invert_feed_rate);
#endif
//TODO - make sure the probe isn't already closed
// NOTE: Parser error-checking ensures the probe isn't already closed/triggered.
sys.probe_state = PROBE_ACTIVE;
sys.execute |= EXEC_CYCLE_START;
@ -328,7 +323,7 @@ void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate)
// Gcode parser position was circumvented by the this routine, so sync position now.
gc_sync_position();
//TODO - ouput a mandatory status update with the probe position. What if another was recently sent?
// Output the probe position as message.
report_probe_parameters();
}

View File

@ -38,11 +38,11 @@ void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate);
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
// for vector transformation direction.
#ifdef USE_LINE_NUMBERS
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
uint8_t axis_linear, float feed_rate, uint8_t invert_feed_rate, float radius, uint8_t isclockwise, int32_t line_number);
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number);
#else
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
uint8_t axis_linear, float feed_rate, uint8_t invert_feed_rate, float radius, uint8_t isclockwise);
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear);
#endif
// Dwell for a specific number of seconds

View File

@ -24,6 +24,7 @@
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
// Extracts a floating point value from a string. The following code is based loosely on
// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
// available conversion method examples, but has been highly optimized for Grbl. For known
@ -31,7 +32,7 @@
// Scientific notation is officially not supported by g-code, and the 'E' character may
// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
int read_float(char *line, uint8_t *char_counter, float *float_ptr)
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
{
char *ptr = line + *char_counter;
unsigned char c;
@ -150,3 +151,8 @@ uint8_t get_direction_mask(uint8_t axis_idx)
return(axis_mask);
}
float hypot_f(float x, float y)
{
return(sqrt(x*x + y*y));
}

View File

@ -38,7 +38,7 @@
// Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*N_AXIS)
#define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
// #define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
@ -53,7 +53,7 @@
// 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
// a pointer to the result variable. Returns true when it succeeds
int read_float(char *line, uint8_t *char_counter, float *float_ptr);
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr);
// Delays variable-defined milliseconds. Compiler compatibility fix for _delay_ms().
void delay_ms(uint16_t ms);
@ -63,4 +63,6 @@ void delay_us(uint32_t us);
uint8_t get_direction_mask(uint8_t i);
float hypot_f(float x, float y);
#endif

34
print.c
View File

@ -76,32 +76,52 @@ void print_uint8_base2(uint8_t n)
serial_write('0' + buf[i - 1]);
}
void print_uint32_base10(unsigned long n)
void print_uint8_base10(uint8_t n)
{
unsigned char buf[10];
uint8_t i = 0;
if (n == 0) {
serial_write('0');
return;
}
unsigned char buf[3];
uint8_t i = 0;
while (n > 0) {
buf[i++] = n % 10 + '0';
n /= 10;
}
for (; i > 0; i--)
serial_write(buf[i-1]);
serial_write(buf[i - 1]);
}
void print_uint32_base10(unsigned long n)
{
if (n == 0) {
serial_write('0');
return;
}
unsigned char buf[10];
uint8_t i = 0;
while (n > 0) {
buf[i++] = n % 10;
n /= 10;
}
for (; i > 0; i--)
serial_write('0' + buf[i-1]);
}
void printInteger(long n)
{
if (n < 0) {
serial_write('-');
n = -n;
}
print_uint32_base10((-n));
} else {
print_uint32_base10(n);
}
}
// Convert float to string by immediately converting to a long integer, which contains

View File

@ -35,6 +35,8 @@ void print_uint32_base10(uint32_t n);
void print_uint8_base2(uint8_t n);
void print_uint8_base10(uint8_t n);
void printFloat(float n);
#endif

View File

@ -30,13 +30,19 @@ void probe_init()
}
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
uint8_t probe_get_state()
{
return(!(PROBE_PIN & PROBE_MASK));
}
// Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick.
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
void probe_state_monitor()
{
if (sys.probe_state == PROBE_ACTIVE) {
if (!(PROBE_PIN & PROBE_MASK)) {
if (probe_get_state()) {
sys.probe_state = PROBE_OFF;
memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS);
sys.execute |= EXEC_FEED_HOLD;

View File

@ -29,6 +29,9 @@
// Probe pin initialization routine.
void probe_init();
// Returns probe pin state.
uint8_t probe_get_state();
// Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick.
void probe_state_monitor();

View File

@ -36,37 +36,27 @@ static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also directs and executes Grbl internal commands,
// such as settings, initiating the homing cycle, and toggling switch states.
// TODO: Eventually re-organize this function to more cleanly organize order of operations,
// which will hopefully reduce some of the current spaghetti logic and dynamic memory usage.
static void protocol_execute_line(char *line)
{
protocol_execute_runtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to calling function upon system abort
uint8_t status;
if (line[0] == 0) {
// Empty or comment line. Send status message for syncing purposes.
status = STATUS_OK;
report_status_message(STATUS_OK);
} else if (line[0] == '$') {
// Grbl '$' system command
status = system_execute_line(line);
report_status_message(system_execute_line(line));
} else if (sys.state == STATE_ALARM) {
// Everything else is gcode. Block if in alarm mode.
report_status_message(STATUS_ALARM_LOCK);
} else {
// Everything else is gcode. Send to g-code parser! Block if in alarm mode.
if (sys.state == STATE_ALARM) { status = STATUS_ALARM_LOCK; }
else { status = gc_execute_line(line); }
// 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.
// TODO: Clean up the multi-tasking workflow with the execution of commands. It's a
// bit complicated and patch-worked. Could be made simplier to understand.
// Parse and execute g-code block!
report_status_message(gc_execute_line(line));
}
report_status_message(status);
}
@ -119,10 +109,25 @@ void protocol_main_loop()
if (c <= ' ') {
// Throw away whitepace and control characters
} else if (c == '/') {
// Block delete not supported. Ignore character.
// Block delete NOT SUPPORTED. Ignore character.
// NOTE: If supported, would simply need to check the system if block delete is enabled.
} else if (c == '(') {
// Enable comments flag and ignore all characters until ')' or EOL.
// NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
// In the future, we could simply remove the items within the comments, but retain the
// comment control characters, so that the g-code parser can error-check it.
iscomment = true;
// } else if (c == ';') {
// Comment character to EOL NOT SUPPORTED. LinuxCNC definition. Not NIST.
// TODO: Install '%' feature
// } else if (c == '%') {
// Program start-end percent sign NOT SUPPORTED.
// NOTE: This maybe installed to tell Grbl when a program is running vs manual input,
// where, during a program, the system auto-cycle start will continue to execute
// everything until the next '%' sign. This will help fix resuming issues with certain
// functions that empty the planner buffer to execute its task on-time.
} else if (char_counter >= LINE_BUFFER_SIZE-1) {
// Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW);

122
report.c
View File

@ -51,22 +51,16 @@ void report_status_message(uint8_t status_code)
} else {
printPgmString(PSTR("error: "));
switch(status_code) {
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_EXPECTED_COMMAND_LETTER:
printPgmString(PSTR("Expected command letter")); break;
case STATUS_UNSUPPORTED_STATEMENT:
printPgmString(PSTR("Unsupported statement")); break;
case STATUS_ARC_RADIUS_ERROR:
printPgmString(PSTR("Invalid radius")); break;
case STATUS_MODAL_GROUP_VIOLATION:
printPgmString(PSTR("Modal group violation")); break;
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break;
case STATUS_NEGATIVE_VALUE:
printPgmString(PSTR("Value < 0")); break;
case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Setting disabled")); break;
case STATUS_SETTING_VALUE_NEG:
printPgmString(PSTR("Value < 0.0")); break;
case STATUS_SETTING_STEP_PULSE_MIN:
printPgmString(PSTR("Value < 3 usec")); break;
case STATUS_SETTING_READ_FAIL:
@ -79,6 +73,18 @@ void report_status_message(uint8_t status_code)
printPgmString(PSTR("Homing not enabled")); break;
case STATUS_OVERFLOW:
printPgmString(PSTR("Line overflow")); break;
// Common g-code parser errors.
case STATUS_GCODE_MODAL_GROUP_VIOLATION:
printPgmString(PSTR("Modal group violation")); break;
case STATUS_GCODE_UNSUPPORTED_COMMAND:
printPgmString(PSTR("Unsupported command")); break;
case STATUS_GCODE_UNDEFINED_FEED_RATE:
printPgmString(PSTR("Undefined feed rate")); break;
default:
// Remaining g-code parser errors with error codes
printPgmString(PSTR("Invalid gcode ID:"));
print_uint8_base10(status_code); // Print error code for user reference
}
printPgmString(PSTR("\r\n"));
}
@ -163,29 +169,28 @@ void report_grbl_settings() {
printPgmString(PSTR(" (z accel, mm/sec^2)\r\n$9=")); printFloat(-settings.max_travel[X_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (x max travel, mm)\r\n$10=")); printFloat(-settings.max_travel[Y_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (y max travel, mm)\r\n$11=")); printFloat(-settings.max_travel[Z_AXIS]); // Grbl internally store this as negative.
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(" (default feed, mm/min)\r\n$14=")); printInteger(settings.step_invert_mask);
printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); print_uint8_base10(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); print_uint8_base10(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$14=")); print_uint8_base10(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(" (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(" (arc tolerance, mm)\r\n$19=")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (n-decimals, int)\r\n$20=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (report inches, bool)\r\n$21=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start, bool)\r\n$22=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (invert step enable, bool)\r\n$23=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
printPgmString(PSTR(" (invert limit pins, bool)\r\n$24=")); printInteger(bit_istrue(settings.flags,BITFLAG_SOFT_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(" (homing cycle, bool)\r\n$27=")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$15=")); print_uint8_base10(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (step idle delay, msec)\r\n$16=")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (junction deviation, mm)\r\n$17=")); printFloat(settings.arc_tolerance);
printPgmString(PSTR(" (arc tolerance, mm)\r\n$18=")); print_uint8_base10(settings.decimal_places);
printPgmString(PSTR(" (n-decimals, int)\r\n$19=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (report inches, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start, bool)\r\n$21=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (invert step enable, bool)\r\n$22=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
printPgmString(PSTR(" (invert limit pins, bool)\r\n$23=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
printPgmString(PSTR(" (soft limits, bool)\r\n$24=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$25=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$26=")); print_uint8_base10(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(" (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 debounce, msec)\r\n$31=")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(")\r\n$27=")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$28=")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$29=")); print_uint8_base10(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce, msec)\r\n$30=")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
}
@ -222,16 +227,11 @@ void report_ngc_parameters()
}
printPgmString(PSTR("[G"));
switch (coord_select) {
case 0: printPgmString(PSTR("54:")); break;
case 1: printPgmString(PSTR("55:")); break;
case 2: printPgmString(PSTR("56:")); break;
case 3: printPgmString(PSTR("57:")); break;
case 4: printPgmString(PSTR("58:")); break;
case 5: printPgmString(PSTR("59:")); break;
case 6: printPgmString(PSTR("28:")); break;
case 7: printPgmString(PSTR("30:")); break;
// case 8: printPgmString(PSTR("92:")); break; // G92.2, G92.3 not supported. Hence not stored.
case 6: printPgmString(PSTR("28")); break;
case 7: printPgmString(PSTR("30")); break;
default: print_uint8_base10(coord_select+54); break; // G54-G59
}
printPgmString(PSTR(":"));
for (i=0; i<N_AXIS; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { printFloat(coord_data[i]*INCH_PER_MM); }
else { printFloat(coord_data[i]); }
@ -241,8 +241,8 @@ void report_ngc_parameters()
}
printPgmString(PSTR("[G92:")); // Print G92,G92.1 which are not persistent in memory
for (i=0; i<N_AXIS; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { printFloat(gc.coord_offset[i]*INCH_PER_MM); }
else { printFloat(gc.coord_offset[i]); }
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { printFloat(gc_state.coord_offset[i]*INCH_PER_MM); }
else { printFloat(gc_state.coord_offset[i]); }
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
else { printPgmString(PSTR("]\r\n")); }
}
@ -253,44 +253,45 @@ void report_ngc_parameters()
// Print current gcode parser mode state
void report_gcode_modes()
{
switch (gc.motion_mode) {
switch (gc_state.modal.motion) {
case MOTION_MODE_SEEK : printPgmString(PSTR("[G0")); break;
case MOTION_MODE_LINEAR : printPgmString(PSTR("[G1")); break;
case MOTION_MODE_CW_ARC : printPgmString(PSTR("[G2")); break;
case MOTION_MODE_CCW_ARC : printPgmString(PSTR("[G3")); break;
case MOTION_MODE_CANCEL : printPgmString(PSTR("[G80")); break;
case MOTION_MODE_NONE : printPgmString(PSTR("[G80")); break;
}
printPgmString(PSTR(" G"));
printInteger(gc.coord_select+54);
print_uint8_base10(gc_state.modal.coord_select+54);
if (gc.plane_axis_0 == X_AXIS) {
if (gc.plane_axis_1 == Y_AXIS) { printPgmString(PSTR(" G17")); }
else { printPgmString(PSTR(" G18")); }
} else { printPgmString(PSTR(" G19")); }
switch (gc_state.modal.plane_select) {
case PLANE_SELECT_XY : printPgmString(PSTR(" G17")); break;
case PLANE_SELECT_ZX : printPgmString(PSTR(" G18")); break;
case PLANE_SELECT_YZ : printPgmString(PSTR(" G19")); break;
}
if (gc.inches_mode) { printPgmString(PSTR(" G20")); }
else { printPgmString(PSTR(" G21")); }
if (gc_state.modal.units == UNITS_MODE_MM) { printPgmString(PSTR(" G21")); }
else { printPgmString(PSTR(" G20")); }
if (gc.absolute_mode) { printPgmString(PSTR(" G90")); }
if (gc_state.modal.distance == DISTANCE_MODE_ABSOLUTE) { printPgmString(PSTR(" G90")); }
else { printPgmString(PSTR(" G91")); }
if (gc.inverse_feed_rate_mode) { printPgmString(PSTR(" G93")); }
if (gc_state.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { printPgmString(PSTR(" G93")); }
else { printPgmString(PSTR(" G94")); }
switch (gc.program_flow) {
switch (gc_state.modal.program_flow) {
case PROGRAM_FLOW_RUNNING : printPgmString(PSTR(" M0")); break;
case PROGRAM_FLOW_PAUSED : printPgmString(PSTR(" M1")); break;
case PROGRAM_FLOW_COMPLETED : printPgmString(PSTR(" M2")); break;
}
switch (gc.spindle_direction) {
switch (gc_state.modal.spindle) {
case SPINDLE_ENABLE_CW : printPgmString(PSTR(" M3")); break;
case SPINDLE_ENABLE_CCW : printPgmString(PSTR(" M4")); break;
case SPINDLE_DISABLE : printPgmString(PSTR(" M5")); break;
}
switch (gc.coolant_mode) {
switch (gc_state.modal.coolant) {
case COOLANT_DISABLE : printPgmString(PSTR(" M9")); break;
case COOLANT_FLOOD_ENABLE : printPgmString(PSTR(" M8")); break;
#ifdef ENABLE_M7
@ -299,11 +300,10 @@ void report_gcode_modes()
}
printPgmString(PSTR(" T"));
printInteger(gc.tool);
print_uint8_base10(gc_state.tool);
printPgmString(PSTR(" F"));
if (gc.inches_mode) { printFloat(gc.feed_rate*INCH_PER_MM); }
else { printFloat(gc.feed_rate); }
printFloat(gc_state.feed_rate);
printPgmString(PSTR("]\r\n"));
}
@ -311,7 +311,7 @@ void report_gcode_modes()
// Prints specified startup line
void report_startup_line(uint8_t n, char *line)
{
printPgmString(PSTR("$N")); printInteger(n);
printPgmString(PSTR("$N")); print_uint8_base10(n);
printPgmString(PSTR("=")); printString(line);
printPgmString(PSTR("\r\n"));
}
@ -366,9 +366,9 @@ void report_realtime_status()
printPgmString(PSTR("WPos:"));
for (i=0; i< N_AXIS; i++) {
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
print_position[i] -= (gc.coord_system[i]+gc.coord_offset[i])*INCH_PER_MM;
print_position[i] -= (gc_state.coord_system[i]+gc_state.coord_offset[i])*INCH_PER_MM;
} else {
print_position[i] -= gc.coord_system[i]+gc.coord_offset[i];
print_position[i] -= gc_state.coord_system[i]+gc_state.coord_offset[i];
}
printFloat(print_position[i]);
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }

View File

@ -22,20 +22,36 @@
// Define Grbl status codes.
#define STATUS_OK 0
#define STATUS_BAD_NUMBER_FORMAT 1
#define STATUS_EXPECTED_COMMAND_LETTER 2
#define STATUS_UNSUPPORTED_STATEMENT 3
#define STATUS_ARC_RADIUS_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6
#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 STATUS_SOFT_LIMIT_ERROR 13
#define STATUS_OVERFLOW 14
#define STATUS_EXPECTED_COMMAND_LETTER 1
#define STATUS_BAD_NUMBER_FORMAT 2
#define STATUS_INVALID_STATEMENT 3
#define STATUS_NEGATIVE_VALUE 4
#define STATUS_SETTING_DISABLED 5
#define STATUS_SETTING_STEP_PULSE_MIN 6
#define STATUS_SETTING_READ_FAIL 7
#define STATUS_IDLE_ERROR 8
#define STATUS_ALARM_LOCK 9
#define STATUS_SOFT_LIMIT_ERROR 10
#define STATUS_OVERFLOW 11
#define STATUS_GCODE_UNSUPPORTED_COMMAND 20
#define STATUS_GCODE_MODAL_GROUP_VIOLATION 21
#define STATUS_GCODE_UNDEFINED_FEED_RATE 22
#define STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER 23
#define STATUS_GCODE_AXIS_COMMAND_CONFLICT 24
#define STATUS_GCODE_WORD_REPEATED 25
#define STATUS_GCODE_NO_AXIS_WORDS 26
#define STATUS_GCODE_INVALID_LINE_NUMBER 27
#define STATUS_GCODE_VALUE_WORD_MISSING 28
#define STATUS_GCODE_UNSUPPORTED_COORD_SYS 29
#define STATUS_GCODE_G53_INVALID_MOTION_MODE 30
#define STATUS_GCODE_AXIS_WORDS_EXIST 31
#define STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE 32
#define STATUS_GCODE_INVALID_TARGET 33
#define STATUS_GCODE_ARC_RADIUS_ERROR 34
#define STATUS_GCODE_NO_OFFSETS_IN_PLANE 35
#define STATUS_GCODE_PROBE_TRIGGERED 36
#define STATUS_GCODE_UNUSED_WORDS 37
// Define Grbl alarm codes. Less than zero to distinguish alarm error from status error.
#define ALARM_LIMIT_ERROR -1

View File

@ -66,7 +66,6 @@ void settings_reset() {
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
settings.default_feed_rate = DEFAULT_FEEDRATE;
settings.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
settings.max_rate[Y_AXIS] = DEFAULT_Y_MAX_RATE;
settings.max_rate[Z_AXIS] = DEFAULT_Z_MAX_RATE;
@ -161,7 +160,7 @@ uint8_t read_global_settings() {
// A helper method to set settings from command line
uint8_t settings_store_global_setting(int parameter, float value) {
if (value < 0.0) { return(STATUS_SETTING_VALUE_NEG); }
if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); }
switch(parameter) {
case 0: case 1: case 2:
settings.steps_per_mm[parameter] = value; break;
@ -177,52 +176,51 @@ uint8_t settings_store_global_setting(int parameter, float value) {
case 12:
if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
settings.pulse_microseconds = round(value); break;
case 13: settings.default_feed_rate = value; break;
case 14: settings.step_invert_mask = trunc(value); break;
case 15: settings.dir_invert_mask = trunc(value); break;
case 16: settings.stepper_idle_lock_time = round(value); break;
case 17: settings.junction_deviation = fabs(value); break;
case 18: settings.arc_tolerance = value; break;
case 19: settings.decimal_places = round(value); break;
case 20:
case 13: settings.step_invert_mask = trunc(value); break;
case 14: settings.dir_invert_mask = trunc(value); break;
case 15: settings.stepper_idle_lock_time = round(value); break;
case 16: settings.junction_deviation = fabs(value); break;
case 17: settings.arc_tolerance = value; break;
case 18: settings.decimal_places = round(value); break;
case 19:
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break;
case 21: // Reset to ensure change. Immediate re-init may cause problems.
case 20: // 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 22: // Reset to ensure change. Immediate re-init may cause problems.
case 21: // 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 23: // Reset to ensure change. Immediate re-init may cause problems.
case 22: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
break;
case 24:
case 23:
if (value) {
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
break;
case 25:
case 24:
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 26:
case 25:
if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
else {
settings.flags &= ~BITFLAG_HOMING_ENABLE;
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
}
break;
case 27: settings.homing_dir_mask = trunc(value); break;
case 28: settings.homing_feed_rate = value; break;
case 29: settings.homing_seek_rate = value; break;
case 30: settings.homing_debounce_delay = round(value); break;
case 31: settings.homing_pulloff = value; break;
case 26: settings.homing_dir_mask = trunc(value); break;
case 27: settings.homing_feed_rate = value; break;
case 28: settings.homing_seek_rate = value; break;
case 29: settings.homing_debounce_delay = round(value); break;
case 30: settings.homing_pulloff = value; break;
default:
return(STATUS_INVALID_STATEMENT);
}

View File

@ -25,12 +25,12 @@
#include "system.h"
#define GRBL_VERSION "0.9d"
#define GRBL_VERSION_BUILD "20140228"
#define GRBL_VERSION "0.9e"
#define GRBL_VERSION_BUILD "20140525"
// 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
#define SETTINGS_VERSION 6
#define SETTINGS_VERSION 7
// Define bit flag masks for the boolean settings in settings.flag.
#define BITFLAG_REPORT_INCHES bit(0)
@ -65,7 +65,6 @@ typedef struct {
float acceleration[N_AXIS];
float max_travel[N_AXIS];
uint8_t pulse_microseconds;
float default_feed_rate;
uint8_t step_invert_mask;
uint8_t dir_invert_mask;
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.

View File

@ -22,6 +22,7 @@
#include "system.h"
#include "spindle_control.h"
#include "protocol.h"
#include "gcode.h"
void spindle_init()
@ -56,6 +57,8 @@ void spindle_stop()
void spindle_run(uint8_t direction, float rpm)
{
if (sys.state != STATE_CHECK_MODE) { return; }
// Empty planner buffer to ensure spindle is set when programmed.
protocol_buffer_synchronize();

View File

@ -23,11 +23,6 @@
#define spindle_control_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.
void spindle_init();

View File

@ -87,11 +87,11 @@ uint8_t system_execute_line(char *line)
switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
case 'G' : // Prints gcode parser state
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if ( line[++char_counter] != 0 ) { return(STATUS_INVALID_STATEMENT); }
else { report_gcode_modes(); }
break;
case 'C' : // Set check g-code mode [IDLE/CHECK]
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if ( line[++char_counter] != 0 ) { return(STATUS_INVALID_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.
@ -105,7 +105,7 @@ uint8_t system_execute_line(char *line)
}
break;
case 'X' : // Disable alarm lock [ALARM]
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if ( line[++char_counter] != 0 ) { return(STATUS_INVALID_STATEMENT); }
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE;
@ -129,11 +129,11 @@ uint8_t system_execute_line(char *line)
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
switch( line[char_counter] ) {
case '$' : // Prints Grbl settings [IDLE/ALARM]
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if ( line[++char_counter] != 0 ) { return(STATUS_INVALID_STATEMENT); }
else { report_grbl_settings(); }
break;
case '#' : // Print Grbl NGC parameters
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if ( line[++char_counter] != 0 ) { return(STATUS_INVALID_STATEMENT); }
else { report_ngc_parameters(); }
break;
case 'H' : // Perform homing cycle [IDLE/ALARM]
@ -151,7 +151,7 @@ uint8_t system_execute_line(char *line)
report_build_info(line);
}
} else { // Store startup line [IDLE/ALARM]
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if(line[char_counter++] != '=') { return(STATUS_INVALID_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];
@ -176,7 +176,7 @@ uint8_t system_execute_line(char *line)
}
default : // Storing setting methods [IDLE/ALARM]
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if(line[char_counter++] != '=') { return(STATUS_INVALID_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
@ -192,7 +192,7 @@ uint8_t system_execute_line(char *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); }
if(line[char_counter] != 0) { return(STATUS_INVALID_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
}