From df90e641714e7e10e90f388b08185a269d2c5ecd Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Thu, 3 Sep 2020 13:46:49 -1000 Subject: [PATCH] Replaced #defines with enums in GCode.h (#572) * Replaced #defines with enums in GCode.h * More #defines bit the dust * Resolved review comments * Some fixes * Added parser test * Fixed braces in GCode.cpp * Clang format * Revised delay value in tests/parser.nc --- Grbl_Esp32/Custom/polar_coaster.cpp | 2 +- Grbl_Esp32/src/Config.h | 2 +- Grbl_Esp32/src/CoolantControl.cpp | 18 +- Grbl_Esp32/src/CoolantControl.h | 13 +- Grbl_Esp32/src/GCode.cpp | 772 ++++++++++++-------- Grbl_Esp32/src/GCode.h | 293 ++++---- Grbl_Esp32/src/Grbl.h | 8 +- Grbl_Esp32/src/Jog.cpp | 2 +- Grbl_Esp32/src/Limits.cpp | 4 +- Grbl_Esp32/src/MotionControl.cpp | 39 +- Grbl_Esp32/src/MotionControl.h | 8 +- Grbl_Esp32/src/NutsBolts.h | 11 +- Grbl_Esp32/src/Planner.cpp | 18 +- Grbl_Esp32/src/Planner.h | 26 +- Grbl_Esp32/src/ProcessSettings.cpp | 20 +- Grbl_Esp32/src/Protocol.cpp | 85 ++- Grbl_Esp32/src/Report.cpp | 143 ++-- Grbl_Esp32/src/Spindles/10vSpindle.cpp | 17 +- Grbl_Esp32/src/Spindles/10vSpindle.h | 6 +- Grbl_Esp32/src/Spindles/H2ASpindle.cpp | 4 +- Grbl_Esp32/src/Spindles/H2ASpindle.h | 2 +- Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp | 8 +- Grbl_Esp32/src/Spindles/HuanyangSpindle.h | 2 +- Grbl_Esp32/src/Spindles/NullSpindle.cpp | 8 +- Grbl_Esp32/src/Spindles/NullSpindle.h | 12 +- Grbl_Esp32/src/Spindles/PWMSpindle.cpp | 18 +- Grbl_Esp32/src/Spindles/PWMSpindle.h | 8 +- Grbl_Esp32/src/Spindles/Spindle.cpp | 5 +- Grbl_Esp32/src/Spindles/Spindle.h | 26 +- Grbl_Esp32/src/Spindles/VFDSpindle.cpp | 16 +- Grbl_Esp32/src/Spindles/VFDSpindle.h | 24 +- Grbl_Esp32/src/Stepper.cpp | 8 +- Grbl_Esp32/src/tests/parser-result.txt | 665 +++++++++++++++++ Grbl_Esp32/src/tests/parser.nc | 253 +++++++ 34 files changed, 1835 insertions(+), 711 deletions(-) create mode 100644 Grbl_Esp32/src/tests/parser-result.txt create mode 100644 Grbl_Esp32/src/tests/parser.nc diff --git a/Grbl_Esp32/Custom/polar_coaster.cpp b/Grbl_Esp32/Custom/polar_coaster.cpp index a9ae8018..777113a2 100644 --- a/Grbl_Esp32/Custom/polar_coaster.cpp +++ b/Grbl_Esp32/Custom/polar_coaster.cpp @@ -105,7 +105,7 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio // calculate the total X,Y axis move distance // Z axis is the same in both coord systems, so it is ignored dist = sqrt((dx * dx) + (dy * dy) + (dz * dz)); - if (pl_data->condition & PL_COND_FLAG_RAPID_MOTION) { + if (pl_data->motion & PL_MOTION_RAPID_MOTION) { segment_count = 1; // rapid G0 motion is not used to draw, so skip the segmentation } else { segment_count = ceil(dist / SEGMENT_LENGTH); // determine the number of segments we need ... round up so there is at least 1 diff --git a/Grbl_Esp32/src/Config.h b/Grbl_Esp32/src/Config.h index b765c754..b8fe7c21 100644 --- a/Grbl_Esp32/src/Config.h +++ b/Grbl_Esp32/src/Config.h @@ -233,7 +233,7 @@ Some features should not be changed. See notes below. // Number of homing cycles performed after when the machine initially jogs to limit switches. // This help in preventing overshoot and should improve repeatability. This value should be one or // greater. -#define N_HOMING_LOCATE_CYCLE 1 // Integer (1-128) +static const uint8_t NHomingLocateCycle = 1; // Integer (1-128) // Enables single axis homing commands. $HX, $HY, and $HZ for X, Y, and Z-axis homing. The full homing // cycle is still invoked by the $H command. This is disabled by default. It's here only to address diff --git a/Grbl_Esp32/src/CoolantControl.cpp b/Grbl_Esp32/src/CoolantControl.cpp index 9f4016e8..8e617a8f 100644 --- a/Grbl_Esp32/src/CoolantControl.cpp +++ b/Grbl_Esp32/src/CoolantControl.cpp @@ -34,15 +34,15 @@ void coolant_init() { } // Returns current coolant output state. Overrides may alter it from programmed state. -uint8_t coolant_get_state() { - uint8_t cl_state = COOLANT_STATE_DISABLE; +CoolantMode coolant_get_state() { + CoolantMode cl_state = CoolantMode::Disable; #ifdef COOLANT_FLOOD_PIN # ifdef INVERT_COOLANT_FLOOD_PIN if (!digitalRead(COOLANT_FLOOD_PIN)) { # else if (digitalRead(COOLANT_FLOOD_PIN)) { # endif - cl_state |= COOLANT_STATE_FLOOD; + cl_state |= CoolantMode::Flood; } #endif #ifdef COOLANT_MIST_PIN @@ -51,7 +51,7 @@ uint8_t coolant_get_state() { # else if (digitalRead(COOLANT_MIST_PIN)) { # endif - cl_state |= COOLANT_STATE_MIST; + cl_state |= CoolantMode::Mist; } #endif return (cl_state); @@ -80,14 +80,14 @@ void coolant_stop() { // if enabled. Also sets a flag to report an update to a coolant state. // Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code // parser program end, and g-code parser coolant_sync(). -void coolant_set_state(uint8_t mode) { +void coolant_set_state(CoolantMode mode) { if (sys.abort) return; // Block during abort. - if (mode == COOLANT_DISABLE) + if (mode == CoolantMode::Disable) coolant_stop(); else { #ifdef COOLANT_FLOOD_PIN - if (mode & COOLANT_FLOOD_ENABLE) { + if (mode & CoolantMode::Enable) { # ifdef INVERT_COOLANT_FLOOD_PIN digitalWrite(COOLANT_FLOOD_PIN, 0); # else @@ -96,7 +96,7 @@ void coolant_set_state(uint8_t mode) { } #endif #ifdef COOLANT_MIST_PIN - if (mode & COOLANT_MIST_ENABLE) { + if (mode & CoolantMode::Mist) { # ifdef INVERT_COOLANT_MIST_PIN digitalWrite(COOLANT_MIST_PIN, 0); # else @@ -110,7 +110,7 @@ void coolant_set_state(uint8_t mode) { // G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails // if an abort or check-mode is active. -void coolant_sync(uint8_t mode) { +void coolant_sync(CoolantMode mode) { if (sys.state == STATE_CHECK_MODE) return; protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program. diff --git a/Grbl_Esp32/src/CoolantControl.h b/Grbl_Esp32/src/CoolantControl.h index b4696a07..54df14a7 100644 --- a/Grbl_Esp32/src/CoolantControl.h +++ b/Grbl_Esp32/src/CoolantControl.h @@ -23,24 +23,17 @@ along with Grbl. If not, see . */ -#define COOLANT_NO_SYNC false -#define COOLANT_FORCE_SYNC true - -#define COOLANT_STATE_DISABLE 0 // Must be zero -#define COOLANT_STATE_FLOOD bit(0) -#define COOLANT_STATE_MIST bit(1) - // Initializes coolant control pins. void coolant_init(); // Returns current coolant output state. Overrides may alter it from programmed state. -uint8_t coolant_get_state(); +CoolantMode coolant_get_state(); // Immediately disables coolant pins. void coolant_stop(); // Sets the coolant pins according to state specified. -void coolant_set_state(uint8_t mode); +void coolant_set_state(CoolantMode mode); // G-code parser entry-point for setting coolant states. Checks for and executes additional conditions. -void coolant_sync(uint8_t mode); +void coolant_sync(CoolantMode mode); diff --git a/Grbl_Esp32/src/GCode.cpp b/Grbl_Esp32/src/GCode.cpp index 8f711368..1e0d5b11 100644 --- a/Grbl_Esp32/src/GCode.cpp +++ b/Grbl_Esp32/src/GCode.cpp @@ -27,13 +27,8 @@ // NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an // arbitrary value, and some GUIs may require more. So we increased it based on a max safe // value when converting a float (7.2 digit precision)s to an integer. -#define MAX_LINE_NUMBER 10000000 -#define MAX_TOOL_NUMBER 255 // Limited by max unsigned 8-bit value - -#define AXIS_COMMAND_NONE 0 -#define AXIS_COMMAND_NON_MODAL 1 -#define AXIS_COMMAND_MOTION_MODE 2 -#define AXIS_COMMAND_TOOL_LENGTH_OFFSET 3 // *Undefined but required +static const int32_t MaxLineNumber = 10000000; +static const uint8_t MaxToolNumber = 255; // Limited by max unsigned 8-bit value // Declare gc extern struct parser_state_t gc_state; @@ -44,8 +39,9 @@ parser_block_t gc_block; void gc_init() { memset(&gc_state, 0, sizeof(parser_state_t)); // Load default G54 coordinate system. - if (!(settings_read_coord_data(gc_state.modal.coord_select, gc_state.coord_system))) + if (!(settings_read_coord_data(gc_state.modal.coord_select, gc_state.coord_system))) { report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL); + } } // Sets g-code parser position in mm. Input in steps. Called by the system abort and hard @@ -134,22 +130,22 @@ uint8_t gc_execute_line(char* line, uint8_t client) { block. This struct contains all of the necessary information to execute the block. */ memset(&gc_block, 0, sizeof(parser_block_t)); // Initialize the parser block struct. memcpy(&gc_block.modal, &gc_state.modal, sizeof(gc_modal_t)); // Copy current modes - uint8_t axis_command = AXIS_COMMAND_NONE; - uint8_t axis_0, axis_1, axis_linear; - uint8_t coord_select = 0; // Tracks G10 P coordinate selection for execution + AxisCommand axis_command = AxisCommand::None; + uint8_t axis_0, axis_1, axis_linear; + uint8_t coord_select = 0; // Tracks G10 P coordinate selection for execution // Initialize bitflag tracking variables for axis indices compatible operations. uint8_t axis_words = 0; // XYZ tracking uint8_t ijk_words = 0; // IJK tracking // Initialize command and value words and parser flags variables. uint16_t command_words = 0; // Tracks G and M command words. Also used for modal group violations. uint16_t value_words = 0; // Tracks value words. - uint8_t gc_parser_flags = GC_PARSER_NONE; + uint8_t gc_parser_flags = GCParserNone; // Determine if the line is a jogging motion or a normal g-code block. if (line[0] == '$') { // NOTE: `$J=` already parsed when passed to this function. // Set G1 and G94 enforced modes to ensure accurate error checks. - gc_parser_flags |= GC_PARSER_JOG_MOTION; - gc_block.modal.motion = MOTION_MODE_LINEAR; - gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; + gc_parser_flags |= GCParserJogMotion; + gc_block.modal.motion = Motion::Linear; + gc_block.modal.feed_rate = FeedRate::UnitsPerMin; #ifdef USE_LINE_NUMBERS gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog. #endif @@ -159,16 +155,18 @@ uint8_t gc_execute_line(char* line, uint8_t client) { a number, which can either be a 'G'/'M' command or sets/assigns a command value. Also, perform initial error-checks for command word modal group violations, for any repeated words, and for negative values set for the value words F, N, P, T, and S. */ - uint8_t word_bit = 0; // Bit-value for assigning tracking variables - uint8_t char_counter; - char letter; - float value; - uint8_t int_value = 0; - uint16_t mantissa = 0; - if (gc_parser_flags & GC_PARSER_JOG_MOTION) { + ModalGroup mg_word_bit; // Bit-value for assigning tracking variables + uint8_t bitmask = 0; + uint8_t char_counter; + char letter; + float value; + uint8_t int_value = 0; + uint16_t mantissa = 0; + if (gc_parser_flags & GCParserJogMotion) { char_counter = 3; // Start parsing after `$J=` - } else + } else { char_counter = 0; + } while (line[char_counter] != 0) { // Loop until no more g-code words in line. // Import the next g-code word, expecting a letter followed by a value. Otherwise, error out. letter = line[char_counter]; @@ -197,113 +195,180 @@ uint8_t gc_execute_line(char* line, uint8_t client) { case 'G': // Determine 'G' command and its modal group switch (int_value) { + // Modal Group G0 - non-modal actions case 10: - case 28: - case 30: - case 92: - // Check for G10/28/30/92 being called with G0/1/2/3/38 on same block. - // * G43.1 is also an axis command but is not explicitly defined this way. - if (mantissa == 0) { // Ignore G28.1, G30.1, and G92.1 - if (axis_command) { + gc_block.non_modal_command = NonModal::SetCoordinateData; + if (mantissa == 0) { + if (axis_command != AxisCommand::None) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); // [Axis word/command conflict] } - axis_command = AXIS_COMMAND_NON_MODAL; - } - // No break. Continues to next line. - case 4: - case 53: - word_bit = MODAL_GROUP_G0; - gc_block.non_modal_command = int_value; - if ((int_value == 28) || (int_value == 30) || (int_value == 92)) { - if (!((mantissa == 0) || (mantissa == 10))) - FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); - gc_block.non_modal_command += mantissa; - mantissa = 0; // Set to zero to indicate valid non-integer G command. + axis_command = AxisCommand::NonModal; } + mg_word_bit = ModalGroup::MG0; break; - case 0: - case 1: - case 2: - case 3: - case 38: -#ifndef PROBE_PIN //only allow G38 "Probe" commands if a probe pin is defined. - if (int_value == 38) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No probe pin defined"); - FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G command] + + case 28: gc_block.non_modal_command = mantissa ? NonModal::SetHome0 : NonModal::GoHome0; goto check_mantissa; + case 30: gc_block.non_modal_command = mantissa ? NonModal::SetHome1 : NonModal::GoHome1; goto check_mantissa; + case 92: + gc_block.non_modal_command = mantissa ? NonModal::ResetCoordinateOffset : NonModal::SetCoordinateOffset; + check_mantissa: + // Check for G10/28/30/92 being called with G0/1/2/3/38 on same block. + // * G43.1 is also an axis command but is not explicitly defined this way. + switch (mantissa) { + case 0: // Ignore G28.1, G30.1, and G92.1 + if (axis_command != AxisCommand::None) { + FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); // [Axis word/command conflict] + } + axis_command = AxisCommand::NonModal; + break; + case 10: + mantissa = 0; // Set to zero to indicate valid non-integer G command. + break; + default: + FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); + // not reached + break; } + mg_word_bit = ModalGroup::MG0; + break; + case 4: + gc_block.non_modal_command = NonModal::Dwell; + mg_word_bit = ModalGroup::MG0; + break; + case 53: + gc_block.non_modal_command = NonModal::AbsoluteOverride; + mg_word_bit = ModalGroup::MG0; + break; + + // Modal Group G1 - motion commands + case 0: // G0 - linear rapid traverse + axis_command = AxisCommand::MotionMode; + gc_block.modal.motion = Motion::Seek; + mg_word_bit = ModalGroup::MG1; + break; + case 1: // G1 - linear feedrate move + axis_command = AxisCommand::MotionMode; + gc_block.modal.motion = Motion::Linear; + mg_word_bit = ModalGroup::MG1; + break; + case 2: // G2 - clockwise arc + axis_command = AxisCommand::MotionMode; + gc_block.modal.motion = Motion::CwArc; + mg_word_bit = ModalGroup::MG1; + break; + case 3: // G3 - counterclockwise arc + axis_command = AxisCommand::MotionMode; + gc_block.modal.motion = Motion::CcwArc; + mg_word_bit = ModalGroup::MG1; + break; + case 38: // G38 - probe +#ifndef PROBE_PIN //only allow G38 "Probe" commands if a probe pin is defined. + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No probe pin defined"); + FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G command] #endif // Check for G0/1/2/3/38 being called with G10/28/30/92 on same block. // * G43.1 is also an axis command but is not explicitly defined this way. - if (axis_command) { + if (axis_command != AxisCommand::None) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); // [Axis word/command conflict] } - axis_command = AXIS_COMMAND_MOTION_MODE; - // No break. Continues to next line. - case 80: - word_bit = MODAL_GROUP_G1; - gc_block.modal.motion = int_value; - if (int_value == 38) { - if (!((mantissa == 20) || (mantissa == 30) || (mantissa == 40) || (mantissa == 50))) { - FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command] - } - gc_block.modal.motion += (mantissa / 10) + 100; - mantissa = 0; // Set to zero to indicate valid non-integer G command. + axis_command = AxisCommand::MotionMode; + switch (mantissa) { + case 20: gc_block.modal.motion = Motion::ProbeToward; break; + case 30: gc_block.modal.motion = Motion::ProbeTowardNoError; break; + case 40: gc_block.modal.motion = Motion::ProbeAway; break; + case 50: gc_block.modal.motion = Motion::ProbeAway; break; + default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); break; // [Unsupported G38.x command] } + mantissa = 0; // Set to zero to indicate valid non-integer G command. + mg_word_bit = ModalGroup::MG1; + break; + + case 80: // G80 - cancel canned cycle + gc_block.modal.motion = Motion::None; + mg_word_bit = ModalGroup::MG1; break; case 17: + gc_block.modal.plane_select = Plane::XY; + mg_word_bit = ModalGroup::MG2; + break; case 18: + gc_block.modal.plane_select = Plane::ZX; + mg_word_bit = ModalGroup::MG2; + break; case 19: - word_bit = MODAL_GROUP_G2; - gc_block.modal.plane_select = int_value - 17; + gc_block.modal.plane_select = Plane::YZ; + mg_word_bit = ModalGroup::MG2; break; case 90: - case 91: - if (mantissa == 0) { - word_bit = MODAL_GROUP_G3; - gc_block.modal.distance = int_value - 90; - } else { - word_bit = MODAL_GROUP_G4; - if ((mantissa != 10) || (int_value == 90)) { + switch (mantissa) { + case 0: + gc_block.modal.distance = Distance::Absolute; + mg_word_bit = ModalGroup::MG3; + break; + case 10: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [G90.1 not supported] - } - mantissa = 0; // Set to zero to indicate valid non-integer G command. - // Otherwise, arc IJK incremental mode is default. G91.1 does nothing. + // mg_word_bit = ModalGroup::MG4; + // gc_block.modal.distance_arc = ArcDistance::Absolute; + break; + default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); break; + } + break; + case 91: + switch (mantissa) { + case 0: + gc_block.modal.distance = Distance::Incremental; + mg_word_bit = ModalGroup::MG3; + break; + case 10: + mantissa = 0; // Set to zero to indicate valid non-integer G command. + // Arc incremental mode is the default and only supported mode + // gc_block.modal.distance_arc = ArcDistance::Incremental; + mg_word_bit = ModalGroup::MG4; + break; + default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); break; } break; case 93: + gc_block.modal.feed_rate = FeedRate::InverseTime; + mg_word_bit = ModalGroup::MG5; + break; case 94: - word_bit = MODAL_GROUP_G5; - gc_block.modal.feed_rate = 94 - int_value; + gc_block.modal.feed_rate = FeedRate::UnitsPerMin; + mg_word_bit = ModalGroup::MG5; break; case 20: + gc_block.modal.units = Units::Inches; + mg_word_bit = ModalGroup::MG6; + break; case 21: - word_bit = MODAL_GROUP_G6; - gc_block.modal.units = 21 - int_value; + gc_block.modal.units = Units::Mm; + mg_word_bit = ModalGroup::MG6; break; case 40: - word_bit = MODAL_GROUP_G7; // NOTE: Not required since cutter radius compensation is always disabled. Only here // to support G40 commands that often appear in g-code program headers to setup defaults. - // gc_block.modal.cutter_comp = CUTTER_COMP_DISABLE; // G40 + // gc_block.modal.cutter_comp = CutterCompensation::Disable; // G40 + mg_word_bit = ModalGroup::MG7; break; case 43: case 49: - word_bit = MODAL_GROUP_G8; // NOTE: The NIST g-code standard vaguely states that when a tool length offset is changed, // there cannot be any axis motion or coordinate offsets updated. Meaning G43, G43.1, and G49 // all are explicit axis commands, regardless if they require axis words or not. - if (axis_command) + if (axis_command != AxisCommand::None) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); + } // [Axis word/command conflict] } - axis_command = AXIS_COMMAND_TOOL_LENGTH_OFFSET; - if (int_value == 49) // G49 - gc_block.modal.tool_length = TOOL_LENGTH_OFFSET_CANCEL; - else if (mantissa == 10) // G43.1 - gc_block.modal.tool_length = TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC; - else { + axis_command = AxisCommand::ToolLengthOffset; + if (int_value == 49) { // G49 + gc_block.modal.tool_length = ToolLengthOffset::Cancel; + } else if (mantissa == 10) { // G43.1 + gc_block.modal.tool_length = ToolLengthOffset::EnableDynamic; + } else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G43.x command] } - mantissa = 0; // Set to zero to indicate valid non-integer G command. + mantissa = 0; // Set to zero to indicate valid non-integer G command. + mg_word_bit = ModalGroup::MG8; break; case 54: case 55: @@ -312,15 +377,15 @@ uint8_t gc_execute_line(char* line, uint8_t client) { case 58: case 59: // NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.) - word_bit = MODAL_GROUP_G12; gc_block.modal.coord_select = int_value - 54; // Shift to array indexing. + mg_word_bit = ModalGroup::MG12; break; case 61: - word_bit = MODAL_GROUP_G13; if (mantissa != 0) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [G61.1 not supported] } - // gc_block.modal.control = CONTROL_MODE_EXACT_PATH; // G61 + // gc_block.modal.control = ControlMode::ExactPath; // G61 + mg_word_bit = ModalGroup::MG13; break; default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G command] } @@ -328,10 +393,12 @@ uint8_t gc_execute_line(char* line, uint8_t client) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); // [Unsupported or invalid Gxx.x command] } // Check for more than one command per modal group violations in the current block - // NOTE: Variable 'word_bit' is always assigned, if the command is valid. - if (bit_istrue(command_words, bit(word_bit))) + // NOTE: Variable 'mg_word_bit' is always assigned, if the command is valid. + bitmask = bit(mg_word_bit); + if (bit_istrue(command_words, bitmask)) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); - command_words |= bit(word_bit); + } + command_words |= bitmask; break; case 'M': // Determine 'M' command and its modal group @@ -340,182 +407,194 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } switch (int_value) { case 0: + // M0 - Pause + gc_block.modal.program_flow = ProgramFlow::Paused; + mg_word_bit = ModalGroup::MM4; + break; case 1: + // M1 - Optional Stop not supported + mg_word_bit = ModalGroup::MM4; + break; case 2: + // M2 - Stop + gc_block.modal.program_flow = ProgramFlow::CompletedM2; + mg_word_bit = ModalGroup::MM4; + break; case 30: - word_bit = MODAL_GROUP_M4; - switch (int_value) { - case 0: gc_block.modal.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause - case 1: break; // Optional stop not supported. Ignore. - default: gc_block.modal.program_flow = int_value; // Program end and reset - } + // M30 - End + gc_block.modal.program_flow = ProgramFlow::CompletedM30; + mg_word_bit = ModalGroup::MM4; break; case 3: case 4: case 5: - word_bit = MODAL_GROUP_M7; switch (int_value) { - case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break; + case 3: gc_block.modal.spindle = SpindleState::Cw; break; case 4: // Supported if SPINDLE_DIR_PIN is defined or laser mode is on. - if (spindle->is_reversable || laser_mode->get()) - gc_block.modal.spindle = SPINDLE_ENABLE_CCW; - else + if (spindle->is_reversable || laser_mode->get()) { + gc_block.modal.spindle = SpindleState::Ccw; + } else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); + } break; - case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break; + case 5: gc_block.modal.spindle = SpindleState::Disable; break; } + mg_word_bit = ModalGroup::MM7; break; case 6: // tool change - word_bit = MODAL_GROUP_M6; - gc_block.modal.tool_change = TOOL_CHANGE; + gc_block.modal.tool_change = ToolChange::Enable; #ifdef USE_TOOL_CHANGE //user_tool_change(gc_state.tool); #endif + mg_word_bit = ModalGroup::MM6; break; case 7: case 8: case 9: - word_bit = MODAL_GROUP_M8; switch (int_value) { #ifdef COOLANT_MIST_PIN - case 7: gc_block.modal.coolant = COOLANT_MIST_ENABLE; break; + case 7: gc_block.modal.coolant = CoolantMode::Mist; break; #endif #ifdef COOLANT_FLOOD_PIN - case 8: gc_block.modal.coolant = COOLANT_FLOOD_ENABLE; break; + case 8: gc_block.modal.coolant = CoolantMode::Flood; break; #endif - case 9: gc_block.modal.coolant = COOLANT_DISABLE; break; + case 9: gc_block.modal.coolant = CoolantMode::Disable; break; } + mg_word_bit = ModalGroup::MM8; break; #ifdef ENABLE_PARKING_OVERRIDE_CONTROL case 56: - word_bit = MODAL_GROUP_M9; - gc_block.modal.override = OVERRIDE_PARKING_MOTION; + gc_block.modal.override = Override::ParkingMotion; + mg_word_bit = ModalGroup::MM9; break; #endif case 62: + gc_block.modal.io_control = IoControl::Enable; + mg_word_bit = ModalGroup::MM10; + break; case 63: - //grbl_sendf(CLIENT_SERIAL,"M%d...\r\n", int_value); - word_bit = MODAL_GROUP_M10; - switch (int_value) { - case 62: gc_block.modal.io_control = NON_MODAL_IO_ENABLE; break; - case 63: gc_block.modal.io_control = NON_MODAL_IO_DISABLE; break; - default: break; - } + gc_block.modal.io_control = IoControl::Disable; + mg_word_bit = ModalGroup::MM10; break; default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command] } // Check for more than one command per modal group violations in the current block - // NOTE: Variable 'word_bit' is always assigned, if the command is valid. - if (bit_istrue(command_words, bit(word_bit))) + // NOTE: Variable 'mg_word_bit' is always assigned, if the command is valid. + bitmask = bit(mg_word_bit); + if (bit_istrue(command_words, bitmask)) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); - command_words |= bit(word_bit); + } + command_words |= bitmask; break; // NOTE: All remaining letters assign values. default: /* Non-Command Words: This initial parsing phase only checks for repeats of the remaining legal g-code words and stores their value. Error-checking is performed later since some words (I,J,K,L,P,R) have multiple connotations and/or depend on the issued commands. */ + GCodeWord axis_word_bit; switch (letter) { #if (N_AXIS > A_AXIS) case 'A': - word_bit = WORD_A; + axis_word_bit = GCodeWord::A; gc_block.values.xyz[A_AXIS] = value; axis_words |= bit(A_AXIS); break; #endif #if (N_AXIS > B_AXIS) case 'B': - word_bit = WORD_B; + axis_word_bit = GCodeWord::B; gc_block.values.xyz[B_AXIS] = value; axis_words |= bit(B_AXIS); break; #endif #if (N_AXIS > C_AXIS) case 'C': - word_bit = WORD_C; + axis_word_bit = GCodeWord::C; gc_block.values.xyz[C_AXIS] = value; axis_words |= bit(C_AXIS); break; #endif // case 'D': // Not supported case 'F': - word_bit = WORD_F; + axis_word_bit = GCodeWord::F; gc_block.values.f = value; break; // case 'H': // Not supported case 'I': - word_bit = WORD_I; + axis_word_bit = GCodeWord::I; gc_block.values.ijk[X_AXIS] = value; ijk_words |= bit(X_AXIS); break; case 'J': - word_bit = WORD_J; + axis_word_bit = GCodeWord::J; gc_block.values.ijk[Y_AXIS] = value; ijk_words |= bit(Y_AXIS); break; case 'K': - word_bit = WORD_K; + axis_word_bit = GCodeWord::K; gc_block.values.ijk[Z_AXIS] = value; ijk_words |= bit(Z_AXIS); break; case 'L': - word_bit = WORD_L; + axis_word_bit = GCodeWord::L; gc_block.values.l = int_value; break; case 'N': - word_bit = WORD_N; + axis_word_bit = GCodeWord::N; gc_block.values.n = trunc(value); break; case 'P': - word_bit = WORD_P; + axis_word_bit = GCodeWord::P; gc_block.values.p = value; break; // NOTE: For certain commands, P value must be an integer, but none of these commands are supported. // case 'Q': // Not supported case 'R': - word_bit = WORD_R; + axis_word_bit = GCodeWord::R; gc_block.values.r = value; break; case 'S': - word_bit = WORD_S; + axis_word_bit = GCodeWord::S; gc_block.values.s = value; break; case 'T': - word_bit = WORD_T; - if (value > MAX_TOOL_NUMBER) + axis_word_bit = GCodeWord::T; + if (value > MaxToolNumber) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); + } grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Tool No: %d", int_value); gc_state.tool = int_value; break; case 'X': - word_bit = WORD_X; + axis_word_bit = GCodeWord::X; gc_block.values.xyz[X_AXIS] = value; axis_words |= bit(X_AXIS); break; case 'Y': - word_bit = WORD_Y; + axis_word_bit = GCodeWord::Y; gc_block.values.xyz[Y_AXIS] = value; axis_words |= bit(Y_AXIS); break; case 'Z': - word_bit = WORD_Z; + axis_word_bit = GCodeWord::Z; gc_block.values.xyz[Z_AXIS] = value; axis_words |= bit(Z_AXIS); break; default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } - // NOTE: Variable 'word_bit' is always assigned, if the non-command letter is valid. - if (bit_istrue(value_words, bit(word_bit))) { + // NOTE: Variable 'axis_word_bit' is always assigned, if the non-command letter is valid. + bitmask = bit(axis_word_bit); + if (bit_istrue(value_words, bitmask)) { FAIL(STATUS_GCODE_WORD_REPEATED); // [Word repeated] } // Check for invalid negative values for words F, N, P, T, and S. // NOTE: Negative value check is done here simply for code-efficiency. - if (bit(word_bit) & (bit(WORD_F) | bit(WORD_N) | bit(WORD_P) | bit(WORD_T) | bit(WORD_S))) { + if (bitmask & (bit(GCodeWord::F) | bit(GCodeWord::N) | bit(GCodeWord::P) | bit(GCodeWord::T) | bit(GCodeWord::S))) { if (value < 0.0) { FAIL(STATUS_NEGATIVE_VALUE); // [Word value cannot be negative] } } - value_words |= bit(word_bit); // Flag to indicate parameter assigned. + value_words |= bitmask; // Flag to indicate parameter assigned. } } // Parsing complete! @@ -547,18 +626,18 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // Determine implicit axis command conditions. Axis words have been passed, but no explicit axis // command has been sent. If so, set axis command to current motion mode. if (axis_words) { - if (!axis_command) { - axis_command = AXIS_COMMAND_MOTION_MODE; // Assign implicit motion-mode + if (axis_command == AxisCommand::None) { + axis_command = AxisCommand::MotionMode; // Assign implicit motion-mode } } // Check for valid line number N value. - if (bit_istrue(value_words, bit(WORD_N))) { + if (bit_istrue(value_words, bit(GCodeWord::N))) { // Line number value cannot be less than zero (done) or greater than max line number. - if (gc_block.values.n > MAX_LINE_NUMBER) { + if (gc_block.values.n > MaxLineNumber) { FAIL(STATUS_GCODE_INVALID_LINE_NUMBER); // [Exceeds max line number] } } - // bit_false(value_words,bit(WORD_N)); // NOTE: Single-meaning value word. Set at end of error-checking. + // bit_false(value_words,bit(GCodeWord::N)); // NOTE: Single-meaning value word. Set at end of error-checking. // Track for unused words at the end of error-checking. // NOTE: Single-meaning value words are removed all at once at the end of error-checking, because // they are always used when present. This was done to save a few bytes of flash. For clarity, the @@ -569,17 +648,19 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate // is not defined after switching to G94 from G93. // NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word. - if (gc_parser_flags & GC_PARSER_JOG_MOTION) { - if (bit_isfalse(value_words, bit(WORD_F))) + if (gc_parser_flags & GCParserJogMotion) { + if (bit_isfalse(value_words, bit(GCodeWord::F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); - if (gc_block.modal.units == UNITS_MODE_INCHES) + } + if (gc_block.modal.units == Units::Inches) { gc_block.values.f *= MM_PER_INCH; + } } else { - if (gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93 + if (gc_block.modal.feed_rate == FeedRate::InverseTime) { // = G93 // NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here. - if (axis_command == AXIS_COMMAND_MOTION_MODE) { - if ((gc_block.modal.motion != MOTION_MODE_NONE) || (gc_block.modal.motion != MOTION_MODE_SEEK)) { - if (bit_isfalse(value_words, bit(WORD_F))) { + if (axis_command == AxisCommand::MotionMode) { + if ((gc_block.modal.motion != Motion::None) || (gc_block.modal.motion != Motion::Seek)) { + if (bit_isfalse(value_words, bit(GCodeWord::F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); // [F word missing] } } @@ -597,62 +678,65 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // a feed rate, we simply move on and the state feed rate value gets updated to zero and remains undefined. } else { // = G94 // - In units per mm mode: If F word passed, ensure value is in mm/min, otherwise push last state value. - if (gc_state.modal.feed_rate == FEED_RATE_MODE_UNITS_PER_MIN) { // Last state is also G94 - if (bit_istrue(value_words, bit(WORD_F))) { - if (gc_block.modal.units == UNITS_MODE_INCHES) + if (gc_state.modal.feed_rate == FeedRate::UnitsPerMin) { // Last state is also G94 + if (bit_istrue(value_words, bit(GCodeWord::F))) { + if (gc_block.modal.units == Units::Inches) { gc_block.values.f *= MM_PER_INCH; + } } else { gc_block.values.f = gc_state.feed_rate; // Push last state feed rate } } // Else, switching to G94 from G93, so don't push last state feed rate. Its undefined or the passed F word value. } } - // bit_false(value_words,bit(WORD_F)); // NOTE: Single-meaning value word. Set at end of error-checking. + // bit_false(value_words,bit(GCodeWord::F)); // NOTE: Single-meaning value word. Set at end of error-checking. // [4. Set spindle speed ]: S is negative (done.) - if (bit_isfalse(value_words, bit(WORD_S))) + if (bit_isfalse(value_words, bit(GCodeWord::S))) { gc_block.values.s = gc_state.spindle_speed; - // bit_false(value_words,bit(WORD_S)); // NOTE: Single-meaning value word. Set at end of error-checking. + // bit_false(value_words,bit(GCodeWord::S)); // NOTE: Single-meaning value word. Set at end of error-checking. // [5. Select tool ]: NOT SUPPORTED. Only tracks value. T is negative (done.) Not an integer. Greater than max tool value. - // bit_false(value_words,bit(WORD_T)); // NOTE: Single-meaning value word. Set at end of error-checking. + // bit_false(value_words,bit(GCodeWord::T)); // NOTE: Single-meaning value word. Set at end of error-checking. // [6. Change tool ]: N/A // [7. Spindle control ]: N/A // [8. Coolant control ]: N/A // [9. Enable/disable feed rate or spindle overrides ]: NOT SUPPORTED. + } #ifdef ENABLE_PARKING_OVERRIDE_CONTROL - if (bit_istrue(command_words, bit(MODAL_GROUP_M9))) { // Already set as enabled in parser. - if (bit_istrue(value_words, bit(WORD_P))) { - if (gc_block.values.p == 0.0) - gc_block.modal.override = OVERRIDE_DISABLED; - bit_false(value_words, bit(WORD_P)); + if (bit_istrue(command_words, bit(ModalGroup::MM9))) { // Already set as enabled in parser. + if (bit_istrue(value_words, bit(GCodeWord::P))) { + if (gc_block.values.p == 0.0) { + gc_block.modal.override = Override::Disabled; + } + bit_false(value_words, bit(GCodeWord::P)); } } #endif // [10. Dwell ]: P value missing. P is negative (done.) NOTE: See below. - if (gc_block.non_modal_command == NON_MODAL_DWELL) { - if (bit_isfalse(value_words, bit(WORD_P))) { + if (gc_block.non_modal_command == NonModal::Dwell) { + if (bit_isfalse(value_words, bit(GCodeWord::P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); // [P word missing] } - bit_false(value_words, bit(WORD_P)); + bit_false(value_words, bit(GCodeWord::P)); } - if ((gc_block.modal.io_control == NON_MODAL_IO_ENABLE) || (gc_block.modal.io_control == NON_MODAL_IO_DISABLE)) { - if (bit_isfalse(value_words, bit(WORD_P))) { + if ((gc_block.modal.io_control == IoControl::Enable) || (gc_block.modal.io_control == IoControl::Disable)) { + if (bit_isfalse(value_words, bit(GCodeWord::P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); // [P word missing] } - bit_false(value_words, bit(WORD_P)); + bit_false(value_words, bit(GCodeWord::P)); } // [11. Set active plane ]: N/A switch (gc_block.modal.plane_select) { - case PLANE_SELECT_XY: + case Plane::XY: axis_0 = X_AXIS; axis_1 = Y_AXIS; axis_linear = Z_AXIS; break; - case PLANE_SELECT_ZX: + case Plane::ZX: axis_0 = Z_AXIS; axis_1 = X_AXIS; axis_linear = Y_AXIS; break; - default: // case PLANE_SELECT_YZ: + default: // case Plane::YZ: axis_0 = Y_AXIS; axis_1 = Z_AXIS; axis_linear = X_AXIS; @@ -660,10 +744,11 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // [12. Set length units ]: N/A // Pre-convert XYZ coordinate values to millimeters, if applicable. uint8_t idx; - if (gc_block.modal.units == UNITS_MODE_INCHES) { + if (gc_block.modal.units == Units::Inches) { for (idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used. - if (bit_istrue(axis_words, bit(idx))) + if (bit_istrue(axis_words, bit(idx))) { gc_block.values.xyz[idx] *= MM_PER_INCH; + } } } // [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED. Error, if enabled while G53 is active. @@ -675,10 +760,11 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // NOTE: Although not explicitly stated so, G43.1 should be applied to only one valid // axis that is configured (in config.h). There should be an error if the configured axis // is absent or if any of the other axis words are present. - if (axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET) { // Indicates called in block. - if (gc_block.modal.tool_length == TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC) { - if (axis_words ^ bit(TOOL_LENGTH_OFFSET_AXIS)) + if (axis_command == AxisCommand::ToolLengthOffset) { // Indicates called in block. + if (gc_block.modal.tool_length == ToolLengthOffset::EnableDynamic) { + if (axis_words ^ bit(TOOL_LENGTH_OFFSET_AXIS)) { FAIL(STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR); + } } } // [15. Coordinate system selection ]: *N/A. Error, if cutter radius comp is active. @@ -688,13 +774,14 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // in memory and written to EEPROM only when there is not a cycle active. float block_coord_system[N_AXIS]; memcpy(block_coord_system, gc_state.coord_system, sizeof(gc_state.coord_system)); - if (bit_istrue(command_words, bit(MODAL_GROUP_G12))) { // Check if called in block + if (bit_istrue(command_words, bit(ModalGroup::MG12))) { // Check if called in block if (gc_block.modal.coord_select > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); // [Greater than N sys] } if (gc_state.modal.coord_select != gc_block.modal.coord_select) { - if (!(settings_read_coord_data(gc_block.modal.coord_select, block_coord_system))) + if (!(settings_read_coord_data(gc_block.modal.coord_select, block_coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); + } } } // [16. Set path control mode ]: N/A. Only G61. G61.1 and G64 NOT SUPPORTED. @@ -706,14 +793,14 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // the axis value, G92 similarly to G10 L20, and G28/30 as an intermediate target position that observes // all the current coordinate system and G92 offsets. switch (gc_block.non_modal_command) { - case NON_MODAL_SET_COORDINATE_DATA: + case NonModal::SetCoordinateData: // [G10 Errors]: L missing and is not 2 or 20. P word missing. (Negative P value done.) // [G10 L2 Errors]: R word NOT SUPPORTED. P value not 0 to nCoordSys(max 9). Axis words missing. // [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing. if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS) }; // [No axis words] - if (bit_isfalse(value_words, (bit(WORD_P) | bit(WORD_L)))) { + if (bit_isfalse(value_words, (bit(GCodeWord::P) | bit(GCodeWord::L)))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); // [P/L word missing] } coord_select = trunc(gc_block.values.p); // Convert p value to int. @@ -722,14 +809,14 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } if (gc_block.values.l != 20) { if (gc_block.values.l == 2) { - if (bit_istrue(value_words, bit(WORD_R))) { + if (bit_istrue(value_words, bit(GCodeWord::R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [G10 L2 R not supported] } } else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported L] } } - bit_false(value_words, (bit(WORD_L) | bit(WORD_P))); + bit_false(value_words, (bit(GCodeWord::L) | bit(GCodeWord::P))); // Determine coordinate system to change and try to load from EEPROM. if (coord_select > 0) { coord_select--; // Adjust P1-P6 index to EEPROM coordinate data indexing. @@ -749,8 +836,9 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // L20: Update coordinate system axis at current position (with modifiers) with programmed value // WPos = MPos - WCS - G92 - TLO -> WCS = MPos - G92 - TLO - WPos gc_block.values.ijk[idx] = gc_state.position[idx] - gc_state.coord_offset[idx] - gc_block.values.xyz[idx]; - if (idx == TOOL_LENGTH_OFFSET_AXIS) + if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.ijk[idx] -= gc_state.tool_length_offset; + } } else { // L2: Update coordinate system axis to programmed value. gc_block.values.ijk[idx] = gc_block.values.xyz[idx]; @@ -758,7 +846,7 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } // Else, keep current stored value. } break; - case NON_MODAL_SET_COORDINATE_OFFSET: + case NonModal::SetCoordinateOffset: // [G92 Errors]: No axis words. if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); // [No axis words] @@ -769,10 +857,12 @@ uint8_t gc_execute_line(char* line, uint8_t client) { if (bit_istrue(axis_words, bit(idx))) { // WPos = MPos - WCS - G92 - TLO -> G92 = MPos - WCS - TLO - WPos gc_block.values.xyz[idx] = gc_state.position[idx] - block_coord_system[idx] - gc_block.values.xyz[idx]; - if (idx == TOOL_LENGTH_OFFSET_AXIS) + if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.xyz[idx] -= gc_state.tool_length_offset; - } else + } + } else { gc_block.values.xyz[idx] = gc_state.coord_offset[idx]; + } } break; default: @@ -780,7 +870,7 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // target position with the coordinate system offsets, G92 offsets, absolute override, and distance // modes applied. This includes the motion mode commands. We can now pre-compute the target position. // NOTE: Tool offsets may be appended to these conversions when/if this feature is added. - if (axis_command != AXIS_COMMAND_TOOL_LENGTH_OFFSET) { // TLO block any axis command. + if (axis_command != AxisCommand::ToolLengthOffset) { // TLO block any axis command. if (axis_words) { for (idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space. if (bit_isfalse(axis_words, bit(idx))) { @@ -788,14 +878,16 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } else { // Update specified value according to distance mode or ignore if absolute override is active. // NOTE: G53 is never active with G28/30 since they are in the same modal group. - if (gc_block.non_modal_command != NON_MODAL_ABSOLUTE_OVERRIDE) { + if (gc_block.non_modal_command != NonModal::AbsoluteOverride) { // Apply coordinate offsets based on distance mode. - if (gc_block.modal.distance == DISTANCE_MODE_ABSOLUTE) { + if (gc_block.modal.distance == Distance::Absolute) { gc_block.values.xyz[idx] += block_coord_system[idx] + gc_state.coord_offset[idx]; - if (idx == TOOL_LENGTH_OFFSET_AXIS) + if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.xyz[idx] += gc_state.tool_length_offset; - } else // Incremental mode + } + } else { // Incremental mode gc_block.values.xyz[idx] += gc_state.position[idx]; + } } } } @@ -803,47 +895,51 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } // Check remaining non-modal commands for errors. switch (gc_block.non_modal_command) { - case NON_MODAL_GO_HOME_0: // G28 - case NON_MODAL_GO_HOME_1: // G30 + case NonModal::GoHome0: // G28 + case NonModal::GoHome1: // G30 // [G28/30 Errors]: Cutter compensation is enabled. // Retreive G28/30 go-home position data (in machine coordinates) from EEPROM // NOTE: Store parameter data in IJK values. By rule, they are not in use with this command. - if (gc_block.non_modal_command == NON_MODAL_GO_HOME_0) { - if (!settings_read_coord_data(SETTING_INDEX_G28, gc_block.values.ijk)) + if (gc_block.non_modal_command == NonModal::GoHome0) { + if (!settings_read_coord_data(SETTING_INDEX_G28, gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); - } else { // == NON_MODAL_GO_HOME_1 - if (!settings_read_coord_data(SETTING_INDEX_G30, gc_block.values.ijk)) + } + } else { // == NonModal::GoHome1 + if (!settings_read_coord_data(SETTING_INDEX_G30, gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); + } } if (axis_words) { // Move only the axes specified in secondary move. for (idx = 0; idx < N_AXIS; idx++) { - if (!(axis_words & bit(idx))) + if (!(axis_words & bit(idx))) { gc_block.values.ijk[idx] = gc_state.position[idx]; + } } } else { - axis_command = AXIS_COMMAND_NONE; // Set to none if no intermediate motion. + axis_command = AxisCommand::None; // Set to none if no intermediate motion. } break; - case NON_MODAL_SET_HOME_0: // G28.1 - case NON_MODAL_SET_HOME_1: // G30.1 + case NonModal::SetHome0: // G28.1 + case NonModal::SetHome1: // G30.1 // [G28.1/30.1 Errors]: Cutter compensation is enabled. // NOTE: If axis words are passed here, they are interpreted as an implicit motion mode. break; - case NON_MODAL_RESET_COORDINATE_OFFSET: + case NonModal::ResetCoordinateOffset: // NOTE: If axis words are passed here, they are interpreted as an implicit motion mode. break; - case NON_MODAL_ABSOLUTE_OVERRIDE: + case NonModal::AbsoluteOverride: // [G53 Errors]: G0 and G1 are not active. Cutter compensation is enabled. // NOTE: All explicit axis word commands are in this modal group. So no implicit check necessary. - if (!(gc_block.modal.motion == MOTION_MODE_SEEK || gc_block.modal.motion == MOTION_MODE_LINEAR)) { + if (!(gc_block.modal.motion == Motion::Seek || gc_block.modal.motion == Motion::Linear)) { FAIL(STATUS_GCODE_G53_INVALID_MOTION_MODE); // [G53 G0/1 not active] } break; + default: break; } } // [20. Motion modes ]: - if (gc_block.modal.motion == MOTION_MODE_NONE) { + if (gc_block.modal.motion == Motion::None) { // [G80 Errors]: Axis word are programmed while G80 is active. // NOTE: Even non-modal commands or TLO that use axis words will throw this strict error. if (axis_words) { @@ -851,12 +947,13 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } // Check remaining motion modes, if axis word are implicit (exist and not used by G10/28/30/92), or // was explicitly commanded in the g-code block. - } else if (axis_command == AXIS_COMMAND_MOTION_MODE) { - if (gc_block.modal.motion == MOTION_MODE_SEEK) { + } else if (axis_command == AxisCommand::MotionMode) { + if (gc_block.modal.motion == Motion::Seek) { // [G0 Errors]: Axis letter not configured or without real value (done.) // Axis words are optional. If missing, set axis command flag to ignore execution. - if (!axis_words) - axis_command = AXIS_COMMAND_NONE; + if (!axis_words) { + axis_command = AxisCommand::None; + } // All remaining motion modes (all but G0 and G80), require a valid feed rate value. In units per mm mode, // the value must be positive. In inverse time mode, a positive value must be passed with each block. } else { @@ -865,14 +962,17 @@ uint8_t gc_execute_line(char* line, uint8_t client) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); // [Feed rate undefined] } switch (gc_block.modal.motion) { - case MOTION_MODE_LINEAR: + case Motion::None: break; // Feed rate is unnecessary + case Motion::Seek: break; // Feed rate is unnecessary + case Motion::Linear: // [G1 Errors]: Feed rate undefined. Axis letter not configured or without real value. // Axis words are optional. If missing, set axis command flag to ignore execution. - if (!axis_words) - axis_command = AXIS_COMMAND_NONE; + if (!axis_words) { + axis_command = AxisCommand::None; + } break; - case MOTION_MODE_CW_ARC: gc_parser_flags |= GC_PARSER_ARC_IS_CLOCKWISE; // No break intentional. - case MOTION_MODE_CCW_ARC: + case Motion::CwArc: gc_parser_flags |= GCParserArcIsClockwise; // No break intentional. + case Motion::CcwArc: // [G2/3 Errors All-Modes]: Feed rate undefined. // [G2/3 Radius-Mode Errors]: No axis words in selected plane. Target point is same as current. // [G2/3 Offset-Mode Errors]: No axis words and/or offsets in selected plane. The radius to the current @@ -889,14 +989,15 @@ uint8_t gc_execute_line(char* line, uint8_t client) { float x, y; x = gc_block.values.xyz[axis_0] - gc_state.position[axis_0]; // Delta x between current position and target y = gc_block.values.xyz[axis_1] - gc_state.position[axis_1]; // Delta y between current position and target - if (value_words & bit(WORD_R)) { // Arc Radius Mode - bit_false(value_words, bit(WORD_R)); + if (value_words & bit(GCodeWord::R)) { // Arc Radius Mode + bit_false(value_words, bit(GCodeWord::R)); if (isequal_position_vector(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); // [Invalid target] } // Convert radius value to proper units. - if (gc_block.modal.units == UNITS_MODE_INCHES) + if (gc_block.modal.units == Units::Inches) { gc_block.values.r *= MM_PER_INCH; + } /* We need to calculate the center of the circle that has the designated radius and passes through both the current position and the target position. This method calculates the following set of equations where [x,y] is the vector from current to target position, d == magnitude of @@ -953,8 +1054,9 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // Finish computing h_x2_div_d. h_x2_div_d = -sqrt(h_x2_div_d) / hypot_f(x, y); // == -(h * 2 / d) // Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below) - if (gc_block.modal.motion == MOTION_MODE_CCW_ARC) + if (gc_block.modal.motion == Motion::CcwArc) { h_x2_div_d = -h_x2_div_d; + } /* The counter clockwise circle lies to the left of the target direction. When offset is positive, the left hand circle will be generated - when it is negative the right hand circle is generated. @@ -985,12 +1087,13 @@ uint8_t gc_execute_line(char* line, uint8_t client) { if (!(ijk_words & (bit(axis_0) | bit(axis_1)))) { FAIL(STATUS_GCODE_NO_OFFSETS_IN_PLANE); // [No offsets in plane] } - bit_false(value_words, (bit(WORD_I) | bit(WORD_J) | bit(WORD_K))); + bit_false(value_words, (bit(GCodeWord::I) | bit(GCodeWord::J) | bit(GCodeWord::K))); // Convert IJK values to proper units. - if (gc_block.modal.units == UNITS_MODE_INCHES) { + if (gc_block.modal.units == Units::Inches) { for (idx = 0; idx < N_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space. - if (ijk_words & bit(idx)) + if (ijk_words & bit(idx)) { gc_block.values.ijk[idx] *= MM_PER_INCH; + } } } // Arc radius from center to target @@ -1011,12 +1114,13 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } } break; - case MOTION_MODE_PROBE_TOWARD_NO_ERROR: - case MOTION_MODE_PROBE_AWAY_NO_ERROR: gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional. - case MOTION_MODE_PROBE_TOWARD: - case MOTION_MODE_PROBE_AWAY: - if ((gc_block.modal.motion == MOTION_MODE_PROBE_AWAY) || (gc_block.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) - gc_parser_flags |= GC_PARSER_PROBE_IS_AWAY; + case Motion::ProbeTowardNoError: + case Motion::ProbeAwayNoError: gc_parser_flags |= GCParserProbeIsNoError; // No break intentional. + case Motion::ProbeToward: + case Motion::ProbeAway: + if ((gc_block.modal.motion == Motion::ProbeAway) || (gc_block.modal.motion == Motion::ProbeAwayNoError)) { + gc_parser_flags |= GCParserProbeIsAway; + } // [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate // is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning // an error, it issues an alarm to prevent further motion to the probe. It's also done there to @@ -1034,14 +1138,17 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // [21. Program flow ]: No error checks required. // [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc // radius mode, or axis words that aren't used in the block. - if (gc_parser_flags & GC_PARSER_JOG_MOTION) { + if (gc_parser_flags & GCParserJogMotion) { // Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid. - bit_false(value_words, (bit(WORD_N) | bit(WORD_F))); + bit_false(value_words, (bit(GCodeWord::N) | bit(GCodeWord::F))); } else { - bit_false(value_words, (bit(WORD_N) | bit(WORD_F) | bit(WORD_S) | bit(WORD_T))); // Remove single-meaning value words. + bit_false(value_words, + (bit(GCodeWord::N) | bit(GCodeWord::F) | bit(GCodeWord::S) | bit(GCodeWord::T))); // Remove single-meaning value words. } - if (axis_command) { - bit_false(value_words, (bit(WORD_X) | bit(WORD_Y) | bit(WORD_Z) | bit(WORD_A) | bit(WORD_B) | bit(WORD_C))); // Remove axis words. + if (axis_command != AxisCommand::None) { + bit_false(value_words, + (bit(GCodeWord::X) | bit(GCodeWord::Y) | bit(GCodeWord::Z) | bit(GCodeWord::A) | bit(GCodeWord::B) | + bit(GCodeWord::C))); // Remove axis words. } if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); // [Unused words] @@ -1059,45 +1166,50 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // NOTE: G-code parser state is not updated, except the position to ensure sequential jog // targets are computed correctly. The final parser position after a jog is updated in // protocol_execute_realtime() when jogging completes or is canceled. - if (gc_parser_flags & GC_PARSER_JOG_MOTION) { + if (gc_parser_flags & GCParserJogMotion) { // Only distance and unit modal commands and G53 absolute override command are allowed. // NOTE: Feed rate word and axis word checks have already been performed in STEP 3. - if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6) | bit(MODAL_GROUP_G0))) { + if (command_words & ~(bit(ModalGroup::MG3) | bit(ModalGroup::MG6) | bit(ModalGroup::MG0))) { FAIL(STATUS_INVALID_JOG_COMMAND) }; - if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) + if (!(gc_block.non_modal_command == NonModal::AbsoluteOverride || gc_block.non_modal_command == NonModal::NoAction)) { FAIL(STATUS_INVALID_JOG_COMMAND); + } // Initialize planner data to current spindle and coolant modal state. pl_data->spindle_speed = gc_state.spindle_speed; - plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant); - uint8_t status = jog_execute(&plan_data, &gc_block); - if (status == STATUS_OK) + pl_data->spindle = gc_state.modal.spindle; + pl_data->coolant = gc_state.modal.coolant; + uint8_t status = jog_execute(pl_data, &gc_block); + if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); + } return (status); } // If in laser mode, setup laser power based on current and past parser conditions. if (laser_mode->get()) { - if (!((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC) || - (gc_block.modal.motion == MOTION_MODE_CCW_ARC))) - gc_parser_flags |= GC_PARSER_LASER_DISABLE; + if (!((gc_block.modal.motion == Motion::Linear) || (gc_block.modal.motion == Motion::CwArc) || + (gc_block.modal.motion == Motion::CcwArc))) { + gc_parser_flags |= GCParserLaserDisable; + } // Any motion mode with axis words is allowed to be passed from a spindle speed update. // NOTE: G1 and G0 without axis words sets axis_command to none. G28/30 are intentionally omitted. // TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length). - if (axis_words && (axis_command == AXIS_COMMAND_MOTION_MODE)) - gc_parser_flags |= GC_PARSER_LASER_ISMOTION; - else { + if (axis_words && (axis_command == AxisCommand::MotionMode)) { + gc_parser_flags |= GCParserLaserIsMotion; + } else { // M3 constant power laser requires planner syncs to update the laser when changing between // a G1/2/3 motion mode state and vice versa when there is no motion in the line. - if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) { - if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC) || - (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) { - if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { - gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode. + if (gc_state.modal.spindle == SpindleState::Cw) { + if ((gc_state.modal.motion == Motion::Linear) || (gc_state.modal.motion == Motion::CwArc) || + (gc_state.modal.motion == Motion::CcwArc)) { + if (bit_istrue(gc_parser_flags, GCParserLaserDisable)) { + gc_parser_flags |= GCParserLaserForceSync; // Change from G1/2/3 motion mode. } } else { // When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode. - if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) - gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; + if (bit_isfalse(gc_parser_flags, GCParserLaserDisable)) { + gc_parser_flags |= GCParserLaserForceSync; + } } } } @@ -1111,32 +1223,33 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // [1. Comments feedback ]: NOT SUPPORTED // [2. Set feed rate mode ]: gc_state.modal.feed_rate = gc_block.modal.feed_rate; - if (gc_state.modal.feed_rate) { - pl_data->condition |= PL_COND_FLAG_INVERSE_TIME; // Set condition flag for planner use. + if (gc_state.modal.feed_rate == FeedRate::InverseTime) { + pl_data->motion |= PL_MOTION_INVERSE_TIME; // Set condition flag for planner use. } // [3. Set feed rate ]: gc_state.feed_rate = gc_block.values.f; // Always copy this value. See feed rate error-checking. pl_data->feed_rate = gc_state.feed_rate; // Record data for planner use. // [4. Set spindle speed ]: - if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags, GC_PARSER_LASER_FORCE_SYNC)) { - if (gc_state.modal.spindle != SPINDLE_DISABLE) { - if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_ISMOTION)) { - if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) + if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags, GCParserLaserForceSync)) { + if (gc_state.modal.spindle != SpindleState::Disable) { + if (bit_isfalse(gc_parser_flags, GCParserLaserIsMotion)) { + if (bit_istrue(gc_parser_flags, GCParserLaserDisable)) { spindle->sync(gc_state.modal.spindle, 0); - else + } else { spindle->sync(gc_state.modal.spindle, (uint32_t)gc_block.values.s); + } } } gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state. } // NOTE: Pass zero spindle speed for all restricted laser motions. - if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { + if (bit_isfalse(gc_parser_flags, GCParserLaserDisable)) { pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use. } // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already. // [5. Select tool ]: NOT SUPPORTED. Only tracks tool value. // gc_state.tool = gc_block.values.t; // [6. Change tool ]: NOT SUPPORTED - if (gc_block.modal.tool_change == TOOL_CHANGE) { + if (gc_block.modal.tool_change == ToolChange::Enable) { #ifdef USE_TOOL_CHANGE user_tool_change(gc_state.tool); #endif @@ -1149,24 +1262,27 @@ uint8_t gc_execute_line(char* line, uint8_t client) { spindle->sync(gc_block.modal.spindle, (uint32_t)pl_data->spindle_speed); gc_state.modal.spindle = gc_block.modal.spindle; } - pl_data->condition |= gc_state.modal.spindle; // Set condition flag for planner use. + pl_data->spindle = gc_state.modal.spindle; // [8. Coolant control ]: if (gc_state.modal.coolant != gc_block.modal.coolant) { // NOTE: Coolant M-codes are modal. Only one command per line is allowed. But, multiple states // can exist at the same time, while coolant disable clears all states. coolant_sync(gc_block.modal.coolant); - if (gc_block.modal.coolant == COOLANT_DISABLE) - gc_state.modal.coolant = COOLANT_DISABLE; - else - gc_state.modal.coolant |= gc_block.modal.coolant; + if (gc_block.modal.coolant == CoolantMode::Disable) { + gc_state.modal.coolant = CoolantMode::Disable; + } else { + gc_state.modal.coolant = + static_cast(static_cast(gc_state.modal.coolant) | static_cast(gc_block.modal.coolant)); + } } - pl_data->condition |= gc_state.modal.coolant; // Set condition flag for planner use. + pl_data->coolant = gc_state.modal.coolant; // Set state for planner use. // turn on/off an i/o pin - if ((gc_block.modal.io_control == NON_MODAL_IO_ENABLE) || (gc_block.modal.io_control == NON_MODAL_IO_DISABLE)) { - if (gc_block.values.p <= MAX_USER_DIGITAL_PIN) - sys_io_control(bit((int)gc_block.values.p), (gc_block.modal.io_control == NON_MODAL_IO_ENABLE)); - else + if ((gc_block.modal.io_control == IoControl::Enable) || (gc_block.modal.io_control == IoControl::Disable)) { + if (gc_block.values.p <= MaxUserDigitalPin) { + sys_io_control(bit((int)gc_block.values.p), (gc_block.modal.io_control == IoControl::Enable)); + } else { FAIL(STATUS_P_PARAM_MAX_EXCEEDED); + } } // [9. Override control ]: NOT SUPPORTED. Always enabled. Except for a Grbl-only parking control. #ifdef ENABLE_PARKING_OVERRIDE_CONTROL @@ -1176,8 +1292,9 @@ uint8_t gc_execute_line(char* line, uint8_t client) { } #endif // [10. Dwell ]: - if (gc_block.non_modal_command == NON_MODAL_DWELL) + if (gc_block.non_modal_command == NonModal::Dwell) { mc_dwell(gc_block.values.p); + } // [11. Set active plane ]: gc_state.modal.plane_select = gc_block.modal.plane_select; // [12. Set length units ]: @@ -1188,10 +1305,11 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // NOTE: If G43 were supported, its operation wouldn't be any different from G43.1 in terms // of execution. The error-checking step would simply load the offset value into the correct // axis of the block XYZ value array. - if (axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET) { // Indicates a change. + if (axis_command == AxisCommand::ToolLengthOffset) { // Indicates a change. gc_state.modal.tool_length = gc_block.modal.tool_length; - if (gc_state.modal.tool_length == TOOL_LENGTH_OFFSET_CANCEL) // G49 + if (gc_state.modal.tool_length == ToolLengthOffset::Cancel) { // G49 gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] = 0.0; + } // else G43.1 if (gc_state.tool_length_offset != gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS]) { gc_state.tool_length_offset = gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS]; @@ -1211,7 +1329,7 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // [18. Set retract mode ]: NOT SUPPORTED // [19. Go to predefined position, Set G10, or Set axis offsets ]: switch (gc_block.non_modal_command) { - case NON_MODAL_SET_COORDINATE_DATA: + case NonModal::SetCoordinateData: settings_write_coord_data(coord_select, gc_block.values.ijk); // Update system coordinate system if currently active. if (gc_state.modal.coord_select == coord_select) { @@ -1219,46 +1337,47 @@ uint8_t gc_execute_line(char* line, uint8_t client) { system_flag_wco_change(); } break; - case NON_MODAL_GO_HOME_0: - case NON_MODAL_GO_HOME_1: + case NonModal::GoHome0: + case NonModal::GoHome1: // Move to intermediate position before going home. Obeys current coordinate system and offsets // and absolute and incremental modes. - pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag. - if (axis_command) { + pl_data->motion |= PL_MOTION_RAPID_MOTION; // Set rapid motion flag. + if (axis_command != AxisCommand::None) { mc_line(gc_block.values.xyz, pl_data); // kinematics kinematics not used for homing righ now } mc_line(gc_block.values.ijk, pl_data); memcpy(gc_state.position, gc_block.values.ijk, N_AXIS * sizeof(float)); break; - case NON_MODAL_SET_HOME_0: settings_write_coord_data(SETTING_INDEX_G28, gc_state.position); break; - case NON_MODAL_SET_HOME_1: settings_write_coord_data(SETTING_INDEX_G30, gc_state.position); break; - case NON_MODAL_SET_COORDINATE_OFFSET: + case NonModal::SetHome0: settings_write_coord_data(SETTING_INDEX_G28, gc_state.position); break; + case NonModal::SetHome1: settings_write_coord_data(SETTING_INDEX_G30, gc_state.position); break; + case NonModal::SetCoordinateOffset: memcpy(gc_state.coord_offset, gc_block.values.xyz, sizeof(gc_block.values.xyz)); system_flag_wco_change(); break; - case NON_MODAL_RESET_COORDINATE_OFFSET: + case NonModal::ResetCoordinateOffset: clear_vector(gc_state.coord_offset); // Disable G92 offsets by zeroing offset vector. system_flag_wco_change(); break; + default: break; } // [20. Motion modes ]: // NOTE: Commands G10,G28,G30,G92 lock out and prevent axis words from use in motion modes. // Enter motion modes only if there are axis words or a motion mode command word in the block. gc_state.modal.motion = gc_block.modal.motion; - if (gc_state.modal.motion != MOTION_MODE_NONE) { - if (axis_command == AXIS_COMMAND_MOTION_MODE) { - uint8_t gc_update_pos = GC_UPDATE_POS_TARGET; + if (gc_state.modal.motion != Motion::None) { + if (axis_command == AxisCommand::MotionMode) { + GCUpdatePos gc_update_pos = GCUpdatePos::Target; #ifdef USE_I2S_STEPS stepper_id_t save_stepper = current_stepper; #endif - if (gc_state.modal.motion == MOTION_MODE_LINEAR) { + if (gc_state.modal.motion == Motion::Linear) { //mc_line(gc_block.values.xyz, pl_data); mc_line_kins(gc_block.values.xyz, pl_data, gc_state.position); - } else if (gc_state.modal.motion == MOTION_MODE_SEEK) { - pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag. + } else if (gc_state.modal.motion == Motion::Seek) { + pl_data->motion |= PL_MOTION_RAPID_MOTION; // Set rapid motion flag. //mc_line(gc_block.values.xyz, pl_data); mc_line_kins(gc_block.values.xyz, pl_data, gc_state.position); - } else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) { + } else if ((gc_state.modal.motion == Motion::CwArc) || (gc_state.modal.motion == Motion::CcwArc)) { mc_arc(gc_block.values.xyz, pl_data, gc_state.position, @@ -1267,12 +1386,12 @@ uint8_t gc_execute_line(char* line, uint8_t client) { axis_0, axis_1, axis_linear, - bit_istrue(gc_parser_flags, GC_PARSER_ARC_IS_CLOCKWISE)); + bit_istrue(gc_parser_flags, GCParserArcIsClockwise)); } else { // NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So // upon a successful probing cycle, the machine position and the returned value should be the same. #ifndef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES - pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE; + pl_data->motion |= PL_MOTION_NO_FEED_OVERRIDE; #endif #ifdef USE_I2S_STEPS save_stepper = current_stepper; // remember the stepper @@ -1285,11 +1404,11 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // As far as the parser is concerned, the position is now == target. In reality the // motion control system might still be processing the action and the real tool position // in any intermediate location. - if (gc_update_pos == GC_UPDATE_POS_TARGET) { + if (gc_update_pos == GCUpdatePos::Target) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc_state.position[] = gc_block.values.xyz[] - } else if (gc_update_pos == GC_UPDATE_POS_SYSTEM) { + } else if (gc_update_pos == GCUpdatePos::System) { gc_sync_position(); // gc_state.position[] = sys_position - } // == GC_UPDATE_POS_NONE + } // == GCUpdatePos::None #ifdef USE_I2S_STEPS if (save_stepper == ST_I2S_STREAM && current_stepper != ST_I2S_STREAM) { stepper_switch(ST_I2S_STREAM); // Put the stepper back on. @@ -1301,31 +1420,40 @@ uint8_t gc_execute_line(char* line, uint8_t client) { // M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may // refill and can only be resumed by the cycle start run-time command. gc_state.modal.program_flow = gc_block.modal.program_flow; - if (gc_state.modal.program_flow) { - protocol_buffer_synchronize(); // Sync and finish all remaining buffered motions before moving on. - if (gc_state.modal.program_flow == PROGRAM_FLOW_PAUSED) { + switch (gc_state.modal.program_flow) { + case ProgramFlow::Running: break; + case ProgramFlow::OptionalStop: + // TODO - to support M1 we would need some code to determine whether to stop + // Then either break or fall through to actually stop. + break; + case ProgramFlow::Paused: + protocol_buffer_synchronize(); // Sync and finish all remaining buffered motions before moving on. if (sys.state != STATE_CHECK_MODE) { system_set_exec_state_flag(EXEC_FEED_HOLD); // Use feed hold for program pause. protocol_execute_realtime(); // Execute suspend. } - } else { // == PROGRAM_FLOW_COMPLETED + break; + case ProgramFlow::CompletedM2: + case ProgramFlow::CompletedM30: + protocol_buffer_synchronize(); // Sync and finish all remaining buffered motions before moving on. + // Upon program complete, only a subset of g-codes reset to certain defaults, according to // LinuxCNC's program end descriptions and testing. Only modal groups [G-code 1,2,3,5,7,12] // and [M-code 7,8,9] reset to [G1,G17,G90,G94,G40,G54,M5,M9,M48]. The remaining modal groups // [G-code 4,6,8,10,13,14,15] and [M-code 4,5,6] and the modal words [F,S,T,H] do not reset. - gc_state.modal.motion = MOTION_MODE_LINEAR; - gc_state.modal.plane_select = PLANE_SELECT_XY; - gc_state.modal.distance = DISTANCE_MODE_ABSOLUTE; - gc_state.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; - // gc_state.modal.cutter_comp = CUTTER_COMP_DISABLE; // Not supported. + gc_state.modal.motion = Motion::Linear; + gc_state.modal.plane_select = Plane::XY; + gc_state.modal.distance = Distance::Absolute; + gc_state.modal.feed_rate = FeedRate::UnitsPerMin; + // gc_state.modal.cutter_comp = CutterComp::Disable; // Not supported. gc_state.modal.coord_select = 0; // G54 - gc_state.modal.spindle = SPINDLE_DISABLE; - gc_state.modal.coolant = COOLANT_DISABLE; + gc_state.modal.spindle = SpindleState::Disable; + gc_state.modal.coolant = CoolantMode::Disable; #ifdef ENABLE_PARKING_OVERRIDE_CONTROL # ifdef DEACTIVATE_PARKING_UPON_INIT - gc_state.modal.override = OVERRIDE_DISABLED; + gc_state.modal.override = Override::Disabled; # else - gc_state.modal.override = OVERRIDE_PARKING_MOTION; + gc_state.modal.override = Override::ParkingMotion; # endif #endif // gc_state.modal.override = OVERRIDE_DISABLE; // Not supported. @@ -1336,19 +1464,21 @@ uint8_t gc_execute_line(char* line, uint8_t client) { #endif // Execute coordinate change and spindle/coolant stop. if (sys.state != STATE_CHECK_MODE) { - if (!(settings_read_coord_data(gc_state.modal.coord_select, gc_state.coord_system))) + if (!(settings_read_coord_data(gc_state.modal.coord_select, gc_state.coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); + } system_flag_wco_change(); // Set to refresh immediately just in case something altered. - spindle->set_state(SPINDLE_DISABLE, 0); - coolant_set_state(COOLANT_DISABLE); + spindle->set_state(SpindleState::Disable, 0); + coolant_set_state(CoolantMode::Disable); } report_feedback_message(MESSAGE_PROGRAM_END); #ifdef USE_M30 user_m30(); #endif - } - gc_state.modal.program_flow = PROGRAM_FLOW_RUNNING; // Reset program flow. + break; } + gc_state.modal.program_flow = ProgramFlow::Running; // Reset program flow. + // TODO: % to denote start of program. return (STATUS_OK); } diff --git a/Grbl_Esp32/src/GCode.h b/Grbl_Esp32/src/GCode.h index 70dbe62b..60bad181 100644 --- a/Grbl_Esp32/src/GCode.h +++ b/Grbl_Esp32/src/GCode.h @@ -30,28 +30,26 @@ // 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). // 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,G38.3,G38.4,G38.5,G80] Motion -#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection -#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode -#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode -#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode -#define MODAL_GROUP_G6 6 // [G20,G21] Units -#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED. -#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset -#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection -#define MODAL_GROUP_G13 10 // [G61] Control mode -#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping -#define MODAL_GROUP_M6 14 // [M6] Tool change -#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning -#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control -#define MODAL_GROUP_M9 14 // [M56] Override control -#define MODAL_GROUP_M10 15 // [M62, M63] User Defined http://linuxcnc.org/docs/html/gcode/overview.html#_modal_groups - -// #define OTHER_INPUT_F 14 -// #define OTHER_INPUT_S 15 -// #define OTHER_INPUT_T 16 +enum class ModalGroup : uint8_t { + MG0 = 0, // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal + MG1 = 1, // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion + MG2 = 2, // [G17,G18,G19] Plane selection + MG3 = 3, // [G90,G91] Distance mode + MG4 = 4, // [G91.1] Arc IJK distance mode + MG5 = 5, // [G93,G94] Feed rate mode + MG6 = 6, // [G20,G21] Units + MG7 = 7, // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED. + MG8 = 8, // [G43.1,G49] Tool length offset + MG12 = 9, // [G54,G55,G56,G57,G58,G59] Coordinate system selection + MG13 = 10, // [G61] Control mode + MM4 = 11, // [M0,M1,M2,M30] Stopping + MM6 = 14, // [M6] Tool change + MM7 = 12, // [M3,M4,M5] Spindle turning + MM8 = 13, // [M7,M8,M9] Coolant control + MM9 = 14, // [M56] Override control + MM10 = 15, // [M62, M63] User Defined http://linuxcnc.org/docs/html/gcode/overview.html#_modal_groups +}; // Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used // internally by the parser to know which command to execute. @@ -61,157 +59,189 @@ // to see how they are used, if you need to alter them. // Modal Group G0: Non-modal actions -#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero) -#define NON_MODAL_DWELL 4 // G4 (Do not alter value) -#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value) -#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value) -#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value) -#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value) -#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value) -#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value) -#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value) -#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value) + +enum class NonModal : uint8_t { + NoAction = 0, // (Default: Must be zero) + Dwell = 4, // G4 (Do not alter value) + SetCoordinateData = 10, // G10 (Do not alter value) + GoHome0 = 28, // G28 (Do not alter value) + SetHome0 = 38, // G28.1 (Do not alter value) + GoHome1 = 30, // G30 (Do not alter value) + SetHome1 = 40, // G30.1 (Do not alter value) + AbsoluteOverride = 53, // G53 (Do not alter value) + SetCoordinateOffset = 92, // G92 (Do not alter value) + ResetCoordinateOffset = 102, //G92.1 (Do not alter value) +}; // Modal Group G1: Motion modes -#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero) -#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value) -#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value) -#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value) -#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value) -#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value) -#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value) -#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value) -#define MOTION_MODE_NONE 80 // G80 (Do not alter value) +enum class Motion : uint8_t { + Seek = 0, // G0 (Default: Must be zero) + Linear = 1, // G1 (Do not alter value) + CwArc = 2, // G2 (Do not alter value) + CcwArc = 3, // G3 (Do not alter value) + ProbeToward = 140, // G38.2 (Do not alter value) + ProbeTowardNoError = 141, // G38.3 (Do not alter value) + ProbeAway = 142, // G38.4 (Do not alter value) + ProbeAwayNoError = 143, // G38.5 (Do not alter value) + None = 80, // G80 (Do not alter value) +}; // Modal Group G2: Plane select -#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero) -#define PLANE_SELECT_ZX 1 // G18 (Do not alter value) -#define PLANE_SELECT_YZ 2 // G19 (Do not alter value) +enum class Plane : uint8_t { + XY = 0, // G17 (Default: Must be zero) + ZX = 1, // G18 (Do not alter value) + YZ = 2, // G19 (Do not alter value) +}; // Modal Group G3: Distance mode -#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero) -#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value) +enum class Distance : uint8_t { + Absolute = 0, // G90 (Default: Must be zero) + Incremental = 1, // G91 (Do not alter value) +}; // Modal Group G4: Arc IJK distance mode -#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero) +enum class ArcDistance : uint8_t { + Incremental = 0, // G91.1 (Default: Must be zero) + Absolute = 1, +}; // Modal Group M4: Program flow -#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero) -#define PROGRAM_FLOW_PAUSED 3 // M0 -#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored. -#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value) -#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value) +enum class ProgramFlow : uint8_t { + Running = 0, // (Default: Must be zero) + Paused = 3, // M0 + OptionalStop = 1, // M1 NOTE: Not supported, but valid and ignored. + CompletedM2 = 2, // M2 (Do not alter value) + CompletedM30 = 30, // M30 (Do not alter value) +}; // Modal Group G5: Feed rate mode -#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero) -#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value) +enum class FeedRate : uint8_t { + UnitsPerMin = 0, // G94 (Default: Must be zero) + InverseTime = 1, // G93 (Do not alter value) +}; // Modal Group G6: Units mode -#define UNITS_MODE_MM 0 // G21 (Default: Must be zero) -#define UNITS_MODE_INCHES 1 // G20 (Do not alter value) +enum class Units : uint8_t { + Mm = 0, // G21 (Default: Must be zero) + Inches = 1, // G20 (Do not alter value) +}; // Modal Group G7: Cutter radius compensation mode -#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero) +enum class CutterCompensation : uint8_t { + Disable = 0, // G40 (Default: Must be zero) + Enable = 1, +}; // Modal Group G13: Control mode -#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero) +enum class ControlMode : uint8_t { + ExactPath = 0, // G61 (Default: Must be zero) +}; // Modal Group M7: Spindle control -#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero) -#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag) -#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag) +enum class SpindleState : uint8_t { + Disable = 0, // M5 (Default: Must be zero) + Cw = 1, // M3 + Ccw = 2, // M4 +}; // Modal Group M8: Coolant control -#define COOLANT_DISABLE 0 // M9 (Default: Must be zero) -#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag) -#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag) +enum class CoolantMode : uint8_t { + Disable = 0, // M9 (Default: Must be zero) + Flood = 1, // M8 + Mist = 2, // M7 +}; // Modal Group M9: Override control +enum class Override : uint8_t { #ifdef DEACTIVATE_PARKING_UPON_INIT -# define OVERRIDE_DISABLED 0 // (Default: Must be zero) -# define OVERRIDE_PARKING_MOTION 1 // M56 + Disabled = 0, // (Default: Must be zero) + ParkingMotion = 1, // M56 #else -# define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero) -# define OVERRIDE_DISABLED 1 // Parking disabled. + ParkingMotion = 0, // M56 (Default: Must be zero) + Disabled = 1, // Parking disabled. #endif +}; // modal Group M10: User I/O control -#define NON_MODAL_IO_ENABLE 1 -#define NON_MODAL_IO_DISABLE 2 -#define MAX_USER_DIGITAL_PIN 4 +enum class IoControl : uint8_t { + Enable = 1, + Disable = 2, +}; + +static const int MaxUserDigitalPin = 4; // Modal Group G8: Tool length offset -#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero) -#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1 +enum class ToolLengthOffset : uint8_t { + Cancel = 0, // G49 (Default: Must be zero) + EnableDynamic = 1, // G43.1 +}; -#define TOOL_CHANGE 1 +enum class ToolChange : uint8_t { + Disable = 0, + Enable = 1, +}; // Modal Group G12: Active work coordinate system // N/A: Stores coordinate system value (54-59) to change to. // Define parameter word mapping. -#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 -#define WORD_A 13 -#define WORD_B 14 -#define WORD_C 15 +enum class GCodeWord : uint8_t { + F = 0, + I = 1, + J = 2, + K = 3, + L = 4, + N = 5, + P = 6, + R = 7, + S = 8, + T = 9, + X = 10, + Y = 11, + Z = 12, + A = 13, + B = 14, + C = 15, +}; // Define g-code parser position updating flags -#define GC_UPDATE_POS_TARGET 0 // Must be zero -#define GC_UPDATE_POS_SYSTEM 1 -#define GC_UPDATE_POS_NONE 2 - -// Define probe cycle exit states and assign proper position updating. -#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM -#define GC_PROBE_ABORT GC_UPDATE_POS_NONE -#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE -#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET -#ifdef SET_CHECK_MODE_PROBE_TO_START -# define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE -#else -# define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET -#endif +enum class GCUpdatePos : uint8_t { + Target = 0, // Must be zero + System = 1, + None = 2, +}; // Define gcode parser flags for handling special cases. -#define GC_PARSER_NONE 0 // Must be zero. -#define GC_PARSER_JOG_MOTION bit(0) -#define GC_PARSER_CHECK_MANTISSA bit(1) -#define GC_PARSER_ARC_IS_CLOCKWISE bit(2) -#define GC_PARSER_PROBE_IS_AWAY bit(3) -#define GC_PARSER_PROBE_IS_NO_ERROR bit(4) -#define GC_PARSER_LASER_FORCE_SYNC bit(5) -#define GC_PARSER_LASER_DISABLE bit(6) -#define GC_PARSER_LASER_ISMOTION bit(7) +enum GCParserFlags { + GCParserNone = 0, // Must be zero. + GCParserJogMotion = bit(0), + GCParserCheckMantissa = bit(1), + GCParserArcIsClockwise = bit(2), + GCParserProbeIsAway = bit(3), + GCParserProbeIsNoError = bit(4), + GCParserLaserForceSync = bit(5), + GCParserLaserDisable = bit(6), + GCParserLaserIsMotion = bit(7), +}; // NOTE: When this struct is zeroed, the above defines set the defaults for the system. typedef struct { - uint8_t motion; // {G0,G1,G2,G3,G38.2,G80} - uint8_t feed_rate; // {G93,G94} - uint8_t units; // {G20,G21} - uint8_t distance; // {G90,G91} - // uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported. - uint8_t plane_select; // {G17,G18,G19} - // uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported. - uint8_t tool_length; // {G43.1,G49} - uint8_t coord_select; // {G54,G55,G56,G57,G58,G59} + Motion motion; // {G0,G1,G2,G3,G38.2,G80} + FeedRate feed_rate; // {G93,G94} + Units units; // {G20,G21} + Distance distance; // {G90,G91} + // ArcDistance distance_arc; // {G91.1} NOTE: Don't track. Only default supported. + Plane plane_select; // {G17,G18,G19} + // CutterCompensation cutter_comp; // {G40} NOTE: Don't track. Only default supported. + ToolLengthOffset tool_length; // {G43.1,G49} + uint8_t coord_select; // {G54,G55,G56,G57,G58,G59} // uint8_t control; // {G61} NOTE: Don't track. Only default supported. - uint8_t program_flow; // {M0,M1,M2,M30} - uint8_t coolant; // {M7,M8,M9} - uint8_t spindle; // {M3,M4,M5} - uint8_t tool_change; // {M6} - uint8_t io_control; // {M62, M63} - uint8_t override; // {M56} + ProgramFlow program_flow; // {M0,M1,M2,M30} + CoolantMode coolant; // {M7,M8,M9} + SpindleState spindle; // {M3,M4,M5} + ToolChange tool_change; // {M6} + IoControl io_control; // {M62, M63} + Override override; // {M56} } gc_modal_t; typedef struct { @@ -246,11 +276,18 @@ typedef struct { extern parser_state_t gc_state; typedef struct { - uint8_t non_modal_command; + NonModal non_modal_command; gc_modal_t modal; gc_values_t values; } parser_block_t; +enum class AxisCommand : uint8_t { + None = 0, + NonModal = 1, + MotionMode = 2, + ToolLengthOffset = 3, +}; + // Initialize the parser void gc_init(); diff --git a/Grbl_Esp32/src/Grbl.h b/Grbl_Esp32/src/Grbl.h index 35271cf5..6f3f2e48 100644 --- a/Grbl_Esp32/src/Grbl.h +++ b/Grbl_Esp32/src/Grbl.h @@ -23,7 +23,7 @@ // Grbl versioning system #define GRBL_VERSION "1.3a" -#define GRBL_VERSION_BUILD "20200828" +#define GRBL_VERSION_BUILD "20200831" //#include #include @@ -45,10 +45,10 @@ #include "WebUI/Commands.h" #include "System.h" -#include "Planner.h" -#include "CoolantControl.h" -#include "Eeprom.h" #include "GCode.h" +#include "Planner.h" +#include "Eeprom.h" +#include "CoolantControl.h" #include "Limits.h" #include "MotionControl.h" #include "Probe.h" diff --git a/Grbl_Esp32/src/Jog.cpp b/Grbl_Esp32/src/Jog.cpp index b3eb4917..f72961ea 100644 --- a/Grbl_Esp32/src/Jog.cpp +++ b/Grbl_Esp32/src/Jog.cpp @@ -28,7 +28,7 @@ uint8_t jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block) { // Initialize planner data struct for jogging motions. // NOTE: Spindle and coolant are allowed to fully function with overrides during a jog. pl_data->feed_rate = gc_block->values.f; - pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE; + pl_data->motion |= PL_MOTION_NO_FEED_OVERRIDE; #ifdef USE_LINE_NUMBERS pl_data->line_number = gc_block->values.n; #endif diff --git a/Grbl_Esp32/src/Limits.cpp b/Grbl_Esp32/src/Limits.cpp index a197db95..7ae6e3d4 100644 --- a/Grbl_Esp32/src/Limits.cpp +++ b/Grbl_Esp32/src/Limits.cpp @@ -27,7 +27,7 @@ #include "Grbl.h" -uint8_t n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; +uint8_t n_homing_locate_cycle = NHomingLocateCycle; xQueueHandle limit_sw_queue; // used by limit switch debouncing @@ -82,7 +82,7 @@ void limits_go_home(uint8_t cycle_mask) { plan_line_data_t plan_data; plan_line_data_t* pl_data = &plan_data; memset(pl_data, 0, sizeof(plan_line_data_t)); - pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE); + pl_data->motion = (PL_MOTION_SYSTEM_MOTION | PL_MOTION_NO_FEED_OVERRIDE); #ifdef USE_LINE_NUMBERS pl_data->line_number = HOMING_CYCLE_LINE_NUMBER; #endif diff --git a/Grbl_Esp32/src/MotionControl.cpp b/Grbl_Esp32/src/MotionControl.cpp index 49201fe5..cc60a3b4 100644 --- a/Grbl_Esp32/src/MotionControl.cpp +++ b/Grbl_Esp32/src/MotionControl.cpp @@ -135,9 +135,9 @@ void mc_arc(float* target, // Multiply inverse feed_rate to compensate for the fact that this movement is approximated // by a number of discrete segments. The inverse feed_rate should be correct for the sum of // all segments. - if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) { + if (pl_data->motion & PL_MOTION_INVERSE_TIME) { pl_data->feed_rate *= segments; - bit_false(pl_data->condition, PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments. + bit_false(pl_data->motion, PL_MOTION_INVERSE_TIME); // Force as feed absolute mode over arc segments. } float theta_per_segment = angular_travel / segments; float linear_per_segment = (target[axis_linear] - position[axis_linear]) / segments; @@ -277,7 +277,7 @@ void mc_homing_cycle(uint8_t cycle_mask) { limits_disable(); // Disable hard limits pin change register for cycle duration // ------------------------------------------------------------------------------------- // Perform homing routine. NOTE: Special motion case. Only system reset works. - n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; + n_homing_locate_cycle = NHomingLocateCycle; #ifdef HOMING_SINGLE_AXIS_COMMANDS /* if (cycle_mask) { limits_go_home(cycle_mask); } // Perform homing cycle based on mask. @@ -291,7 +291,7 @@ void mc_homing_cycle(uint8_t cycle_mask) { n_homing_locate_cycle = 0; // don't do a second touch cycle limits_go_home(cycle_mask); ganged_mode = SquaringMode::A; - n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value + n_homing_locate_cycle = NHomingLocateCycle; // restore to default value limits_go_home(cycle_mask); ganged_mode = SquaringMode::B; limits_go_home(cycle_mask); @@ -309,7 +309,7 @@ void mc_homing_cycle(uint8_t cycle_mask) { n_homing_locate_cycle = 0; // don't do a second touch cycle limits_go_home(HOMING_CYCLE_0); ganged_mode = SquaringMode::A; - n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value + n_homing_locate_cycle = NHomingLocateCycle; // restore to default value limits_go_home(HOMING_CYCLE_0); ganged_mode = SquaringMode::B; limits_go_home(HOMING_CYCLE_0); @@ -323,7 +323,7 @@ void mc_homing_cycle(uint8_t cycle_mask) { n_homing_locate_cycle = 0; // don't do a second touch cycle limits_go_home(HOMING_CYCLE_1); ganged_mode = SquaringMode::A; - n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value + n_homing_locate_cycle = NHomingLocateCycle; // restore to default value limits_go_home(HOMING_CYCLE_1); ganged_mode = SquaringMode::B; limits_go_home(HOMING_CYCLE_1); @@ -338,7 +338,7 @@ void mc_homing_cycle(uint8_t cycle_mask) { n_homing_locate_cycle = 0; // don't do a second touch cycle limits_go_home(HOMING_CYCLE_2); ganged_mode = SquaringMode::A; - n_homing_locate_cycle = N_HOMING_LOCATE_CYCLE; // restore to default value + n_homing_locate_cycle = NHomingLocateCycle; // restore to default value limits_go_home(HOMING_CYCLE_2); ganged_mode = SquaringMode::B; limits_go_home(HOMING_CYCLE_2); @@ -374,17 +374,22 @@ void mc_homing_cycle(uint8_t cycle_mask) { // Perform tool length probe cycle. Requires probe switch. // NOTE: Upon probe failure, the program will be stopped and placed into ALARM state. -uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags) { +GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags) { // TODO: Need to update this cycle so it obeys a non-auto cycle start. - if (sys.state == STATE_CHECK_MODE) - return (GC_PROBE_CHECK_MODE); + if (sys.state == STATE_CHECK_MODE) { +#ifdef SET_CHECK_MODE_PROBE_TO_START + return (GCUpdatePos::None); +#else + return (GCUpdatePos::Target); +#endif + } // Finish all queued commands and empty planner buffer before starting probe cycle. protocol_buffer_synchronize(); if (sys.abort) - return (GC_PROBE_ABORT); // Return if system reset has been issued. + return (GCUpdatePos::None); // Return if system reset has been issued. // Initialize probing control variables - uint8_t is_probe_away = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_AWAY); - uint8_t is_no_error = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_NO_ERROR); + uint8_t is_probe_away = bit_istrue(parser_flags, GCParserProbeIsAway); + uint8_t is_no_error = bit_istrue(parser_flags, GCParserProbeIsNoError); sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle. probe_configure_invert_mask(is_probe_away); // After syncing, check if probe is already triggered. If so, halt and issue alarm. @@ -393,7 +398,7 @@ uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_ system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL); protocol_execute_realtime(); probe_configure_invert_mask(false); // Re-initialize invert mask before returning. - return (GC_PROBE_FAIL_INIT); // Nothing else to do but bail. + return (GCUpdatePos::None); // Nothing else to do but bail. } // Setup and queue probing motion. Auto cycle-start should not start the cycle. mc_line(target, pl_data); @@ -404,7 +409,7 @@ uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_ do { protocol_execute_realtime(); if (sys.abort) - return (GC_PROBE_ABORT); // Check for system abort + return (GCUpdatePos::None); // Check for system abort } while (sys.state != STATE_IDLE); // Probing cycle complete! // Set state variables and error out, if the probe failed and cycle with error is enabled. @@ -428,9 +433,9 @@ uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_ report_probe_parameters(CLIENT_ALL); #endif if (sys.probe_succeeded) - return (GC_PROBE_FOUND); // Successful probe cycle. + return (GCUpdatePos::System); // Successful probe cycle. else - return (GC_PROBE_FAIL_END); // Failed to trigger probe within travel. With or without error. + return (GCUpdatePos::Target); // Failed to trigger probe within travel. With or without error. } // Plans and executes the single special motion case for parking. Independent of main planner buffer. diff --git a/Grbl_Esp32/src/MotionControl.h b/Grbl_Esp32/src/MotionControl.h index eb9183b9..6d38ae6d 100644 --- a/Grbl_Esp32/src/MotionControl.h +++ b/Grbl_Esp32/src/MotionControl.h @@ -31,12 +31,6 @@ #define PARKING_MOTION_LINE_NUMBER 0 #define HOMING_CYCLE_ALL 0 // Must be zero. -#define HOMING_CYCLE_X bit(X_AXIS) -#define HOMING_CYCLE_Y bit(Y_AXIS) -#define HOMING_CYCLE_Z bit(Z_AXIS) -#define HOMING_CYCLE_A bit(A_AXIS) -#define HOMING_CYCLE_B bit(B_AXIS) -#define HOMING_CYCLE_C bit(C_AXIS) // 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 @@ -65,7 +59,7 @@ void mc_dwell(float seconds); void mc_homing_cycle(uint8_t cycle_mask); // Perform tool length probe cycle. Requires probe switch. -uint8_t mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags); +GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags); // Handles updating the override control state. void mc_override_ctrl_update(uint8_t override_state); diff --git a/Grbl_Esp32/src/NutsBolts.h b/Grbl_Esp32/src/NutsBolts.h index fca88326..85a9d823 100644 --- a/Grbl_Esp32/src/NutsBolts.h +++ b/Grbl_Esp32/src/NutsBolts.h @@ -22,8 +22,8 @@ #include "Config.h" -#define false 0 -#define true 1 +// #define false 0 +// #define true 1 #define SOME_LARGE_VALUE 1.0E+38 @@ -72,8 +72,11 @@ #define isequal_position_vector(a, b) !(memcmp(a, b, sizeof(float) * N_AXIS)) // Bit field and masking macros -//Arduino.h:104:0: note: this is the location of the previous definition -//#define bit(n) (1 << n) +// bit(n) is defined in Arduino.h. We redefine it here so we can apply +// the static_cast, thus making it work with scoped enums +#undef bit +#define bit(n) (1 << static_cast(n)) + #define bit_true(x, mask) (x) |= (mask) #define bit_false(x, mask) (x) &= ~(mask) #define bit_istrue(x, mask) ((x & mask) != 0) diff --git a/Grbl_Esp32/src/Planner.cpp b/Grbl_Esp32/src/Planner.cpp index 05bd2bae..31ec8008 100644 --- a/Grbl_Esp32/src/Planner.cpp +++ b/Grbl_Esp32/src/Planner.cpp @@ -240,10 +240,10 @@ uint8_t plan_check_full_buffer() { // NOTE: All system motion commands, such as homing/parking, are not subject to overrides. float plan_compute_profile_nominal_speed(plan_block_t* block) { float nominal_speed = block->programmed_rate; - if (block->condition & PL_COND_FLAG_RAPID_MOTION) + if (block->motion & PL_MOTION_RAPID_MOTION) nominal_speed *= (0.01 * sys.r_override); else { - if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) + if (!(block->motion & PL_MOTION_NO_FEED_OVERRIDE)) nominal_speed *= (0.01 * sys.f_override); if (nominal_speed > block->rapid_rate) nominal_speed = block->rapid_rate; @@ -285,7 +285,9 @@ uint8_t plan_buffer_line(float* target, plan_line_data_t* pl_data) { // Prepare and initialize new block. Copy relevant pl_data for block execution. plan_block_t* block = &block_buffer[block_buffer_head]; memset(block, 0, sizeof(plan_block_t)); // Zero all block values. - block->condition = pl_data->condition; + block->motion = pl_data->motion; + block->coolant = pl_data->coolant; + block->spindle = pl_data->spindle; block->spindle_speed = pl_data->spindle_speed; #ifdef USE_LINE_NUMBERS @@ -296,7 +298,7 @@ uint8_t plan_buffer_line(float* target, plan_line_data_t* pl_data) { float unit_vec[N_AXIS], delta_mm; uint8_t idx; // Copy position data based on type of motion being planned. - if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) { + if (block->motion & PL_MOTION_SYSTEM_MOTION) { #ifdef COREXY position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position); position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position); @@ -352,15 +354,15 @@ uint8_t plan_buffer_line(float* target, plan_line_data_t* pl_data) { block->acceleration = limit_acceleration_by_axis_maximum(unit_vec); block->rapid_rate = limit_rate_by_axis_maximum(unit_vec); // Store programmed rate. - if (block->condition & PL_COND_FLAG_RAPID_MOTION) + if (block->motion & PL_MOTION_RAPID_MOTION) block->programmed_rate = block->rapid_rate; else { block->programmed_rate = pl_data->feed_rate; - if (block->condition & PL_COND_FLAG_INVERSE_TIME) + if (block->motion & PL_MOTION_INVERSE_TIME) block->programmed_rate *= block->millimeters; } // TODO: Need to check this method handling zero junction speeds when starting from rest. - if ((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) { + if ((block_buffer_head == block_buffer_tail) || (block->motion & PL_MOTION_SYSTEM_MOTION)) { // Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later. // If system motion, the system motion block always is assumed to start from rest and end at a complete stop. block->entry_speed_sqr = 0.0; @@ -412,7 +414,7 @@ uint8_t plan_buffer_line(float* target, plan_line_data_t* pl_data) { } } // Block system motion from updating this data to ensure next g-code motion is computed correctly. - if (!(block->condition & PL_COND_FLAG_SYSTEM_MOTION)) { + if (!(block->motion & PL_MOTION_SYSTEM_MOTION)) { float nominal_speed = plan_compute_profile_nominal_speed(block); plan_compute_profile_parameters(block, nominal_speed, pl.previous_nominal_speed); pl.previous_nominal_speed = nominal_speed; diff --git a/Grbl_Esp32/src/Planner.h b/Grbl_Esp32/src/Planner.h index e8abc13a..ab3cca51 100644 --- a/Grbl_Esp32/src/Planner.h +++ b/Grbl_Esp32/src/Planner.h @@ -38,16 +38,10 @@ #define PLAN_EMPTY_BLOCK false // Define planner data condition flags. Used to denote running conditions of a block. -#define PL_COND_FLAG_RAPID_MOTION bit(0) -#define PL_COND_FLAG_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park. -#define PL_COND_FLAG_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override. -#define PL_COND_FLAG_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set. -#define PL_COND_FLAG_SPINDLE_CW bit(4) -#define PL_COND_FLAG_SPINDLE_CCW bit(5) -#define PL_COND_FLAG_COOLANT_FLOOD bit(6) -#define PL_COND_FLAG_COOLANT_MIST bit(7) -#define PL_COND_MOTION_MASK (PL_COND_FLAG_RAPID_MOTION | PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE) -#define PL_COND_ACCESSORY_MASK (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW | PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_MIST) +#define PL_MOTION_RAPID_MOTION bit(0) +#define PL_MOTION_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park. +#define PL_MOTION_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override. +#define PL_MOTION_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set. // This struct stores a linear movement of a g-code block motion with its critical "nominal" values // are as specified in the source g-code. @@ -59,7 +53,9 @@ typedef struct { uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) // Block condition data to ensure correct execution depending on states and overrides. - uint8_t condition; // Block bitflag variable defining block run conditions. Copied from pl_line_data. + uint8_t motion; // Block bitflag motion conditions. Copied from pl_line_data. + SpindleState spindle; // Spindle enable state + CoolantMode coolant; // Coolant state #ifdef USE_LINE_NUMBERS int32_t line_number; // Block line number for real-time reporting. Copied from pl_line_data. #endif @@ -85,9 +81,11 @@ typedef struct { // Planner data prototype. Must be used when passing new motions to the planner. typedef struct { - float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion. - uint32_t spindle_speed; // Desired spindle speed through line motion. - uint8_t condition; // Bitflag variable to indicate planner conditions. See defines above. + float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion. + uint32_t spindle_speed; // Desired spindle speed through line motion. + uint8_t motion; // Bitflag variable to indicate motion conditions. See defines above. + SpindleState spindle; // Spindle enable state + CoolantMode coolant; // Coolant state #ifdef USE_LINE_NUMBERS int32_t line_number; // Desired line number to report when executing. #endif diff --git a/Grbl_Esp32/src/ProcessSettings.cpp b/Grbl_Esp32/src/ProcessSettings.cpp index a32f83e1..10fdf015 100644 --- a/Grbl_Esp32/src/ProcessSettings.cpp +++ b/Grbl_Esp32/src/ProcessSettings.cpp @@ -10,12 +10,12 @@ bool auth_failed(Word* w, const char* value, WebUI::AuthenticationLevel auth_lev permissions_t permissions = w->getPermissions(); switch (auth_level) { case WebUI::AuthenticationLevel::LEVEL_ADMIN: // Admin can do anything - return false; // Nothing is an Admin auth fail + return false; // Nothing is an Admin auth fail case WebUI::AuthenticationLevel::LEVEL_GUEST: // Guest can only access open settings - return permissions != WG; // Anything other than RG is Guest auth fail + return permissions != WG; // Anything other than RG is Guest auth fail case WebUI::AuthenticationLevel::LEVEL_USER: // User is complicated... - if (!value) { // User can read anything - return false; // No read is a User auth fail + if (!value) { // User can read anything + return false; // No read is a User auth fail } return permissions == WA; // User cannot write WA default: return true; @@ -239,22 +239,22 @@ err_t home_all(const char* value, WebUI::AuthenticationLevel auth_level, WebUI:: return home(HOMING_CYCLE_ALL); } err_t home_x(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_X); + return home(X_AXIS); } err_t home_y(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_Y); + return home(Y_AXIS); } err_t home_z(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_Z); + return home(Z_AXIS); } err_t home_a(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_A); + return home(A_AXIS); } err_t home_b(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_B); + return home(B_AXIS); } err_t home_c(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { - return home(HOMING_CYCLE_C); + return home(C_AXIS); } err_t sleep_grbl(const char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* out) { system_set_exec_state_flag(EXEC_SLEEP); diff --git a/Grbl_Esp32/src/Protocol.cpp b/Grbl_Esp32/src/Protocol.cpp index 98095160..2d6b88e6 100644 --- a/Grbl_Esp32/src/Protocol.cpp +++ b/Grbl_Esp32/src/Protocol.cpp @@ -472,7 +472,7 @@ void protocol_exec_rt_system() { sys.spindle_speed_ovr = last_s_override; sys.report_ovr_counter = 0; // Set to report change immediately // If spinlde is on, tell it the rpm has been overridden - if (gc_state.modal.spindle != SPINDLE_DISABLE) + if (gc_state.modal.spindle != SpindleState::Disable) spindle->set_rpm(gc_state.spindle_speed); } if (rt_exec & EXEC_SPINDLE_OVR_STOP) { @@ -489,21 +489,21 @@ void protocol_exec_rt_system() { // run state can be determined by checking the parser state. if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) { if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) { - uint8_t coolant_state = gc_state.modal.coolant; + CoolantMode coolant_state = gc_state.modal.coolant; #ifdef COOLANT_FLOOD_PIN if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE) { - if (coolant_state & COOLANT_FLOOD_ENABLE) - bit_false(coolant_state, COOLANT_FLOOD_ENABLE); + if (coolant_state & CoolantMode::Flood) + bit_false(coolant_state, CoolantMode::Flood); else - coolant_state |= COOLANT_FLOOD_ENABLE; + coolant_state |= CoolantMode::Flood; } #endif #ifdef COOLANT_MIST_PIN if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) { - if (coolant_state & COOLANT_MIST_ENABLE) - bit_false(coolant_state, COOLANT_MIST_ENABLE); + if (coolant_state & CoolantMode::Mist) + bit_false(coolant_state, CoolantMode::Mist); else - coolant_state |= COOLANT_MIST_ENABLE; + coolant_state |= CoolantMode::Mist; } #endif coolant_set_state(coolant_state); // Report counter set in coolant_set_state(). @@ -536,19 +536,22 @@ static void protocol_exec_rt_suspend() { plan_line_data_t plan_data; plan_line_data_t* pl_data = &plan_data; memset(pl_data, 0, sizeof(plan_line_data_t)); - pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE); + pl_data->motion = (PL_MOTION_SYSTEM_MOTION | PL_MOTION_NO_FEED_OVERRIDE); # ifdef USE_LINE_NUMBERS pl_data->line_number = PARKING_MOTION_LINE_NUMBER; # endif #endif plan_block_t* block = plan_get_current_block(); - uint8_t restore_condition; + CoolantMode restore_coolant; + SpindleState restore_spindle; float restore_spindle_speed; if (block == NULL) { - restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant); + restore_coolant = gc_state.modal.coolant; + restore_spindle = gc_state.modal.spindle; restore_spindle_speed = gc_state.spindle_speed; } else { - restore_condition = block->condition; + restore_coolant = block->coolant; + restore_spindle = block->spindle; restore_spindle_speed = block->spindle_speed; } #ifdef DISABLE_LASER_DURING_HOLD @@ -569,8 +572,8 @@ static void protocol_exec_rt_suspend() { // Ensure any prior spindle stop override is disabled at start of safety door routine. sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; #ifndef PARKING_ENABLE - spindle->set_state(SPINDLE_DISABLE, 0); // De-energize - coolant_set_state(COOLANT_DISABLE); // De-energize + spindle->set_state(SpindleState::Disable, 0); // De-energize + coolant_set_state(CoolantMode::Disable); // De-energize #else // Get current position and store restore location and spindle retract waypoint. system_convert_array_steps_to_mpos(parking_target, sys_position); @@ -588,16 +591,19 @@ static void protocol_exec_rt_suspend() { if (parking_target[PARKING_AXIS] < retract_waypoint) { parking_target[PARKING_AXIS] = retract_waypoint; pl_data->feed_rate = PARKING_PULLOUT_RATE; - pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Retain accessory state - pl_data->spindle_speed = restore_spindle_speed; + pl_data->coolant = restore_coolant; + pl_data->spindle = restore_spindle; + pl_data->spindle_speed = restore_spindle_speed; mc_parking_motion(parking_target, pl_data); } // NOTE: Clear accessory state after retract and after an aborted restore motion. - pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE); + pl_data->spindle = SpindleState::Disable; + pl_data->coolant = CoolantMode::Disable; + pl_data->motion = (PL_MOTION_SYSTEM_MOTION | PL_MOTION_NO_FEED_OVERRIDE); pl_data->spindle_speed = 0.0; - spindle->set_state(SPINDLE_DISABLE, 0); // De-energize - coolant_set_state(COOLANT_DISABLE); // De-energize - // Execute fast parking retract motion to parking target location. + spindle->set_state(SpindleState::Disable, 0); // De-energize + coolant_set_state(CoolantMode::Disable); // De-energize + // Execute fast parking retract motion to parking target location. if (parking_target[PARKING_AXIS] < PARKING_TARGET) { parking_target[PARKING_AXIS] = PARKING_TARGET; pl_data->feed_rate = PARKING_RATE; @@ -606,8 +612,8 @@ static void protocol_exec_rt_suspend() { } else { // Parking motion not possible. Just disable the spindle and coolant. // NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately. - spindle->set_state(SPINDLE_DISABLE, 0); // De-energize - coolant_set_state(COOLANT_DISABLE); // De-energize + spindle->set_state(SpindleState::Disable, 0); // De-energize + coolant_set_state(CoolantMode::Disable); // De-energize } #endif sys.suspend &= ~(SUSPEND_RESTART_RETRACT); @@ -616,9 +622,9 @@ static void protocol_exec_rt_suspend() { if (sys.state == STATE_SLEEP) { report_feedback_message(MESSAGE_SLEEP_MODE); // Spindle and coolant should already be stopped, but do it again just to be sure. - spindle->set_state(SPINDLE_DISABLE, 0); // De-energize - coolant_set_state(COOLANT_DISABLE); // De-energize - st_go_idle(); // Disable steppers + spindle->set_state(SpindleState::Disable, 0); // De-energize + coolant_set_state(CoolantMode::Disable); // De-energize + st_go_idle(); // Disable steppers while (!(sys.abort)) protocol_exec_rt_system(); // Do nothing until reset. return; // Abort received. Return to re-initialize. @@ -644,24 +650,23 @@ static void protocol_exec_rt_suspend() { } #endif // Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle. - if (gc_state.modal.spindle != SPINDLE_DISABLE) { + if (gc_state.modal.spindle != SpindleState::Disable) { // Block if safety door re-opened during prior restore actions. if (bit_isfalse(sys.suspend, SUSPEND_RESTART_RETRACT)) { if (laser_mode->get()) { // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts. bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM); } else { - spindle->set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), - (uint32_t)restore_spindle_speed); + spindle->set_state(restore_spindle, (uint32_t)restore_spindle_speed); delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND); } } } - if (gc_state.modal.coolant != COOLANT_DISABLE) { + if (gc_state.modal.coolant != CoolantMode::Disable) { // Block if safety door re-opened during prior restore actions. if (bit_isfalse(sys.suspend, SUSPEND_RESTART_RETRACT)) { // NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin. - coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_FLOOD))); + coolant_set_state(restore_coolant); delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND); } } @@ -673,8 +678,9 @@ static void protocol_exec_rt_suspend() { // Regardless if the retract parking motion was a valid/safe motion or not, the // restore parking motion should logically be valid, either by returning to the // original position through valid machine space or by not moving at all. - pl_data->feed_rate = PARKING_PULLOUT_RATE; - pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state + pl_data->feed_rate = PARKING_PULLOUT_RATE; + pl_data->spindle = restore_spindle; + pl_data->coolant = restore_coolant; pl_data->spindle_speed = restore_spindle_speed; mc_parking_motion(restore_target, pl_data); } @@ -692,22 +698,22 @@ static void protocol_exec_rt_suspend() { if (sys.spindle_stop_ovr) { // Handles beginning of spindle stop if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) { - if (gc_state.modal.spindle != SPINDLE_DISABLE) { - spindle->set_state(SPINDLE_DISABLE, 0); // De-energize + if (gc_state.modal.spindle != SpindleState::Disable) { + spindle->set_state(SpindleState::Disable, 0); // De-energize sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized. } else { sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state } // Handles restoring of spindle state } else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) { - if (gc_state.modal.spindle != SPINDLE_DISABLE) { + if (gc_state.modal.spindle != SpindleState::Disable) { report_feedback_message(MESSAGE_SPINDLE_RESTORE); if (laser_mode->get()) { // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts. bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM); - } else - spindle->set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), - (uint32_t)restore_spindle_speed); + } else { + spindle->set_state(restore_spindle, (uint32_t)restore_spindle_speed); + } } if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) { system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program. @@ -718,8 +724,7 @@ static void protocol_exec_rt_suspend() { // Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state. // NOTE: STEP_CONTROL_UPDATE_SPINDLE_RPM is automatically reset upon resume in step generator. if (bit_istrue(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM)) { - spindle->set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), - (uint32_t)restore_spindle_speed); + spindle->set_state(restore_spindle, (uint32_t)restore_spindle_speed); bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM); } } diff --git a/Grbl_Esp32/src/Report.cpp b/Grbl_Esp32/src/Report.cpp index 42228b27..c969ae80 100644 --- a/Grbl_Esp32/src/Report.cpp +++ b/Grbl_Esp32/src/Report.cpp @@ -337,50 +337,92 @@ void report_ngc_parameters(uint8_t client) { // Print current gcode parser mode state void report_gcode_modes(uint8_t client) { - char temp[20]; - char modes_rpt[75]; - strcpy(modes_rpt, "[GC:G"); - if (gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) - sprintf(temp, "38.%d", gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD - 2)); - else - sprintf(temp, "%d", gc_state.modal.motion); - strcat(modes_rpt, temp); + char temp[20]; + char modes_rpt[75]; + const char* mode = ""; + strcpy(modes_rpt, "[GC:"); + + switch (gc_state.modal.motion) { + case Motion::None: mode = "G80"; break; + case Motion::Seek: mode = "G0"; break; + case Motion::Linear: mode = "G1"; break; + case Motion::CwArc: mode = "G2"; break; + case Motion::CcwArc: mode = "G3"; break; + case Motion::ProbeToward: mode = "G38.1"; break; + case Motion::ProbeTowardNoError: mode = "G38.2"; break; + case Motion::ProbeAway: mode = "G38.3"; break; + case Motion::ProbeAwayNoError: mode = "G38.4"; break; + } + strcat(modes_rpt, mode); + sprintf(temp, " G%d", gc_state.modal.coord_select + 54); strcat(modes_rpt, temp); - sprintf(temp, " G%d", gc_state.modal.plane_select + 17); - strcat(modes_rpt, temp); - sprintf(temp, " G%d", 21 - gc_state.modal.units); - strcat(modes_rpt, temp); - sprintf(temp, " G%d", gc_state.modal.distance + 90); - strcat(modes_rpt, temp); - sprintf(temp, " G%d", 94 - gc_state.modal.feed_rate); - strcat(modes_rpt, temp); - if (gc_state.modal.program_flow) { - //report_util_gcode_modes_M(); - switch (gc_state.modal.program_flow) { - case PROGRAM_FLOW_PAUSED: - strcat(modes_rpt, " M0"); //serial_write('0'); break; - // case PROGRAM_FLOW_OPTIONAL_STOP : serial_write('1'); break; // M1 is ignored and not supported. - case PROGRAM_FLOW_COMPLETED_M2: - case PROGRAM_FLOW_COMPLETED_M30: - sprintf(temp, " M%d", gc_state.modal.program_flow); - strcat(modes_rpt, temp); - break; + + switch (gc_state.modal.plane_select) { + case Plane::XY: mode = " G17"; break; + case Plane::ZX: mode = " G18"; break; + case Plane::YZ: mode = " G19"; break; + } + strcat(modes_rpt, mode); + + switch (gc_state.modal.units) { + case Units::Inches: mode = " G20"; break; + case Units::Mm: mode = " G21"; break; + } + strcat(modes_rpt, mode); + + switch (gc_state.modal.distance) { + case Distance::Absolute: mode = " G90"; break; + case Distance::Incremental: mode = " G91"; break; + } + strcat(modes_rpt, mode); + +#if 0 + switch (gc_state.modal.arc_distance) { + case ArcDistance::Absolute: mode = " G90.1"; break; + case ArcDistance::Incremental: mode = " G91.1"; break; + } + strcat(modes_rpt, mode); +#endif + + switch (gc_state.modal.feed_rate) { + case FeedRate::UnitsPerMin: mode = " G94"; break; + case FeedRate::InverseTime: mode = " G93"; break; + } + strcat(modes_rpt, mode); + + //report_util_gcode_modes_M(); + switch (gc_state.modal.program_flow) { + case ProgramFlow::Running: mode = ""; break; + case ProgramFlow::Paused: mode = " M0"; break; + case ProgramFlow::OptionalStop: mode = " M1"; break; + case ProgramFlow::CompletedM2: mode = " M2"; break; + case ProgramFlow::CompletedM30: mode = " M30"; break; + } + strcat(modes_rpt, mode); + + switch (gc_state.modal.spindle) { + case SpindleState::Cw: mode = " M3"; break; + case SpindleState::Ccw: mode = " M4"; break; + case SpindleState::Disable: mode = " M5"; break; + default: mode = ""; + } + strcat(modes_rpt, mode); + + //report_util_gcode_modes_M(); // optional M7 and M8 should have been dealt with by here + if (gc_state.modal.coolant == CoolantMode::Disable) { + mode = " M9"; + } else { + uint8_t coolant = static_cast(gc_state.modal.coolant); + // Note: Multiple coolant states may be active at the same time. + if (coolant & static_cast(CoolantMode::Mist)) { + mode = " M7"; + } + if (coolant & static_cast(CoolantMode::Flood)) { + mode = " M8"; } } - switch (gc_state.modal.spindle) { - case SPINDLE_ENABLE_CW: strcat(modes_rpt, " M3"); break; - case SPINDLE_ENABLE_CCW: strcat(modes_rpt, " M4"); break; - case SPINDLE_DISABLE: strcat(modes_rpt, " M5"); break; - } - //report_util_gcode_modes_M(); // optional M7 and M8 should have been dealt with by here - if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time. - if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) - strcat(modes_rpt, " M7"); - if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) - strcat(modes_rpt, " M8"); - } else - strcat(modes_rpt, " M9"); + strcat(modes_rpt, mode); #ifdef ENABLE_PARKING_OVERRIDE_CONTROL if (sys.override_ctrl == OVERRIDE_PARKING_MOTION) @@ -664,20 +706,21 @@ void report_realtime_status(uint8_t client) { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT - 1); sprintf(temp, "|Ov:%d,%d,%d", sys.f_override, sys.r_override, sys.spindle_speed_ovr); strcat(status, temp); - uint8_t sp_state = spindle->get_state(); - uint8_t cl_state = coolant_get_state(); - if (sp_state || cl_state) { + SpindleState sp_state = spindle->get_state(); + CoolantMode coolant_state = coolant_get_state(); + if (sp_state != SpindleState::Disable || coolant_state != CoolantMode::Disable) { strcat(status, "|A:"); - if (sp_state) { // != SPINDLE_STATE_DISABLE - if (sp_state == SPINDLE_STATE_CW) - strcat(status, "S"); // CW - else - strcat(status, "C"); // CCW + switch (sp_state) { + case SpindleState::Disable: break; + case SpindleState::Cw: strcat(status, "S"); break; + case SpindleState::Ccw: strcat(status, "C"); break; } - if (cl_state & COOLANT_STATE_FLOOD) + + uint8_t coolant = static_cast(coolant_state); + if (coolant & static_cast(CoolantMode::Flood)) strcat(status, "F"); # ifdef COOLANT_MIST_PIN // TODO Deal with M8 - Flood - if (cl_state & COOLANT_STATE_MIST) + if (coolant & static_cast(CoolantMode::Mist)) strcat(status, "M"); # endif } diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.cpp b/Grbl_Esp32/src/Spindles/10vSpindle.cpp index 14cb841c..905f868e 100644 --- a/Grbl_Esp32/src/Spindles/10vSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/10vSpindle.cpp @@ -104,31 +104,31 @@ namespace Spindles { return rpm; } /* - void _10v::set_state(uint8_t state, uint32_t rpm) { + void _10v::set_state(SpindleState state, uint32_t rpm) { if (sys.abort) return; // Block during abort. - if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. + if (state == SpindleState::Disable) { // Halt or set spindle direction and rpm. sys.spindle_speed = 0; stop(); } else { - set_dir_pin(state == SPINDLE_ENABLE_CW); + set_dir_pin(state == SpindleState:Cw); set_rpm(rpm); } - set_enable_pin(state != SPINDLE_DISABLE); + set_enable_pin(state != SpindleState::Disable); sys.report_ovr_counter = 0; // Set to report change immediately } */ - uint8_t _10v::get_state() { + SpindleState _10v::get_state() { if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) - return (SPINDLE_STATE_DISABLE); + return (SpindleState::Disable); if (_direction_pin != UNDEFINED_PIN) - return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; - return (SPINDLE_STATE_CW); + return digitalRead(_direction_pin) ? SpindleState::Cw : SpindleState::Ccw; + return (SpindleState::Cw); } void _10v::stop() { @@ -142,7 +142,6 @@ namespace Spindles { if (_off_with_zero_speed && sys.spindle_speed == 0) enable = false; - if (spindle_enable_invert->get()) enable = !enable; diff --git a/Grbl_Esp32/src/Spindles/10vSpindle.h b/Grbl_Esp32/src/Spindles/10vSpindle.h index dc0e5b22..a0205320 100644 --- a/Grbl_Esp32/src/Spindles/10vSpindle.h +++ b/Grbl_Esp32/src/Spindles/10vSpindle.h @@ -41,10 +41,10 @@ namespace Spindles { void init() override; void config_message() override; uint32_t set_rpm(uint32_t rpm) override; - //void set_state(uint8_t state, uint32_t rpm); + //void set_state(SpindleState state, uint32_t rpm); - uint8_t get_state() override; - void stop() override; + SpindleState get_state() override; + void stop() override; virtual ~_10v() {} diff --git a/Grbl_Esp32/src/Spindles/H2ASpindle.cpp b/Grbl_Esp32/src/Spindles/H2ASpindle.cpp index 9da1a871..7e504250 100644 --- a/Grbl_Esp32/src/Spindles/H2ASpindle.cpp +++ b/Grbl_Esp32/src/Spindles/H2ASpindle.cpp @@ -41,7 +41,7 @@ namespace Spindles { uart.stop_bits = UART_STOP_BITS_1; } - void H2A::direction_command(uint8_t mode, ModbusCommand& data) { + void H2A::direction_command(SpindleState mode, ModbusCommand& data) { // NOTE: data length is excluding the CRC16 checksum. data.tx_length = 6; data.rx_length = 6; @@ -50,7 +50,7 @@ namespace Spindles { data.msg[2] = 0x20; // Command ID 0x2000 data.msg[3] = 0x00; data.msg[4] = 0x00; - data.msg[5] = (mode == SPINDLE_ENABLE_CCW) ? 0x02 : (mode == SPINDLE_ENABLE_CW ? 0x01 : 0x06); + data.msg[5] = (mode == SpindleState::Ccw) ? 0x02 : (mode == SpindleState::Cw ? 0x01 : 0x06); } void H2A::set_speed_command(uint32_t rpm, ModbusCommand& data) { diff --git a/Grbl_Esp32/src/Spindles/H2ASpindle.h b/Grbl_Esp32/src/Spindles/H2ASpindle.h index d022e421..d206603b 100644 --- a/Grbl_Esp32/src/Spindles/H2ASpindle.h +++ b/Grbl_Esp32/src/Spindles/H2ASpindle.h @@ -26,7 +26,7 @@ namespace Spindles { protected: void default_modbus_settings(uart_config_t& uart) override; - void direction_command(uint8_t mode, ModbusCommand& data) override; + void direction_command(SpindleState mode, ModbusCommand& data) override; void set_speed_command(uint32_t rpm, ModbusCommand& data) override; response_parser get_max_rpm(ModbusCommand& data) override; diff --git a/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp b/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp index e7b4bf3f..7a1dbfef 100644 --- a/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/HuanyangSpindle.cpp @@ -120,7 +120,7 @@ namespace Spindles { // Baud rate is set in the PD164 setting. } - void Huanyang::direction_command(uint8_t mode, ModbusCommand& data) { + void Huanyang::direction_command(SpindleState mode, ModbusCommand& data) { // NOTE: data length is excluding the CRC16 checksum. data.tx_length = 4; data.rx_length = 4; @@ -130,9 +130,9 @@ namespace Spindles { data.msg[2] = 0x01; switch (mode) { - case SPINDLE_ENABLE_CW: data.msg[3] = 0x01; break; - case SPINDLE_ENABLE_CCW: data.msg[3] = 0x11; break; - default: // SPINDLE_DISABLE + case SpindleState::Cw: data.msg[3] = 0x01; break; + case SpindleState::Ccw: data.msg[3] = 0x11; break; + default: // SpindleState::Disable data.msg[3] = 0x08; break; } diff --git a/Grbl_Esp32/src/Spindles/HuanyangSpindle.h b/Grbl_Esp32/src/Spindles/HuanyangSpindle.h index 7aacc433..48fecfdf 100644 --- a/Grbl_Esp32/src/Spindles/HuanyangSpindle.h +++ b/Grbl_Esp32/src/Spindles/HuanyangSpindle.h @@ -30,7 +30,7 @@ namespace Spindles { protected: void default_modbus_settings(uart_config_t& uart) override; - void direction_command(uint8_t mode, ModbusCommand& data) override; + void direction_command(SpindleState mode, ModbusCommand& data) override; void set_speed_command(uint32_t rpm, ModbusCommand& data) override; response_parser get_status_ok(ModbusCommand& data) override; diff --git a/Grbl_Esp32/src/Spindles/NullSpindle.cpp b/Grbl_Esp32/src/Spindles/NullSpindle.cpp index cad13e40..0af1edf0 100644 --- a/Grbl_Esp32/src/Spindles/NullSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/NullSpindle.cpp @@ -34,11 +34,11 @@ namespace Spindles { sys.spindle_speed = rpm; return rpm; } - void Null::set_state(uint8_t state, uint32_t rpm) { + void Null::set_state(SpindleState state, uint32_t rpm) { _current_state = state; sys.spindle_speed = rpm; } - uint8_t Null::get_state() { return _current_state; } - void Null::stop() {} - void Null::config_message() { grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle"); } + SpindleState Null::get_state() { return _current_state; } + void Null::stop() {} + void Null::config_message() { grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle"); } } diff --git a/Grbl_Esp32/src/Spindles/NullSpindle.h b/Grbl_Esp32/src/Spindles/NullSpindle.h index 1d6a2e46..87f08473 100644 --- a/Grbl_Esp32/src/Spindles/NullSpindle.h +++ b/Grbl_Esp32/src/Spindles/NullSpindle.h @@ -35,12 +35,12 @@ namespace Spindles { Null& operator=(const Null&) = delete; Null& operator=(Null&&) = delete; - void init() override; - uint32_t set_rpm(uint32_t rpm) override; - void set_state(uint8_t state, uint32_t rpm) override; - uint8_t get_state() override; - void stop() override; - void config_message() override; + void init() override; + uint32_t set_rpm(uint32_t rpm) override; + void set_state(SpindleState state, uint32_t rpm) override; + SpindleState get_state() override; + void stop() override; + void config_message() override; virtual ~Null() {} }; diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp index 9a1ca848..029cd470 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp @@ -140,19 +140,19 @@ namespace Spindles { pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value); } - set_enable_pin(_current_state != SPINDLE_DISABLE); + set_enable_pin(_current_state != SpindleState::Disable); set_output(pwm_value); return 0; } - void PWM::set_state(uint8_t state, uint32_t rpm) { + void PWM::set_state(SpindleState state, uint32_t rpm) { if (sys.abort) return; // Block during abort. _current_state = state; - if (_current_state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm. + if (_current_state == SpindleState::Disable) { // Halt or set spindle direction and rpm. sys.spindle_speed = 0; stop(); if (use_delays && (_current_state != state)) { @@ -161,9 +161,9 @@ namespace Spindles { //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done"); } } else { - set_dir_pin(_current_state == SPINDLE_ENABLE_CW); + set_dir_pin(_current_state == SpindleState::Cw); set_rpm(rpm); - set_enable_pin(_current_state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work + set_enable_pin(_current_state != SpindleState::Disable); // must be done after setting rpm for enable features to work if (use_delays && (_current_state != state)) { //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm); mc_dwell(spindle_delay_spinup->get()); @@ -176,12 +176,12 @@ namespace Spindles { sys.report_ovr_counter = 0; // Set to report change immediately } - uint8_t PWM::get_state() { + SpindleState PWM::get_state() { if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN) - return (SPINDLE_STATE_DISABLE); + return (SpindleState::Disable); if (_direction_pin != UNDEFINED_PIN) - return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW; - return (SPINDLE_STATE_CW); + return digitalRead(_direction_pin) ? SpindleState::Cw : SpindleState::Ccw; + return (SpindleState::Cw); } void PWM::stop() { diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.h b/Grbl_Esp32/src/Spindles/PWMSpindle.h index a12b4739..cb306a1d 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.h +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.h @@ -36,8 +36,8 @@ namespace Spindles { void init() override; virtual uint32_t set_rpm(uint32_t rpm) override; - void set_state(uint8_t state, uint32_t rpm) override; - uint8_t get_state() override; + void set_state(SpindleState state, uint32_t rpm) override; + SpindleState get_state() override; void stop() override; void config_message() override; @@ -66,7 +66,7 @@ namespace Spindles { virtual void set_output(uint32_t duty); virtual void set_enable_pin(bool enable_pin); - void get_pins_and_settings(); - uint8_t calc_pwm_precision(uint32_t freq); + void get_pins_and_settings(); + uint8_t calc_pwm_precision(uint32_t freq); }; } diff --git a/Grbl_Esp32/src/Spindles/Spindle.cpp b/Grbl_Esp32/src/Spindles/Spindle.cpp index e971437c..bb8e049a 100644 --- a/Grbl_Esp32/src/Spindles/Spindle.cpp +++ b/Grbl_Esp32/src/Spindles/Spindle.cpp @@ -75,9 +75,10 @@ namespace Spindles { return false; // default for basic spindle is false } - void Spindle::sync(uint8_t state, uint32_t rpm) { - if (sys.state == STATE_CHECK_MODE) + void Spindle::sync(SpindleState state, uint32_t rpm) { + if (sys.state == STATE_CHECK_MODE) { return; + } protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed. set_state(state, rpm); } diff --git a/Grbl_Esp32/src/Spindles/Spindle.h b/Grbl_Esp32/src/Spindles/Spindle.h index d09ede2d..5477ff41 100644 --- a/Grbl_Esp32/src/Spindles/Spindle.h +++ b/Grbl_Esp32/src/Spindles/Spindle.h @@ -26,10 +26,6 @@ */ -#define SPINDLE_STATE_DISABLE 0 // Must be zero. -#define SPINDLE_STATE_CW bit(4) // matches PL_COND_FLAG_SPINDLE_CW -#define SPINDLE_STATE_CCW bit(5) // matches PL_COND_FLAG_SPINDLE_CCW - #define SPINDLE_TYPE_NONE 0 #define SPINDLE_TYPE_PWM 1 #define SPINDLE_TYPE_RELAY 2 @@ -58,20 +54,20 @@ namespace Spindles { Spindle& operator=(const Spindle&) = delete; Spindle& operator=(Spindle&&) = delete; - virtual void init() = 0; // not in constructor because this also gets called when $$ settings change - virtual uint32_t set_rpm(uint32_t rpm) = 0; - virtual void set_state(uint8_t state, uint32_t rpm) = 0; - virtual uint8_t get_state() = 0; - virtual void stop() = 0; - virtual void config_message() = 0; - virtual bool isRateAdjusted(); - virtual void sync(uint8_t state, uint32_t rpm); + virtual void init() = 0; // not in constructor because this also gets called when $$ settings change + virtual uint32_t set_rpm(uint32_t rpm) = 0; + virtual void set_state(SpindleState state, uint32_t rpm) = 0; + virtual SpindleState get_state() = 0; + virtual void stop() = 0; + virtual void config_message() = 0; + virtual bool isRateAdjusted(); + virtual void sync(SpindleState state, uint32_t rpm); virtual ~Spindle() {} - bool is_reversable; - bool use_delays; // will SpinUp and SpinDown delays be used. - volatile uint8_t _current_state = SPINDLE_DISABLE; + bool is_reversable; + bool use_delays; // will SpinUp and SpinDown delays be used. + volatile SpindleState _current_state = SpindleState::Disable; static void select(); }; diff --git a/Grbl_Esp32/src/Spindles/VFDSpindle.cpp b/Grbl_Esp32/src/Spindles/VFDSpindle.cpp index 46eea6c7..9e6c6137 100644 --- a/Grbl_Esp32/src/Spindles/VFDSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/VFDSpindle.cpp @@ -283,7 +283,7 @@ namespace Spindles { // Initially we initialize this to 0; over time, we might poll better information from the VFD. _current_rpm = 0; - _current_state = SPINDLE_DISABLE; + _current_state = SpindleState::Disable; config_message(); } @@ -335,17 +335,17 @@ namespace Spindles { pinName(_rts_pin).c_str()); } - void VFD::set_state(uint8_t state, uint32_t rpm) { + void VFD::set_state(SpindleState state, uint32_t rpm) { if (sys.abort) { return; // Block during abort. } - bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE); + bool critical = (sys.state == STATE_CYCLE || state != SpindleState::Disable); if (_current_state != state) { // already at the desired state. This function gets called a lot. set_mode(state, critical); // critical if we are in a job set_rpm(rpm); - if (state == SPINDLE_DISABLE) { + if (state == SpindleState::Disable) { sys.spindle_speed = 0; if (_current_state != state) { mc_dwell(spindle_delay_spindown->get()); @@ -368,7 +368,7 @@ namespace Spindles { return; } - bool VFD::set_mode(uint8_t mode, bool critical) { + bool VFD::set_mode(SpindleState mode, bool critical) { if (!vfd_ok) { return false; } @@ -378,7 +378,7 @@ namespace Spindles { direction_command(mode, mode_cmd); - if (mode == SPINDLE_DISABLE) { + if (mode == SpindleState::Disable) { if (!xQueueReset(vfd_cmd_queue)) { grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset"); } @@ -437,10 +437,10 @@ namespace Spindles { return rpm; } - void VFD::stop() { set_mode(SPINDLE_DISABLE, false); } + void VFD::stop() { set_mode(SpindleState::Disable, false); } // state is cached rather than read right now to prevent delays - uint8_t VFD::get_state() { return _current_state; } + SpindleState VFD::get_state() { return _current_state; } // Calculate the CRC on all of the byte except the last 2 // It then added the CRC to those last 2 bytes diff --git a/Grbl_Esp32/src/Spindles/VFDSpindle.h b/Grbl_Esp32/src/Spindles/VFDSpindle.h index 34daa9ba..1c852292 100644 --- a/Grbl_Esp32/src/Spindles/VFDSpindle.h +++ b/Grbl_Esp32/src/Spindles/VFDSpindle.h @@ -27,9 +27,9 @@ namespace Spindles { class VFD : public Spindle { private: static const int VFD_RS485_MAX_MSG_SIZE = 16; // more than enough for a modbus message - static const int MAX_RETRIES = 3; // otherwise the spindle is marked 'unresponsive' + static const int MAX_RETRIES = 3; // otherwise the spindle is marked 'unresponsive' - bool set_mode(uint8_t mode, bool critical); + bool set_mode(SpindleState mode, bool critical); bool get_pins_and_settings(); uint8_t _txd_pin; @@ -48,7 +48,7 @@ namespace Spindles { protected: struct ModbusCommand { - bool critical; // TODO SdB: change into `uint8_t critical : 1;`: We want more flags... + bool critical; // TODO SdB: change into `uint8_t critical : 1;`: We want more flags... uint8_t tx_length; uint8_t rx_length; @@ -58,8 +58,8 @@ namespace Spindles { virtual void default_modbus_settings(uart_config_t& uart); // Commands: - virtual void direction_command(uint8_t mode, ModbusCommand& data) = 0; - virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0; + virtual void direction_command(SpindleState mode, ModbusCommand& data) = 0; + virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0; // Commands that return the status. Returns nullptr if unavailable by this VFD (default): using response_parser = bool (*)(const uint8_t* response, VFD* spindle); @@ -76,17 +76,17 @@ namespace Spindles { VFD& operator=(const VFD&) = delete; VFD& operator=(VFD&&) = delete; - // TODO FIXME: Have to make these public because of the parsers. + // TODO FIXME: Have to make these public because of the parsers. // Should hide them and use a member function. volatile uint32_t _min_rpm; volatile uint32_t _max_rpm; - void init(); - void config_message(); - void set_state(uint8_t state, uint32_t rpm); - uint8_t get_state(); - uint32_t set_rpm(uint32_t rpm); - void stop(); + void init(); + void config_message(); + void set_state(SpindleState state, uint32_t rpm); + SpindleState get_state(); + uint32_t set_rpm(uint32_t rpm); + void stop(); virtual ~VFD() {} }; diff --git a/Grbl_Esp32/src/Stepper.cpp b/Grbl_Esp32/src/Stepper.cpp index 910a1d06..c6d05c07 100644 --- a/Grbl_Esp32/src/Stepper.cpp +++ b/Grbl_Esp32/src/Stepper.cpp @@ -502,8 +502,8 @@ void st_reset() { segment_buffer_head = 0; // empty = tail segment_next_head = 1; busy = false; - st.step_outbits = 0; - st.dir_outbits = dir_invert_mask->get(); // Initialize direction bits to default. + st.step_outbits = 0; + st.dir_outbits = dir_invert_mask->get(); // Initialize direction bits to default. // TODO do we need to turn step pins off? } @@ -834,7 +834,7 @@ void st_prep_buffer() { prep.current_speed = sqrt(pl_block->entry_speed_sqr); if (spindle->isRateAdjusted()) { // laser_mode->get() { - if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) { + if (pl_block->spindle == SpindleState::Ccw) { // Pre-compute inverse programmed rate to speed up PWM updating per step segment. prep.inv_rate = 1.0 / pl_block->programmed_rate; st_prep_block->is_pwm_rate_adjusted = true; @@ -1034,7 +1034,7 @@ void st_prep_buffer() { Compute spindle speed PWM output for step segment */ if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_RPM)) { - if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) { + if (pl_block->spindle != SpindleState::Disable) { float rpm = pl_block->spindle_speed; // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate. if (st_prep_block->is_pwm_rate_adjusted) { diff --git a/Grbl_Esp32/src/tests/parser-result.txt b/Grbl_Esp32/src/tests/parser-result.txt new file mode 100644 index 00000000..8ff0c403 --- /dev/null +++ b/Grbl_Esp32/src/tests/parser-result.txt @@ -0,0 +1,665 @@ +ets Jul 29 2019 12:21:46 + +rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) +configsip: 0, SPIWP:0xee +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:1 +load:0x3fff0018,len:4 +load:0x3fff001c,len:1216 +ho 0 tail 12 room 4 +load:0x40078000,len:9720 +ho 0 tail 12 room 4 +load:0x40080400,len:6352 +entry 0x400806b8 + +[MSG:Grbl_ESP32 Ver 1.3a Date 20200831] +[MSG:Compiled with ESP32 SDK:v3.2.3-14-gd3e562907] +[MSG:Using machine:Test Drive - Demo Only No I/O!] +[MSG:Axis count 3] +[MSG:Timed Steps] +[MSG:Init Motors] +[MSG:No spindle] + +[MSG:Client Started] +[MSG:Connecting OpenWrt-Bradley] +[MSG:Connecting.] +[MSG:Connecting..] +[MSG:Connecting...] +[MSG:Connected with 192.168.2.198] +[MSG:Start mDNS with hostname:http://grblesp.local/] +[MSG:SSDP Started] +[MSG:HTTP Started] +[MSG:TELNET Started 23] + +Grbl 1.3a ['$' for help] +; paste with a terminal emulator with a 200 ms delay between lines +ok +$rst=gcode +ok +$rst=# +ok +$# +[G54:0.000,0.000,0.000] +[G55:0.000,0.000,0.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:0.000,0.000,0.000] +[G28:0.000,0.000,0.000] +[G30:0.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g10 l2 p0 x0 y0 z0 +ok +g10 l2 p1 x0 y0 z0 +ok +g10 l2 p2 x0 y0 z0 +ok +g10 l2 p3 x0 y0 z0 +ok +g10 l2 p4 x0 y0 z0 +ok +g10 l2 p5 x0 y0 z0 +ok +g10 l2 p6 x0 y0 z0 +ok +? + +ok +g0 x0 y0 z0 +ok +? + +ok +G0 +ok +G0 X1 +ok +G0 I1 +error:36 +$G +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0 S0] +ok +G1 +error:22 +G1 Z10 +error:22 +$G +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0 S0] +ok +F1000 +ok +$G +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +G1 I1 +error:36 +G2 +error:26 +G2 X0 Y0 I-1 J-1 +error:33 +$g +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +G3 +error:26 +G3 X0 Y0 I-1 J-1 +error:33 +$g +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g4 +error:28 +g4 p0 +ok +g4.1 +error:23 +g4.2 +error:23 +g5 +error:20 +g6 +error:20 +g7 +error:20 +g8 +error:20 +g9 +error:20 +g10 +error:26 +g10 l1 +error:26 +g10 l2 +error:26 +g10 l2 p0 +error:26 +g10 l2 p0 x1 y2 z3 +ok +g10 l2 p2 x2 y3 z4 +ok +g10 l2 p6 x3 y4 z5 +ok +$# +[G54:1.000,2.000,3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:3.000,4.000,5.000] +[G28:0.000,0.000,0.000] +[G30:0.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g10 l2 p6 x3 y4 z5 r1 +error:20 +g10 l2 p7 x5 y4 z3 +error:29 +g10 l20 p0 x5 y4 z3 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:3.000,4.000,5.000] +[G28:0.000,0.000,0.000] +[G30:0.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g10 l20 p6 x5 y4 z3 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:-4.000,-4.000,-3.000] +[G28:0.000,0.000,0.000] +[G30:0.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g10 l20 p7 x5 y4 z3 +error:29 +g10 l20 p7 x5 y4 z3 +error:29 +g11 +error:20 +g12 +error:20 +g13 +error:20 +g13 +error:20 +g14 +error:20 +g15 +error:20 +g16 +error:20 + +ok +g17 +ok +$g +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g18 +ok +$g +[GC:G0 G54 G18 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g19 +ok +$g +[GC:G0 G54 G19 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g17 +ok + +ok +g20 +ok +$g +[GC:G0 G54 G17 G20 G90 G94 M5 M9 T0 F1000 S0] +ok +g21 +ok +$g +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok + +ok +g22 +error:20 +g23 +error:20 +g24 +error:20 +g25 +error:20 +g26 +error:20 +g27 +error:20 + +ok +g28 +ok +g28 x3 +ok +$# +error:8 +g28.1 +ok +g28.1 x3 +ok +g28.2 +error:20 +g29 +error:20 +g30 y1 +ok +$# +error:8 +g30.1 +ok +g30.1 y2 +ok +g30.2 +error:20 + +ok +g31 +error:20 +g32 +error:20 +g33 +error:20 +g34 +error:20 +g35 +error:20 +g36 +error:20 +g37 +error:20 +g38 +[MSG:No probe pin defined] +error:20 +g39 +error:20 + +ok +g40 +ok + +ok +g41 +error:20 +g42 +error:20 + +ok +g43 +error:20 +g43.1 x0 +error:37 +g43.1 z2 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:-4.000,-4.000,-3.000] +[G28:0.000,0.000,0.000] +[G30:-1.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:2.000] +[PRB:0.000,0.000,0.000:0] +ok + +ok +g44 +error:20 +g45 +error:20 +g46 +error:20 +g47 +error:20 +g48 +error:20 + +ok +g49 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:-4.000,-4.000,-3.000] +[G28:0.000,0.000,0.000] +[G30:-1.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g49.1 +ok + +ok +g50 +error:20 +g51 +error:20 +g52 +error:20 +g53 +ok +g53 g0 x1 +ok +g53.1 +error:23 + +ok +g54 +ok +$g +[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g55 +ok +$g +[GC:G0 G55 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g56 +ok +$g +[GC:G0 G56 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g57 +ok +$g +[GC:G0 G57 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g58 +ok +$g +[GC:G0 G58 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g59 g0 x1 +ok +$g +[GC:G0 G59 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok + +ok +g60 +error:20 + +ok +g61 +ok +g61.1 +error:20 + +ok +g62 +error:20 +g63 +error:20 +g64 +error:20 +g65 +error:20 +g66 +error:20 +g67 +error:20 +g68 +error:20 +g69 +error:20 +g70 +error:20 +g71 +error:20 +g72 +error:20 +g73 +error:20 +g74 +error:20 +g75 +error:20 +g76 +error:20 +g77 +error:20 +g78 +error:20 +g79 +error:20 + +ok +g80 +ok +$g +[GC:G80 G59 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +x1 +error:31 +g0 x1 +ok +$g +[GC:G0 G59 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok + +ok +g81 +error:20 +g82 +error:20 +g83 +error:20 +g84 +error:20 +g85 +error:20 +g86 +error:20 +g87 +error:20 +g88 +error:20 +g89 +error:20 + +ok +g90 +ok +$g +[GC:G0 G59 G17 G21 G90 G94 M5 M9 T0 F1000 S0] +ok +g90.1 +error:20 +g91 +ok +$g +[GC:G0 G59 G17 G21 G91 G94 M5 M9 T0 F1000 S0] +ok +g91.1 +ok + +ok +g92 +error:26 +g92 z1 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:-4.000,-4.000,-3.000] +[G28:0.000,0.000,0.000] +[G30:-1.000,0.000,0.000] +[G92:0.000,0.000,2.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g92.1 +ok +$# +[G54:-4.000,-4.000,-3.000] +[G55:2.000,3.000,4.000] +[G56:0.000,0.000,0.000] +[G57:0.000,0.000,0.000] +[G58:0.000,0.000,0.000] +[G59:-4.000,-4.000,-3.000] +[G28:0.000,0.000,0.000] +[G30:-1.000,0.000,0.000] +[G92:0.000,0.000,0.000] +[TLO:0.000] +[PRB:0.000,0.000,0.000:0] +ok +g92.1 z0 +ok +g92.2 +error:20 + +ok +g93 +ok +$g +[GC:G0 G59 G17 G21 G91 G93 M5 M9 T0 F0 S0] +ok +g94 +ok +$g +[GC:G0 G59 G17 G21 G91 G94 M5 M9 T0 F0 S0] +ok + +ok +g95 +error:20 +g96 +error:20 +g97 +error:20 +g98 +error:20 +g99 +error:20 + +ok +m0 +? + +~ +ok +ok +ok +? + +ok +m1 +ok +m2 +[MSG:Program End] +ok +? + +ok + +ok +m3 +ok +$g +[GC:G1 G54 G17 G21 G90 G94 M3 M9 T0 F0 S0] +ok +m4 +error:20 +$g +[GC:G1 G54 G17 G21 G90 G94 M3 M9 T0 F0 S0] +ok +m5 +ok +$g +[GC:G1 G54 G17 G21 G90 G94 M5 M9 T0 F0 S0] +ok + +ok +m6 +ok +t2 +[MSG:Tool No: 2] +ok + +ok +m7 +ok +$g +[GC:G1 G54 G17 G21 G90 G94 M5 M9 T2 F0 S0] +ok +m8 +ok +$g +[GC:G1 G54 G17 G21 G90 G94 M5 M9 T2 F0 S0] +ok +m9 +ok +$g +[GC:G1 G54 G17 G21 G90 G94 M5 M9 T2 F0 S0] +ok + +ok +m10 +error:20 +m55 +error:20 + +ok +m56 +error:20 + +ok +m62 +error:28 +m62 p0 +ok +m62 p1 +ok +m62 p4 +ok +m62 p5 +error:39 + +ok +m63 +error:28 +m63 p0 +ok +m63 p1 +ok +m63 p4 +ok +m63 p5 +error:39 + diff --git a/Grbl_Esp32/src/tests/parser.nc b/Grbl_Esp32/src/tests/parser.nc new file mode 100644 index 00000000..10d28c00 --- /dev/null +++ b/Grbl_Esp32/src/tests/parser.nc @@ -0,0 +1,253 @@ +; paste with a terminal emulator with a 200 ms delay between lines +$rst=gcode +$rst=# +$# +g10 l2 p0 x0 y0 z0 +g10 l2 p1 x0 y0 z0 +g10 l2 p2 x0 y0 z0 +g10 l2 p3 x0 y0 z0 +g10 l2 p4 x0 y0 z0 +g10 l2 p5 x0 y0 z0 +g10 l2 p6 x0 y0 z0 +? +g0 x0 y0 z0 +? +G0 +G0 X1 +G0 I1 +$G +G1 +G1 Z10 +$G +F1000 +$G +G1 I1 +G2 +G2 X0 Y0 I-1 J-1 +$g +G3 +G3 X0 Y0 I-1 J-1 +$g +g4 +g4 p0 +g4.1 +g4.2 +g5 +g6 +g7 +g8 +g9 +g10 +g10 l1 +g10 l2 +g10 l2 p0 +g10 l2 p0 x1 y2 z3 +g10 l2 p2 x2 y3 z4 +g10 l2 p6 x3 y4 z5 +$# +g10 l2 p6 x3 y4 z5 r1 +g10 l2 p7 x5 y4 z3 +g10 l20 p0 x5 y4 z3 +$# +g10 l20 p6 x5 y4 z3 +$# +g10 l20 p7 x5 y4 z3 +g10 l20 p7 x5 y4 z3 +g11 +g12 +g13 +g13 +g14 +g15 +g16 + +g17 +$g +g18 +$g +g19 +$g +g17 + +g20 +$g +g21 +$g + +g22 +g23 +g24 +g25 +g26 +g27 + +g28 +g28 x3 +$# +g28.1 +g28.1 x3 +g28.2 +g29 +g30 y1 +$# +g30.1 +g30.1 y2 +g30.2 + +g31 +g32 +g33 +g34 +g35 +g36 +g37 +g38 +g39 + +g40 + +g41 +g42 + +g43 +g43.1 x0 +g43.1 z2 +$# + +g44 +g45 +g46 +g47 +g48 + +g49 +$# +g49.1 + +g50 +g51 +g52 +g53 +g53 g0 x1 +g53.1 + +g54 +$g +g55 +$g +g56 +$g +g57 +$g +g58 +$g +g59 g0 x1 +$g + +g60 + +g61 +g61.1 + +g62 +g63 +g64 +g65 +g66 +g67 +g68 +g69 +g70 +g71 +g72 +g73 +g74 +g75 +g76 +g77 +g78 +g79 + +g80 +$g +x1 +g0 x1 +$g + +g81 +g82 +g83 +g84 +g85 +g86 +g87 +g88 +g89 + +g90 +$g +g90.1 +g91 +$g +g91.1 + +g92 +g92 z1 +$# +g92.1 +$# +g92.1 z0 +g92.2 + +g93 +$g +g94 +$g + +g95 +g96 +g97 +g98 +g99 + +m0 +? +~ +? +m1 +m2 +? + +m3 +$g +m4 +$g +m5 +$g + +m6 +t2 + +m7 +$g +m8 +$g +m9 +$g + +m10 +m55 + +m56 + +m62 +m62 p0 +m62 p1 +m62 p4 +m62 p5 + +m63 +m63 p0 +m63 p1 +m63 p4 +m63 p5