Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
gcode.c
00001 /* 00002 gcode.c - rs274/ngc parser. 00003 Part of Grbl 00004 00005 Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC 00006 Copyright (c) 2009-2011 Simen Svale Skogsrud 00007 00008 Grbl is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 Grbl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with Grbl. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 00022 #include "grbl.h" 00023 00024 // NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an 00025 // arbitrary value, and some GUIs may require more. So we increased it based on a max safe 00026 // value when converting a float (7.2 digit precision)s to an integer. 00027 #define MAX_LINE_NUMBER 10000000 00028 #define MAX_TOOL_NUMBER 255 // Limited by max unsigned 8-bit value 00029 00030 #define AXIS_COMMAND_NONE 0 00031 #define AXIS_COMMAND_NON_MODAL 1 00032 #define AXIS_COMMAND_MOTION_MODE 2 00033 #define AXIS_COMMAND_TOOL_LENGTH_OFFSET 3 // *Undefined but required 00034 00035 // Declare gc extern struct 00036 parser_state_t gc_state; 00037 parser_block_t gc_block; 00038 00039 #define FAIL(status) return(status); 00040 00041 00042 void gc_init() 00043 { 00044 memset(&gc_state, 0, sizeof(parser_state_t)); 00045 00046 // Load default G54 coordinate system. 00047 if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) { 00048 report_status_message(STATUS_SETTING_READ_FAIL); 00049 } 00050 } 00051 00052 00053 // Sets g-code parser position in mm. Input in steps. Called by the system abort and hard 00054 // limit pull-off routines. 00055 void gc_sync_position() 00056 { 00057 system_convert_array_steps_to_mpos(gc_state.position,sys_position); 00058 } 00059 00060 00061 // Executes one line of 0-terminated G-Code. The line is assumed to contain only uppercase 00062 // characters and signed floating point values (no whitespace). Comments and block delete 00063 // characters have been removed. In this function, all units and positions are converted and 00064 // exported to grbl's internal functions in terms of (mm, mm/min) and absolute machine 00065 // coordinates, respectively. 00066 uint8_t gc_execute_line(char *line) 00067 { 00068 /* ------------------------------------------------------------------------------------- 00069 STEP 1: Initialize parser block struct and copy current g-code state modes. The parser 00070 updates these modes and commands as the block line is parser and will only be used and 00071 executed after successful error-checking. The parser block struct also contains a block 00072 values struct, word tracking variables, and a non-modal commands tracker for the new 00073 block. This struct contains all of the necessary information to execute the block. */ 00074 00075 memset(&gc_block, 0, sizeof(parser_block_t)); // Initialize the parser block struct. 00076 memcpy(&gc_block.modal,&gc_state.modal,sizeof(gc_modal_t)); // Copy current modes 00077 00078 uint8_t axis_command = AXIS_COMMAND_NONE; 00079 uint8_t axis_0, axis_1, axis_linear; 00080 uint8_t coord_select = 0; // Tracks G10 P coordinate selection for execution 00081 00082 // Initialize bitflag tracking variables for axis indices compatible operations. 00083 uint8_t axis_words = 0; // XYZ tracking 00084 uint8_t ijk_words = 0; // IJK tracking 00085 00086 // Initialize command and value words and parser flags variables. 00087 uint16_t command_words = 0; // Tracks G and M command words. Also used for modal group violations. 00088 uint16_t value_words = 0; // Tracks value words. 00089 uint8_t gc_parser_flags = GC_PARSER_NONE; 00090 00091 // Determine if the line is a jogging motion or a normal g-code block. 00092 if (line[0] == '$') { // NOTE: `$J=` already parsed when passed to this function. 00093 // Set G1 and G94 enforced modes to ensure accurate error checks. 00094 gc_parser_flags |= GC_PARSER_JOG_MOTION; 00095 gc_block.modal.motion = MOTION_MODE_LINEAR; 00096 gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; 00097 #ifdef USE_LINE_NUMBERS 00098 gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog. 00099 #endif 00100 } 00101 00102 /* ------------------------------------------------------------------------------------- 00103 STEP 2: Import all g-code words in the block line. A g-code word is a letter followed by 00104 a number, which can either be a 'G'/'M' command or sets/assigns a command value. Also, 00105 perform initial error-checks for command word modal group violations, for any repeated 00106 words, and for negative values set for the value words F, N, P, T, and S. */ 00107 00108 uint8_t word_bit; // Bit-value for assigning tracking variables 00109 uint8_t char_counter; 00110 char letter; 00111 float value; 00112 uint8_t int_value = 0; 00113 uint16_t mantissa = 0; 00114 if (gc_parser_flags & GC_PARSER_JOG_MOTION) { char_counter = 3; } // Start parsing after `$J=` 00115 else { char_counter = 0; } 00116 00117 while (line[char_counter] != 0) { // Loop until no more g-code words in line. 00118 00119 // Import the next g-code word, expecting a letter followed by a value. Otherwise, error out. 00120 letter = line[char_counter]; 00121 if((letter < 'A') || (letter > 'Z')) { FAIL(STATUS_EXPECTED_COMMAND_LETTER); } // [Expected word letter] 00122 char_counter++; 00123 if (!read_float(line, &char_counter, &value)) { FAIL(STATUS_BAD_NUMBER_FORMAT); } // [Expected word value] 00124 00125 // Convert values to smaller uint8 significand and mantissa values for parsing this word. 00126 // NOTE: Mantissa is multiplied by 100 to catch non-integer command values. This is more 00127 // accurate than the NIST gcode requirement of x10 when used for commands, but not quite 00128 // accurate enough for value words that require integers to within 0.0001. This should be 00129 // a good enough comprimise and catch most all non-integer errors. To make it compliant, 00130 // we would simply need to change the mantissa to int16, but this add compiled flash space. 00131 // Maybe update this later. 00132 int_value = truncf(value); 00133 mantissa = (uint16_t)lroundf(100 * (value - int_value)); // Compute mantissa for Gxx.x commands. 00134 // NOTE: Rounding must be used to catch small floating point errors. 00135 00136 // Check if the g-code word is supported or errors due to modal group violations or has 00137 // been repeated in the g-code block. If ok, update the command or record its value. 00138 switch(letter) { 00139 00140 /* 'G' and 'M' Command Words: Parse commands and check for modal group violations. 00141 NOTE: Modal group numbers are defined in Table 4 of NIST RS274-NGC v3, pg.20 */ 00142 00143 case 'G': 00144 // Determine 'G' command and its modal group 00145 switch(int_value) { 00146 case 10: case 28: case 30: case 92: 00147 // Check for G10/28/30/92 being called with G0/1/2/3/38 on same block. 00148 // * G43.1 is also an axis command but is not explicitly defined this way. 00149 if (mantissa == 0) { // Ignore G28.1, G30.1, and G92.1 00150 if (axis_command) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); } // [Axis word/command conflict] 00151 axis_command = AXIS_COMMAND_NON_MODAL; 00152 } 00153 // No break. Continues to next line. 00154 case 4: case 53: 00155 word_bit = MODAL_GROUP_G0; 00156 gc_block.non_modal_command = int_value; 00157 if ((int_value == 28) || (int_value == 30) || (int_value == 92)) { 00158 if (!((mantissa == 0) || (mantissa == 10))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } 00159 gc_block.non_modal_command += mantissa; 00160 mantissa = 0; // Set to zero to indicate valid non-integer G command. 00161 } 00162 break; 00163 case 0: case 1: case 2: case 3: case 38: 00164 // Check for G0/1/2/3/38 being called with G10/28/30/92 on same block. 00165 // * G43.1 is also an axis command but is not explicitly defined this way. 00166 if (axis_command) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); } // [Axis word/command conflict] 00167 axis_command = AXIS_COMMAND_MOTION_MODE; 00168 // No break. Continues to next line. 00169 case 80: 00170 word_bit = MODAL_GROUP_G1; 00171 gc_block.modal.motion = int_value; 00172 if (int_value == 38){ 00173 if (!((mantissa == 20) || (mantissa == 30) || (mantissa == 40) || (mantissa == 50))) { 00174 FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G38.x command] 00175 } 00176 gc_block.modal.motion += (mantissa/10)+100; 00177 mantissa = 0; // Set to zero to indicate valid non-integer G command. 00178 } 00179 break; 00180 case 17: case 18: case 19: 00181 word_bit = MODAL_GROUP_G2; 00182 gc_block.modal.plane_select = int_value - 17; 00183 break; 00184 case 90: case 91: 00185 if (mantissa == 0) { 00186 word_bit = MODAL_GROUP_G3; 00187 gc_block.modal.distance = int_value - 90; 00188 } else { 00189 word_bit = MODAL_GROUP_G4; 00190 if ((mantissa != 10) || (int_value == 90)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G90.1 not supported] 00191 mantissa = 0; // Set to zero to indicate valid non-integer G command. 00192 // Otherwise, arc IJK incremental mode is default. G91.1 does nothing. 00193 } 00194 break; 00195 case 93: case 94: 00196 word_bit = MODAL_GROUP_G5; 00197 gc_block.modal.feed_rate = 94 - int_value; 00198 break; 00199 case 20: case 21: 00200 word_bit = MODAL_GROUP_G6; 00201 gc_block.modal.units = 21 - int_value; 00202 break; 00203 case 40: 00204 word_bit = MODAL_GROUP_G7; 00205 // NOTE: Not required since cutter radius compensation is always disabled. Only here 00206 // to support G40 commands that often appear in g-code program headers to setup defaults. 00207 // gc_block.modal.cutter_comp = CUTTER_COMP_DISABLE; // G40 00208 break; 00209 case 43: case 49: 00210 word_bit = MODAL_GROUP_G8; 00211 // NOTE: The NIST g-code standard vaguely states that when a tool length offset is changed, 00212 // there cannot be any axis motion or coordinate offsets updated. Meaning G43, G43.1, and G49 00213 // all are explicit axis commands, regardless if they require axis words or not. 00214 if (axis_command) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); } // [Axis word/command conflict] } 00215 axis_command = AXIS_COMMAND_TOOL_LENGTH_OFFSET; 00216 if (int_value == 49) { // G49 00217 gc_block.modal.tool_length = TOOL_LENGTH_OFFSET_CANCEL; 00218 } else if (mantissa == 10) { // G43.1 00219 gc_block.modal.tool_length = TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC; 00220 } else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [Unsupported G43.x command] 00221 mantissa = 0; // Set to zero to indicate valid non-integer G command. 00222 break; 00223 case 54: case 55: case 56: case 57: case 58: case 59: 00224 // NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.) 00225 word_bit = MODAL_GROUP_G12; 00226 gc_block.modal.coord_select = int_value - 54; // Shift to array indexing. 00227 break; 00228 case 61: 00229 word_bit = MODAL_GROUP_G13; 00230 if (mantissa != 0) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G61.1 not supported] 00231 // gc_block.modal.control = CONTROL_MODE_EXACT_PATH; // G61 00232 break; 00233 default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported G command] 00234 } 00235 if (mantissa > 0) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); } // [Unsupported or invalid Gxx.x command] 00236 // Check for more than one command per modal group violations in the current block 00237 // NOTE: Variable 'word_bit' is always assigned, if the command is valid. 00238 if ( bit_istrue(command_words,bit(word_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); } 00239 command_words |= bit(word_bit); 00240 break; 00241 00242 case 'M': 00243 00244 // Determine 'M' command and its modal group 00245 if (mantissa > 0) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); } // [No Mxx.x commands] 00246 switch(int_value) { 00247 case 0: case 1: case 2: case 30: 00248 word_bit = MODAL_GROUP_M4; 00249 switch(int_value) { 00250 case 0: gc_block.modal.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause 00251 case 1: break; // Optional stop not supported. Ignore. 00252 default: gc_block.modal.program_flow = int_value; // Program end and reset 00253 } 00254 break; 00255 case 3: case 4: case 5: 00256 word_bit = MODAL_GROUP_M7; 00257 switch(int_value) { 00258 case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break; 00259 case 4: gc_block.modal.spindle = SPINDLE_ENABLE_CCW; break; 00260 case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break; 00261 } 00262 break; 00263 #ifdef ENABLE_M7 00264 case 7: case 8: case 9: 00265 #else 00266 case 8: case 9: 00267 #endif 00268 word_bit = MODAL_GROUP_M8; 00269 switch(int_value) { 00270 #ifdef ENABLE_M7 00271 case 7: gc_block.modal.coolant = COOLANT_MIST_ENABLE; break; 00272 #endif 00273 case 8: gc_block.modal.coolant = COOLANT_FLOOD_ENABLE; break; 00274 case 9: gc_block.modal.coolant = COOLANT_DISABLE; break; 00275 } 00276 break; 00277 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL 00278 case 56: 00279 word_bit = MODAL_GROUP_M9; 00280 gc_block.modal.override = OVERRIDE_PARKING_MOTION; 00281 break; 00282 #endif 00283 default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command] 00284 } 00285 00286 // Check for more than one command per modal group violations in the current block 00287 // NOTE: Variable 'word_bit' is always assigned, if the command is valid. 00288 if ( bit_istrue(command_words,bit(word_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); } 00289 command_words |= bit(word_bit); 00290 break; 00291 00292 // NOTE: All remaining letters assign values. 00293 default: 00294 00295 /* Non-Command Words: This initial parsing phase only checks for repeats of the remaining 00296 legal g-code words and stores their value. Error-checking is performed later since some 00297 words (I,J,K,L,P,R) have multiple connotations and/or depend on the issued commands. */ 00298 switch(letter){ 00299 // case 'A': // Not supported 00300 // case 'B': // Not supported 00301 // case 'C': // Not supported 00302 // case 'D': // Not supported 00303 case 'F': word_bit = WORD_F; gc_block.values.f = value; break; 00304 // case 'H': // Not supported 00305 case 'I': word_bit = WORD_I; gc_block.values.ijk[X_AXIS] = value; ijk_words |= (1<<X_AXIS); break; 00306 case 'J': word_bit = WORD_J; gc_block.values.ijk[Y_AXIS] = value; ijk_words |= (1<<Y_AXIS); break; 00307 case 'K': word_bit = WORD_K; gc_block.values.ijk[Z_AXIS] = value; ijk_words |= (1<<Z_AXIS); break; 00308 case 'L': word_bit = WORD_L; gc_block.values.l = int_value; break; 00309 case 'N': word_bit = WORD_N; gc_block.values.n = truncf(value); break; 00310 case 'P': word_bit = WORD_P; gc_block.values.p = value; break; 00311 // NOTE: For certain commands, P value must be an integer, but none of these commands are supported. 00312 // case 'Q': // Not supported 00313 case 'R': word_bit = WORD_R; gc_block.values.r = value; break; 00314 case 'S': word_bit = WORD_S; gc_block.values.s = value; break; 00315 case 'T': word_bit = WORD_T; 00316 if (value > MAX_TOOL_NUMBER) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); } 00317 gc_block.values.t = int_value; 00318 break; 00319 case 'X': word_bit = WORD_X; gc_block.values.xyz[X_AXIS] = value; axis_words |= (1<<X_AXIS); break; 00320 case 'Y': word_bit = WORD_Y; gc_block.values.xyz[Y_AXIS] = value; axis_words |= (1<<Y_AXIS); break; 00321 case 'Z': word_bit = WORD_Z; gc_block.values.xyz[Z_AXIS] = value; axis_words |= (1<<Z_AXIS); break; 00322 default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); 00323 } 00324 00325 // NOTE: Variable 'word_bit' is always assigned, if the non-command letter is valid. 00326 if (bit_istrue(value_words,bit(word_bit))) { FAIL(STATUS_GCODE_WORD_REPEATED); } // [Word repeated] 00327 // Check for invalid negative values for words F, N, P, T, and S. 00328 // NOTE: Negative value check is done here simply for code-efficiency. 00329 if ( bit(word_bit) & (bit(WORD_F)|bit(WORD_N)|bit(WORD_P)|bit(WORD_T)|bit(WORD_S)) ) { 00330 if (value < 0.0) { FAIL(STATUS_NEGATIVE_VALUE); } // [Word value cannot be negative] 00331 } 00332 value_words |= bit(word_bit); // Flag to indicate parameter assigned. 00333 00334 } 00335 } 00336 // Parsing complete! 00337 00338 00339 /* ------------------------------------------------------------------------------------- 00340 STEP 3: Error-check all commands and values passed in this block. This step ensures all of 00341 the commands are valid for execution and follows the NIST standard as closely as possible. 00342 If an error is found, all commands and values in this block are dumped and will not update 00343 the active system g-code modes. If the block is ok, the active system g-code modes will be 00344 updated based on the commands of this block, and signal for it to be executed. 00345 00346 Also, we have to pre-convert all of the values passed based on the modes set by the parsed 00347 block. There are a number of error-checks that require target information that can only be 00348 accurately calculated if we convert these values in conjunction with the error-checking. 00349 This relegates the next execution step as only updating the system g-code modes and 00350 performing the programmed actions in order. The execution step should not require any 00351 conversion calculations and would only require minimal checks necessary to execute. 00352 */ 00353 00354 /* NOTE: At this point, the g-code block has been parsed and the block line can be freed. 00355 NOTE: It's also possible, at some future point, to break up STEP 2, to allow piece-wise 00356 parsing of the block on a per-word basis, rather than the entire block. This could remove 00357 the need for maintaining a large string variable for the entire block and free up some memory. 00358 To do this, this would simply need to retain all of the data in STEP 1, such as the new block 00359 data struct, the modal group and value bitflag tracking variables, and axis array indices 00360 compatible variables. This data contains all of the information necessary to error-check the 00361 new g-code block when the EOL character is received. However, this would break Grbl's startup 00362 lines in how it currently works and would require some refactoring to make it compatible. 00363 */ 00364 00365 // [0. Non-specific/common error-checks and miscellaneous setup]: 00366 00367 // Determine implicit axis command conditions. Axis words have been passed, but no explicit axis 00368 // command has been sent. If so, set axis command to current motion mode. 00369 if (axis_words) { 00370 if (!axis_command) { axis_command = AXIS_COMMAND_MOTION_MODE; } // Assign implicit motion-mode 00371 } 00372 00373 // Check for valid line number N value. 00374 if (bit_istrue(value_words,bit(WORD_N))) { 00375 // Line number value cannot be less than zero (done) or greater than max line number. 00376 if (gc_block.values.n > MAX_LINE_NUMBER) { FAIL(STATUS_GCODE_INVALID_LINE_NUMBER); } // [Exceeds max line number] 00377 } 00378 // bit_false(value_words,bit(WORD_N)); // NOTE: Single-meaning value word. Set at end of error-checking. 00379 00380 // Track for unused words at the end of error-checking. 00381 // NOTE: Single-meaning value words are removed all at once at the end of error-checking, because 00382 // they are always used when present. This was done to save a few bytes of flash. For clarity, the 00383 // single-meaning value words may be removed as they are used. Also, axis words are treated in the 00384 // same way. If there is an explicit/implicit axis command, XYZ words are always used and are 00385 // are removed at the end of error-checking. 00386 00387 // [1. Comments ]: MSG's NOT SUPPORTED. Comment handling performed by protocol. 00388 00389 // [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate 00390 // is not defined after switching to G94 from G93. 00391 // NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word. 00392 if (gc_parser_flags & GC_PARSER_JOG_MOTION) { 00393 if (bit_isfalse(value_words,bit(WORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } 00394 if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; } 00395 } else { 00396 if (gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93 00397 // NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here. 00398 if (axis_command == AXIS_COMMAND_MOTION_MODE) { 00399 if ((gc_block.modal.motion != MOTION_MODE_NONE) && (gc_block.modal.motion != MOTION_MODE_SEEK)) { 00400 if (bit_isfalse(value_words,bit(WORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [F word missing] 00401 } 00402 } 00403 // NOTE: It seems redundant to check for an F word to be passed after switching from G94 to G93. We would 00404 // accomplish the exact same thing if the feed rate value is always reset to zero and undefined after each 00405 // inverse time block, since the commands that use this value already perform undefined checks. This would 00406 // also allow other commands, following this switch, to execute and not error out needlessly. This code is 00407 // combined with the above feed rate mode and the below set feed rate error-checking. 00408 00409 // [3. Set feed rate ]: F is negative (done.) 00410 // - In inverse time mode: Always implicitly zero the feed rate value before and after block completion. 00411 // NOTE: If in G93 mode or switched into it from G94, just keep F value as initialized zero or passed F word 00412 // value in the block. If no F word is passed with a motion command that requires a feed rate, this will error 00413 // out in the motion modes error-checking. However, if no F word is passed with NO motion command that requires 00414 // a feed rate, we simply move on and the state feed rate value gets updated to zero and remains undefined. 00415 } else { // = G94 00416 // - In units per mm mode: If F word passed, ensure value is in mm/min, otherwise push last state value. 00417 if (gc_state.modal.feed_rate == FEED_RATE_MODE_UNITS_PER_MIN) { // Last state is also G94 00418 if (bit_istrue(value_words,bit(WORD_F))) { 00419 if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; } 00420 } else { 00421 gc_block.values.f = gc_state.feed_rate; // Push last state feed rate 00422 } 00423 } // Else, switching to G94 from G93, so don't push last state feed rate. Its undefined or the passed F word value. 00424 } 00425 } 00426 // bit_false(value_words,bit(WORD_F)); // NOTE: Single-meaning value word. Set at end of error-checking. 00427 00428 // [4. Set spindle speed ]: S is negative (done.) 00429 if (bit_isfalse(value_words,bit(WORD_S))) { gc_block.values.s = gc_state.spindle_speed; } 00430 // bit_false(value_words,bit(WORD_S)); // NOTE: Single-meaning value word. Set at end of error-checking. 00431 00432 // [5. Select tool ]: NOT SUPPORTED. Only tracks value. T is negative (done.) Not an integer. Greater than max tool value. 00433 // bit_false(value_words,bit(WORD_T)); // NOTE: Single-meaning value word. Set at end of error-checking. 00434 00435 // [6. Change tool ]: N/A 00436 // [7. Spindle control ]: N/A 00437 // [8. Coolant control ]: N/A 00438 // [9. Override control ]: Not supported except for a Grbl-only parking motion override control. 00439 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL 00440 if (bit_istrue(command_words, bit(MODAL_GROUP_M9))) { // Already set as enabled in parser. 00441 if (bit_istrue(value_words, bit(WORD_P))) { 00442 if (gc_block.values.p == 0.0f) { gc_block.modal.override = OVERRIDE_DISABLED; } 00443 bit_false(value_words, bit(WORD_P)); 00444 } 00445 } 00446 #endif 00447 00448 // [10. Dwell ]: P value missing. P is negative (done.) NOTE: See below. 00449 if (gc_block.non_modal_command == NON_MODAL_DWELL) { 00450 if (bit_isfalse(value_words,bit(WORD_P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P word missing] 00451 bit_false(value_words,bit(WORD_P)); 00452 } 00453 00454 // [11. Set active plane ]: N/A 00455 switch (gc_block.modal.plane_select) { 00456 case PLANE_SELECT_XY: 00457 axis_0 = X_AXIS; 00458 axis_1 = Y_AXIS; 00459 axis_linear = Z_AXIS; 00460 break; 00461 case PLANE_SELECT_ZX: 00462 axis_0 = Z_AXIS; 00463 axis_1 = X_AXIS; 00464 axis_linear = Y_AXIS; 00465 break; 00466 default: // case PLANE_SELECT_YZ: 00467 axis_0 = Y_AXIS; 00468 axis_1 = Z_AXIS; 00469 axis_linear = X_AXIS; 00470 } 00471 00472 // [12. Set length units ]: N/A 00473 // Pre-convert XYZ coordinate values to millimeters, if applicable. 00474 uint8_t idx; 00475 if (gc_block.modal.units == UNITS_MODE_INCHES) { 00476 for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used. 00477 if (bit_istrue(axis_words,bit(idx)) ) { 00478 gc_block.values.xyz[idx] *= MM_PER_INCH; 00479 } 00480 } 00481 } 00482 00483 // [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED. Error, if enabled while G53 is active. 00484 // [G40 Errors]: G2/3 arc is programmed after a G40. The linear move after disabling is less than tool diameter. 00485 // NOTE: Since cutter radius compensation is never enabled, these G40 errors don't apply. Grbl supports G40 00486 // only for the purpose to not error when G40 is sent with a g-code program header to setup the default modes. 00487 00488 // [14. Cutter length compensation ]: G43 NOT SUPPORTED, but G43.1 and G49 are. 00489 // [G43.1 Errors]: Motion command in same line. 00490 // NOTE: Although not explicitly stated so, G43.1 should be applied to only one valid 00491 // axis that is configured (in config.h). There should be an error if the configured axis 00492 // is absent or if any of the other axis words are present. 00493 if (axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // Indicates called in block. 00494 if (gc_block.modal.tool_length == TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC) { 00495 if (axis_words ^ (1<<TOOL_LENGTH_OFFSET_AXIS)) { FAIL(STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR); } 00496 } 00497 } 00498 00499 // [15. Coordinate system selection ]: *N/A. Error, if cutter radius comp is active. 00500 // TODO: An EEPROM read of the coordinate data may require a buffer sync when the cycle 00501 // is active. The read pauses the processor temporarily and may cause a rare crash. For 00502 // future versions on processors with enough memory, all coordinate data should be stored 00503 // in memory and written to EEPROM only when there is not a cycle active. 00504 float block_coord_system[N_AXIS]; 00505 memcpy(block_coord_system,gc_state.coord_system,sizeof(gc_state.coord_system)); 00506 if ( bit_istrue(command_words,bit(MODAL_GROUP_G12)) ) { // Check if called in block 00507 if (gc_block.modal.coord_select > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys] 00508 if (gc_state.modal.coord_select != gc_block.modal.coord_select) { 00509 if (!(settings_read_coord_data(gc_block.modal.coord_select,block_coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); } 00510 } 00511 } 00512 00513 // [16. Set path control mode ]: N/A. Only G61. G61.1 and G64 NOT SUPPORTED. 00514 // [17. Set distance mode ]: N/A. Only G91.1. G90.1 NOT SUPPORTED. 00515 // [18. Set retract mode ]: NOT SUPPORTED. 00516 00517 // [19. Remaining non-modal actions ]: Check go to predefined position, set G10, or set axis offsets. 00518 // NOTE: We need to separate the non-modal commands that are axis word-using (G10/G28/G30/G92), as these 00519 // commands all treat axis words differently. G10 as absolute offsets or computes current position as 00520 // the axis value, G92 similarly to G10 L20, and G28/30 as an intermediate target position that observes 00521 // all the current coordinate system and G92 offsets. 00522 switch (gc_block.non_modal_command) { 00523 case NON_MODAL_SET_COORDINATE_DATA: 00524 // [G10 Errors]: L missing and is not 2 or 20. P word missing. (Negative P value done.) 00525 // [G10 L2 Errors]: R word NOT SUPPORTED. P value not 0 to nCoordSys(max 9). Axis words missing. 00526 // [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing. 00527 if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS) }; // [No axis words] 00528 if (bit_isfalse(value_words,((1<<WORD_P)|(1<<WORD_L)))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P/L word missing] 00529 coord_select = truncf(gc_block.values.p); // Convert p value to int. 00530 if (coord_select > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys] 00531 if (gc_block.values.l != 20) { 00532 if (gc_block.values.l == 2) { 00533 if (bit_istrue(value_words,bit(WORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported] 00534 } else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [Unsupported L] 00535 } 00536 bit_false(value_words,(bit(WORD_L)|bit(WORD_P))); 00537 00538 // Determine coordinate system to change and try to load from EEPROM. 00539 if (coord_select > 0) { coord_select--; } // Adjust P1-P6 index to EEPROM coordinate data indexing. 00540 else { coord_select = gc_block.modal.coord_select; } // Index P0 as the active coordinate system 00541 00542 // NOTE: Store parameter data in IJK values. By rule, they are not in use with this command. 00543 if (!settings_read_coord_data(coord_select,gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); } // [EEPROM read fail] 00544 00545 // Pre-calculate the coordinate data changes. 00546 for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used. 00547 // Update axes defined only in block. Always in machine coordinates. Can change non-active system. 00548 if (bit_istrue(axis_words,bit(idx)) ) { 00549 if (gc_block.values.l == 20) { 00550 // L20: Update coordinate system axis at current position (with modifiers) with programmed value 00551 // WPos = MPos - WCS - G92 - TLO -> WCS = MPos - G92 - TLO - WPos 00552 gc_block.values.ijk[idx] = gc_state.position[idx]-gc_state.coord_offset[idx]-gc_block.values.xyz[idx]; 00553 if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.ijk[idx] -= gc_state.tool_length_offset; } 00554 } else { 00555 // L2: Update coordinate system axis to programmed value. 00556 gc_block.values.ijk[idx] = gc_block.values.xyz[idx]; 00557 } 00558 } // Else, keep current stored value. 00559 } 00560 break; 00561 case NON_MODAL_SET_COORDINATE_OFFSET: 00562 // [G92 Errors]: No axis words. 00563 if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words] 00564 00565 // Update axes defined only in block. Offsets current system to defined value. Does not update when 00566 // active coordinate system is selected, but is still active unless G92.1 disables it. 00567 for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used. 00568 if (bit_istrue(axis_words,bit(idx)) ) { 00569 // WPos = MPos - WCS - G92 - TLO -> G92 = MPos - WCS - TLO - WPos 00570 gc_block.values.xyz[idx] = gc_state.position[idx]-block_coord_system[idx]-gc_block.values.xyz[idx]; 00571 if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.xyz[idx] -= gc_state.tool_length_offset; } 00572 } else { 00573 gc_block.values.xyz[idx] = gc_state.coord_offset[idx]; 00574 } 00575 } 00576 break; 00577 00578 default: 00579 00580 // At this point, the rest of the explicit axis commands treat the axis values as the traditional 00581 // target position with the coordinate system offsets, G92 offsets, absolute override, and distance 00582 // modes applied. This includes the motion mode commands. We can now pre-compute the target position. 00583 // NOTE: Tool offsets may be appended to these conversions when/if this feature is added. 00584 if (axis_command != AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // TLO block any axis command. 00585 if (axis_words) { 00586 for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space. 00587 if ( bit_isfalse(axis_words,bit(idx)) ) { 00588 gc_block.values.xyz[idx] = gc_state.position[idx]; // No axis word in block. Keep same axis position. 00589 } else { 00590 // Update specified value according to distance mode or ignore if absolute override is active. 00591 // NOTE: G53 is never active with G28/30 since they are in the same modal group. 00592 if (gc_block.non_modal_command != NON_MODAL_ABSOLUTE_OVERRIDE) { 00593 // Apply coordinate offsets based on distance mode. 00594 if (gc_block.modal.distance == DISTANCE_MODE_ABSOLUTE) { 00595 gc_block.values.xyz[idx] += block_coord_system[idx] + gc_state.coord_offset[idx]; 00596 if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.xyz[idx] += gc_state.tool_length_offset; } 00597 } else { // Incremental mode 00598 gc_block.values.xyz[idx] += gc_state.position[idx]; 00599 } 00600 } 00601 } 00602 } 00603 } 00604 } 00605 00606 // Check remaining non-modal commands for errors. 00607 switch (gc_block.non_modal_command) { 00608 case NON_MODAL_GO_HOME_0: // G28 00609 case NON_MODAL_GO_HOME_1: // G30 00610 // [G28/30 Errors]: Cutter compensation is enabled. 00611 // Retreive G28/30 go-home position data (in machine coordinates) from EEPROM 00612 // NOTE: Store parameter data in IJK values. By rule, they are not in use with this command. 00613 if (gc_block.non_modal_command == NON_MODAL_GO_HOME_0) { 00614 if (!settings_read_coord_data(SETTING_INDEX_G28,gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); } 00615 } else { // == NON_MODAL_GO_HOME_1 00616 if (!settings_read_coord_data(SETTING_INDEX_G30,gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); } 00617 } 00618 if (axis_words) { 00619 // Move only the axes specified in secondary move. 00620 for (idx=0; idx<N_AXIS; idx++) { 00621 if (!(axis_words & (1<<idx))) { gc_block.values.ijk[idx] = gc_state.position[idx]; } 00622 } 00623 } else { 00624 axis_command = AXIS_COMMAND_NONE; // Set to none if no intermediate motion. 00625 } 00626 break; 00627 case NON_MODAL_SET_HOME_0: // G28.1 00628 case NON_MODAL_SET_HOME_1: // G30.1 00629 // [G28.1/30.1 Errors]: Cutter compensation is enabled. 00630 // NOTE: If axis words are passed here, they are interpreted as an implicit motion mode. 00631 break; 00632 case NON_MODAL_RESET_COORDINATE_OFFSET: 00633 // NOTE: If axis words are passed here, they are interpreted as an implicit motion mode. 00634 break; 00635 case NON_MODAL_ABSOLUTE_OVERRIDE: 00636 // [G53 Errors]: G0 and G1 are not active. Cutter compensation is enabled. 00637 // NOTE: All explicit axis word commands are in this modal group. So no implicit check necessary. 00638 if (!(gc_block.modal.motion == MOTION_MODE_SEEK || gc_block.modal.motion == MOTION_MODE_LINEAR)) { 00639 FAIL(STATUS_GCODE_G53_INVALID_MOTION_MODE); // [G53 G0/1 not active] 00640 } 00641 break; 00642 } 00643 } 00644 00645 // [20. Motion modes ]: 00646 if (gc_block.modal.motion == MOTION_MODE_NONE) { 00647 // [G80 Errors]: Axis word are programmed while G80 is active. 00648 // NOTE: Even non-modal commands or TLO that use axis words will throw this strict error. 00649 if (axis_words) { FAIL(STATUS_GCODE_AXIS_WORDS_EXIST); } // [No axis words allowed] 00650 00651 // Check remaining motion modes, if axis word are implicit (exist and not used by G10/28/30/92), or 00652 // was explicitly commanded in the g-code block. 00653 } else if ( axis_command == AXIS_COMMAND_MOTION_MODE ) { 00654 00655 if (gc_block.modal.motion == MOTION_MODE_SEEK) { 00656 // [G0 Errors]: Axis letter not configured or without real value (done.) 00657 // Axis words are optional. If missing, set axis command flag to ignore execution. 00658 if (!axis_words) { axis_command = AXIS_COMMAND_NONE; } 00659 00660 // All remaining motion modes (all but G0 and G80), require a valid feed rate value. In units per mm mode, 00661 // the value must be positive. In inverse time mode, a positive value must be passed with each block. 00662 } else { 00663 // Check if feed rate is defined for the motion modes that require it. 00664 if (gc_block.values.f == 0.0f) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [Feed rate undefined] 00665 00666 switch (gc_block.modal.motion) { 00667 case MOTION_MODE_LINEAR: 00668 // [G1 Errors]: Feed rate undefined. Axis letter not configured or without real value. 00669 // Axis words are optional. If missing, set axis command flag to ignore execution. 00670 if (!axis_words) { axis_command = AXIS_COMMAND_NONE; } 00671 00672 break; 00673 case MOTION_MODE_CW_ARC: 00674 gc_parser_flags |= GC_PARSER_ARC_IS_CLOCKWISE; // No break intentional. 00675 case MOTION_MODE_CCW_ARC: 00676 // [G2/3 Errors All-Modes]: Feed rate undefined. 00677 // [G2/3 Radius-Mode Errors]: No axis words in selected plane. Target point is same as current. 00678 // [G2/3 Offset-Mode Errors]: No axis words and/or offsets in selected plane. The radius to the current 00679 // point and the radius to the target point differs more than 0.002mm (EMC def. 0.5mm OR 0.005mm and 0.1% radius). 00680 // [G2/3 Full-Circle-Mode Errors]: NOT SUPPORTED. Axis words exist. No offsets programmed. P must be an integer. 00681 // NOTE: Both radius and offsets are required for arc tracing and are pre-computed with the error-checking. 00682 00683 if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words] 00684 if (!(axis_words & (bit(axis_0)|bit(axis_1)))) { FAIL(STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE); } // [No axis words in plane] 00685 00686 // Calculate the change in position along each selected axis 00687 float x,y; 00688 x = gc_block.values.xyz[axis_0]-gc_state.position[axis_0]; // Delta x between current position and target 00689 y = gc_block.values.xyz[axis_1]-gc_state.position[axis_1]; // Delta y between current position and target 00690 00691 if (value_words & bit(WORD_R)) { // Arc Radius Mode 00692 bit_false(value_words,bit(WORD_R)); 00693 if (isequal_position_vector(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target] 00694 00695 // Convert radius value to proper units. 00696 if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.r *= MM_PER_INCH; } 00697 /* We need to calculate the center of the circle that has the designated radius and passes 00698 through both the current position and the target position. This method calculates the following 00699 set of equations where [x,y] is the vector from current to target position, d == magnitude of 00700 that vector, h == hypotenuse of the triangle formed by the radius of the circle, the distance to 00701 the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the 00702 length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point 00703 [i,j] at [x/2-y/d*h, y/2+x/d*h] which will be the center of our arc. 00704 00705 d^2 == x^2 + y^2 00706 h^2 == r^2 - (d/2)^2 00707 i == x/2 - y/d*h 00708 j == y/2 + x/d*h 00709 00710 O <- [i,j] 00711 - | 00712 r - | 00713 - | 00714 - | h 00715 - | 00716 [0,0] -> C -----------------+--------------- T <- [x,y] 00717 | <------ d/2 ---->| 00718 00719 C - Current position 00720 T - Target position 00721 O - center of circle that pass through both C and T 00722 d - distance from C to T 00723 r - designated radius 00724 h - distance from center of CT to O 00725 00726 Expanding the equations: 00727 00728 d -> sqrt(x^2 + y^2) 00729 h -> sqrt(4 * r^2 - x^2 - y^2)/2 00730 i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2 00731 j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2 00732 00733 Which can be written: 00734 00735 i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2 00736 j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2 00737 00738 Which we for size and speed reasons optimize to: 00739 00740 h_x2_div_d = sqrt(4 * r^2 - x^2 - y^2)/sqrt(x^2 + y^2) 00741 i = (x - (y * h_x2_div_d))/2 00742 j = (y + (x * h_x2_div_d))/2 00743 */ 00744 00745 // First, use h_x2_div_d to compute 4*h^2 to check if it is negative or r is smaller 00746 // than d. If so, the sqrt of a negative number is complex and error out. 00747 float h_x2_div_d = 4.0f * gc_block.values.r*gc_block.values.r - x*x - y*y; 00748 00749 if (h_x2_div_d < 0) { FAIL(STATUS_GCODE_ARC_RADIUS_ERROR); } // [Arc radius error] 00750 00751 // Finish computing h_x2_div_d. 00752 h_x2_div_d = -sqrtf(h_x2_div_d)/hypot_f(x,y); // == -(h * 2 / d) 00753 // Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below) 00754 if (gc_block.modal.motion == MOTION_MODE_CCW_ARC) { h_x2_div_d = -h_x2_div_d; } 00755 00756 /* The counter clockwise circle lies to the left of the target direction. When offset is positive, 00757 the left hand circle will be generated - when it is negative the right hand circle is generated. 00758 00759 T <-- Target position 00760 00761 ^ 00762 Clockwise circles with this center | Clockwise circles with this center will have 00763 will have > 180 deg of angular travel | < 180 deg of angular travel, which is a good thing! 00764 \ | / 00765 center of arc when h_x2_div_d is positive -> x <----- | -----> x <- center of arc when h_x2_div_d is negative 00766 | 00767 | 00768 00769 C <-- Current position 00770 */ 00771 // Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!), 00772 // even though it is advised against ever generating such circles in a single line of g-code. By 00773 // inverting the sign of h_x2_div_d the center of the circles is placed on the opposite side of the line of 00774 // travel and thus we get the unadvisably long arcs as prescribed. 00775 if (gc_block.values.r < 0) { 00776 h_x2_div_d = -h_x2_div_d; 00777 gc_block.values.r = -gc_block.values.r; // Finished with r. Set to positive for mc_arc 00778 } 00779 // Complete the operation by calculating the actual center of the arc 00780 gc_block.values.ijk[axis_0] = 0.5f*(x-(y*h_x2_div_d)); 00781 gc_block.values.ijk[axis_1] = 0.5f*(y+(x*h_x2_div_d)); 00782 00783 } else { // Arc Center Format Offset Mode 00784 if (!(ijk_words & (bit(axis_0)|bit(axis_1)))) { FAIL(STATUS_GCODE_NO_OFFSETS_IN_PLANE); } // [No offsets in plane] 00785 bit_false(value_words,(bit(WORD_I)|bit(WORD_J)|bit(WORD_K))); 00786 00787 // Convert IJK values to proper units. 00788 if (gc_block.modal.units == UNITS_MODE_INCHES) { 00789 for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used to save flash space. 00790 if (ijk_words & bit(idx)) { gc_block.values.ijk[idx] *= MM_PER_INCH; } 00791 } 00792 } 00793 00794 // Arc radius from center to target 00795 x -= gc_block.values.ijk[axis_0]; // Delta x between circle center and target 00796 y -= gc_block.values.ijk[axis_1]; // Delta y between circle center and target 00797 float target_r = hypot_f(x,y); 00798 00799 // Compute arc radius for mc_arc. Defined from current location to center. 00800 gc_block.values.r = hypot_f(gc_block.values.ijk[axis_0], gc_block.values.ijk[axis_1]); 00801 00802 // Compute difference between current location and target radii for final error-checks. 00803 float delta_r = fabsf(target_r-gc_block.values.r); 00804 if (delta_r > 0.005f) { 00805 if (delta_r > 0.5f) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.5mm 00806 if (delta_r > (0.001f*gc_block.values.r)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.005mm AND 0.1% radius 00807 } 00808 } 00809 break; 00810 case MOTION_MODE_PROBE_TOWARD_NO_ERROR: case MOTION_MODE_PROBE_AWAY_NO_ERROR: 00811 gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional. 00812 case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_AWAY: 00813 if ((gc_block.modal.motion == MOTION_MODE_PROBE_AWAY) || 00814 (gc_block.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { gc_parser_flags |= GC_PARSER_PROBE_IS_AWAY; } 00815 // [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate 00816 // is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning 00817 // an error, it issues an alarm to prevent further motion to the probe. It's also done there to 00818 // allow the planner buffer to empty and move off the probe trigger before another probing cycle. 00819 if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words] 00820 if (isequal_position_vector(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target] 00821 break; 00822 } 00823 } 00824 } 00825 00826 // [21. Program flow ]: No error checks required. 00827 00828 // [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc 00829 // radius mode, or axis words that aren't used in the block. 00830 if (gc_parser_flags & GC_PARSER_JOG_MOTION) { 00831 // Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid. 00832 bit_false(value_words, (bit(WORD_N) | bit(WORD_F))); 00833 } else { 00834 bit_false(value_words, (bit(WORD_N) | bit(WORD_F) | bit(WORD_S) | bit(WORD_T))); // Remove single-meaning value words. 00835 } 00836 if (axis_command) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words. 00837 if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words] 00838 00839 /* ------------------------------------------------------------------------------------- 00840 STEP 4: EXECUTE!! 00841 Assumes that all error-checking has been completed and no failure modes exist. We just 00842 need to update the state and execute the block according to the order-of-execution. 00843 */ 00844 00845 // Initialize planner data struct for motion blocks. 00846 plan_line_data_t plan_data; 00847 plan_line_data_t *pl_data = &plan_data; 00848 memset(pl_data,0,sizeof(plan_line_data_t)); // Zero pl_data struct 00849 00850 // Intercept jog commands and complete error checking for valid jog commands and execute. 00851 // NOTE: G-code parser state is not updated, except the position to ensure sequential jog 00852 // targets are computed correctly. The final parser position after a jog is updated in 00853 // protocol_execute_realtime() when jogging completes or is canceled. 00854 if (gc_parser_flags & GC_PARSER_JOG_MOTION) { 00855 // Only distance and unit modal commands and G53 absolute override command are allowed. 00856 // NOTE: Feed rate word and axis word checks have already been performed in STEP 3. 00857 if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0)))) { FAIL(STATUS_INVALID_JOG_COMMAND) }; 00858 if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); } 00859 00860 // Initialize planner data to current spindle and coolant modal state. 00861 pl_data->spindle_speed = gc_state.spindle_speed; 00862 plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant); 00863 00864 uint8_t status = jog_execute(&plan_data, &gc_block); 00865 if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); } 00866 return(status); 00867 } 00868 00869 // If in laser mode, setup laser power based on current and past parser conditions. 00870 if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) { 00871 if (!((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC) 00872 || (gc_block.modal.motion == MOTION_MODE_CCW_ARC))) { 00873 gc_parser_flags |= GC_PARSER_LASER_DISABLE; 00874 } 00875 00876 // Any motion mode with axis words is allowed to be passed from a spindle speed update. 00877 // NOTE: G1 and G0 without axis words sets axis_command to none. G28/30 are intentionally omitted. 00878 // TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length). 00879 if (axis_words && (axis_command == AXIS_COMMAND_MOTION_MODE)) { 00880 gc_parser_flags |= GC_PARSER_LASER_ISMOTION; 00881 } 00882 else { 00883 // M3 constant power laser requires planner syncs to update the laser when changing between 00884 // a G1/2/3 motion mode state and vice versa when there is no motion in the line. 00885 if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) { 00886 if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC) 00887 || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) { 00888 if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { 00889 gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode. 00890 } 00891 } 00892 else { 00893 // When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode. 00894 if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { 00895 gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; 00896 } 00897 } 00898 } 00899 } 00900 } 00901 00902 // [0. Non-specific/common error-checks and miscellaneous setup]: 00903 // NOTE: If no line number is present, the value is zero. 00904 gc_state.line_number = gc_block.values.n; 00905 #ifdef USE_LINE_NUMBERS 00906 pl_data->line_number = gc_state.line_number; // Record data for planner use. 00907 #endif 00908 00909 // [1. Comments feedback ]: NOT SUPPORTED 00910 00911 // [2. Set feed rate mode ]: 00912 gc_state.modal.feed_rate = gc_block.modal.feed_rate; 00913 if (gc_state.modal.feed_rate) { pl_data->condition |= PL_COND_FLAG_INVERSE_TIME; } // Set condition flag for planner use. 00914 00915 // [3. Set feed rate ]: 00916 gc_state.feed_rate = gc_block.values.f; // Always copy this value. See feed rate error-checking. 00917 pl_data->feed_rate = gc_state.feed_rate; // Record data for planner use. 00918 00919 // [4. Set spindle speed ]: 00920 if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags, GC_PARSER_LASER_FORCE_SYNC)) { 00921 if (gc_state.modal.spindle != SPINDLE_DISABLE) { 00922 #ifdef VARIABLE_SPINDLE 00923 if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_ISMOTION)) { 00924 if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { 00925 spindle_sync(gc_state.modal.spindle, 0.0); 00926 } 00927 else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); } 00928 } 00929 #else 00930 spindle_sync(gc_state.modal.spindle, 0.0); 00931 #endif 00932 } 00933 gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state. 00934 } 00935 // NOTE: Pass zero spindle speed for all restricted laser motions. 00936 if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) { 00937 pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use. 00938 } // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already. 00939 00940 // [5. Select tool ]: NOT SUPPORTED. Only tracks tool value. 00941 gc_state.tool = gc_block.values.t; 00942 00943 // [6. Change tool ]: NOT SUPPORTED 00944 00945 // [7. Spindle control ]: 00946 if (gc_state.modal.spindle != gc_block.modal.spindle) { 00947 // Update spindle control and apply spindle speed when enabling it in this block. 00948 // NOTE: All spindle state changes are synced, even in laser mode. Also, pl_data, 00949 // rather than gc_state, is used to manage laser state for non-laser motions. 00950 spindle_sync(gc_block.modal.spindle, pl_data->spindle_speed); 00951 gc_state.modal.spindle = gc_block.modal.spindle; 00952 } 00953 pl_data->condition |= gc_state.modal.spindle; // Set condition flag for planner use. 00954 00955 // [8. Coolant control ]: 00956 if (gc_state.modal.coolant != gc_block.modal.coolant) { 00957 // NOTE: Coolant M-codes are modal. Only one command per line is allowed. But, multiple states 00958 // can exist at the same time, while coolant disable clears all states. 00959 coolant_sync(gc_block.modal.coolant); 00960 if (gc_block.modal.coolant == COOLANT_DISABLE) { gc_state.modal.coolant = COOLANT_DISABLE; } 00961 else { gc_state.modal.coolant |= gc_block.modal.coolant; } 00962 } 00963 pl_data->condition |= gc_state.modal.coolant; // Set condition flag for planner use. 00964 00965 // [9. Override control ]: NOT SUPPORTED. Always enabled. Except for a Grbl-only parking control. 00966 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL 00967 if (gc_state.modal.override != gc_block.modal.override) { 00968 gc_state.modal.override = gc_block.modal.override; 00969 mc_override_ctrl_update(gc_state.modal.override); 00970 } 00971 #endif 00972 00973 // [10. Dwell ]: 00974 if (gc_block.non_modal_command == NON_MODAL_DWELL) { mc_dwell(gc_block.values.p); } 00975 00976 // [11. Set active plane ]: 00977 gc_state.modal.plane_select = gc_block.modal.plane_select; 00978 00979 // [12. Set length units ]: 00980 gc_state.modal.units = gc_block.modal.units; 00981 00982 // [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED 00983 // gc_state.modal.cutter_comp = gc_block.modal.cutter_comp; // NOTE: Not needed since always disabled. 00984 00985 // [14. Cutter length compensation ]: G43.1 and G49 supported. G43 NOT SUPPORTED. 00986 // NOTE: If G43 were supported, its operation wouldn't be any different from G43.1 in terms 00987 // of execution. The error-checking step would simply load the offset value into the correct 00988 // axis of the block XYZ value array. 00989 if (axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // Indicates a change. 00990 gc_state.modal.tool_length = gc_block.modal.tool_length; 00991 if (gc_state.modal.tool_length == TOOL_LENGTH_OFFSET_CANCEL) { // G49 00992 gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] = 0.0f; 00993 } // else G43.1 00994 if ( gc_state.tool_length_offset != gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] ) { 00995 gc_state.tool_length_offset = gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS]; 00996 system_flag_wco_change(); 00997 } 00998 } 00999 01000 // [15. Coordinate system selection ]: 01001 if (gc_state.modal.coord_select != gc_block.modal.coord_select) { 01002 gc_state.modal.coord_select = gc_block.modal.coord_select; 01003 memcpy(gc_state.coord_system,block_coord_system,N_AXIS*sizeof(float)); 01004 system_flag_wco_change(); 01005 } 01006 01007 // [16. Set path control mode ]: G61.1/G64 NOT SUPPORTED 01008 // gc_state.modal.control = gc_block.modal.control; // NOTE: Always default. 01009 01010 // [17. Set distance mode ]: 01011 gc_state.modal.distance = gc_block.modal.distance; 01012 01013 // [18. Set retract mode ]: NOT SUPPORTED 01014 01015 // [19. Go to predefined position, Set G10, or Set axis offsets ]: 01016 switch(gc_block.non_modal_command) { 01017 case NON_MODAL_SET_COORDINATE_DATA: 01018 settings_write_coord_data(coord_select,gc_block.values.ijk); 01019 // Update system coordinate system if currently active. 01020 if (gc_state.modal.coord_select == coord_select) { 01021 memcpy(gc_state.coord_system,gc_block.values.ijk,N_AXIS*sizeof(float)); 01022 system_flag_wco_change(); 01023 } 01024 break; 01025 case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1: 01026 // Move to intermediate position before going home. Obeys current coordinate system and offsets 01027 // and absolute and incremental modes. 01028 pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag. 01029 if (axis_command) { mc_line(gc_block.values.xyz, pl_data); } 01030 mc_line(gc_block.values.ijk, pl_data); 01031 memcpy(gc_state.position, gc_block.values.ijk, N_AXIS*sizeof(float)); 01032 break; 01033 case NON_MODAL_SET_HOME_0: 01034 settings_write_coord_data(SETTING_INDEX_G28,gc_state.position); 01035 break; 01036 case NON_MODAL_SET_HOME_1: 01037 settings_write_coord_data(SETTING_INDEX_G30,gc_state.position); 01038 break; 01039 case NON_MODAL_SET_COORDINATE_OFFSET: 01040 memcpy(gc_state.coord_offset,gc_block.values.xyz,sizeof(gc_block.values.xyz)); 01041 system_flag_wco_change(); 01042 break; 01043 case NON_MODAL_RESET_COORDINATE_OFFSET: 01044 clear_vector(gc_state.coord_offset); // Disable G92 offsets by zeroing offset vector. 01045 system_flag_wco_change(); 01046 break; 01047 } 01048 01049 01050 // [20. Motion modes ]: 01051 // NOTE: Commands G10,G28,G30,G92 lock out and prevent axis words from use in motion modes. 01052 // Enter motion modes only if there are axis words or a motion mode command word in the block. 01053 gc_state.modal.motion = gc_block.modal.motion; 01054 if (gc_state.modal.motion != MOTION_MODE_NONE) { 01055 if (axis_command == AXIS_COMMAND_MOTION_MODE) { 01056 uint8_t gc_update_pos = GC_UPDATE_POS_TARGET; 01057 if (gc_state.modal.motion == MOTION_MODE_LINEAR) { 01058 mc_line(gc_block.values.xyz, pl_data); 01059 } else if (gc_state.modal.motion == MOTION_MODE_SEEK) { 01060 pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag. 01061 mc_line(gc_block.values.xyz, pl_data); 01062 } else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) { 01063 mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r, 01064 axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags, GC_PARSER_ARC_IS_CLOCKWISE)); 01065 } else { 01066 // NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So 01067 // upon a successful probing cycle, the machine position and the returned value should be the same. 01068 #ifndef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES 01069 pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE; 01070 #endif 01071 gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, gc_parser_flags); 01072 } 01073 01074 // As far as the parser is concerned, the position is now == target. In reality the 01075 // motion control system might still be processing the action and the real tool position 01076 // in any intermediate location. 01077 if (gc_update_pos == GC_UPDATE_POS_TARGET) { 01078 memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc_state.position[] = gc_block.values.xyz[] 01079 } else if (gc_update_pos == GC_UPDATE_POS_SYSTEM) { 01080 gc_sync_position(); // gc_state.position[] = sys_position 01081 } // == GC_UPDATE_POS_NONE 01082 } 01083 01084 } 01085 01086 // [21. Program flow ]: 01087 // M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may 01088 // refill and can only be resumed by the cycle start run-time command. 01089 gc_state.modal.program_flow = gc_block.modal.program_flow; 01090 if (gc_state.modal.program_flow) { 01091 protocol_buffer_synchronize(); // Sync and finish all remaining buffered motions before moving on. 01092 if (gc_state.modal.program_flow == PROGRAM_FLOW_PAUSED) { 01093 if (sys.state != STATE_CHECK_MODE) { 01094 system_set_exec_state_flag(EXEC_FEED_HOLD); // Use feed hold for program pause. 01095 protocol_execute_realtime(); // Execute suspend. 01096 } 01097 } else { // == PROGRAM_FLOW_COMPLETED 01098 // Upon program complete, only a subset of g-codes reset to certain defaults, according to 01099 // LinuxCNC's program end descriptions and testing. Only modal groups [G-code 1,2,3,5,7,12] 01100 // and [M-code 7,8,9] reset to [G1,G17,G90,G94,G40,G54,M5,M9,M48]. The remaining modal groups 01101 // [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. 01102 gc_state.modal.motion = MOTION_MODE_LINEAR; 01103 gc_state.modal.plane_select = PLANE_SELECT_XY; 01104 gc_state.modal.distance = DISTANCE_MODE_ABSOLUTE; 01105 gc_state.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN; 01106 // gc_state.modal.cutter_comp = CUTTER_COMP_DISABLE; // Not supported. 01107 gc_state.modal.coord_select = 0; // G54 01108 gc_state.modal.spindle = SPINDLE_DISABLE; 01109 gc_state.modal.coolant = COOLANT_DISABLE; 01110 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL 01111 #ifdef DEACTIVATE_PARKING_UPON_INIT 01112 gc_state.modal.override = OVERRIDE_DISABLED; 01113 #else 01114 gc_state.modal.override = OVERRIDE_PARKING_MOTION; 01115 #endif 01116 #endif 01117 01118 #ifdef RESTORE_OVERRIDES_AFTER_PROGRAM_END 01119 sys.f_override = DEFAULT_FEED_OVERRIDE; 01120 sys.r_override = DEFAULT_RAPID_OVERRIDE; 01121 sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; 01122 #endif 01123 01124 // Execute coordinate change and spindle/coolant stop. 01125 if (sys.state != STATE_CHECK_MODE) { 01126 if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); } 01127 system_flag_wco_change(); // Set to refresh immediately just in case something altered. 01128 spindle_set_state(SPINDLE_DISABLE,0.0f); 01129 coolant_set_state(COOLANT_DISABLE); 01130 } 01131 report_feedback_message(MESSAGE_PROGRAM_END); 01132 } 01133 gc_state.modal.program_flow = PROGRAM_FLOW_RUNNING; // Reset program flow. 01134 } 01135 01136 // TODO: % to denote start of program. 01137 01138 return(STATUS_OK); 01139 } 01140 01141 01142 /* 01143 Not supported: 01144 01145 - Canned cycles 01146 - Tool radius compensation 01147 - A,B,C-axes 01148 - Evaluation of expressions 01149 - Variables 01150 - Override control (TBD) 01151 - Tool changes 01152 - Switches 01153 01154 (*) Indicates optional parameter, enabled through config.h and re-compile 01155 group 0 = {G92.2, G92.3} (Non modal: Cancel and re-enable G92 offsets) 01156 group 1 = {G81 - G89} (Motion modes: Canned cycles) 01157 group 4 = {M1} (Optional stop, ignored) 01158 group 6 = {M6} (Tool change) 01159 group 7 = {G41, G42} cutter radius compensation (G40 is supported) 01160 group 8 = {G43} tool length offset (G43.1/G49 are supported) 01161 group 8 = {M7*} enable mist coolant (* Compile-option) 01162 group 9 = {M48, M49, M56*} enable/disable override switches (* Compile-option) 01163 group 10 = {G98, G99} return mode canned cycles 01164 group 13 = {G61.1, G64} path control mode (G61 is supported) 01165 */
Generated on Tue Jul 12 2022 20:45:31 by
1.7.2