G-code parser G0/G1 bug fix.

- Although stated as invalid in the NIST g-code standard, most g-code
parsers, including linuxcnc, allow G0 and G1 to be commanded without
axis words present. For example, something like ‘G1 F100.0’ to preset
the motion mode and feed rate without a motion commanded. Older CNC
controllers actually required this for feed rate settings. This update
should now allow this type of behavior.
This commit is contained in:
Sonny Jeon 2014-07-03 18:13:39 -06:00
parent 1ef5a45479
commit 92d6c2bca5

70
gcode.c
View File

@ -92,7 +92,7 @@ uint8_t gc_execute_line(char *line)
memset(&gc_block, 0, sizeof(gc_block)); // Initialize the parser block struct.
memcpy(&gc_block.modal,&gc_state.modal,sizeof(gc_modal_t)); // Copy current modes
uint8_t axis_explicit = AXIS_COMMAND_NONE;
uint8_t axis_command = AXIS_COMMAND_NONE;
uint8_t axis_0, axis_1, axis_linear;
float coordinate_data[N_AXIS]; // Multi-use variable to store coordinate data for execution
float parameter_data[N_AXIS]; // Multi-use variable to store parameter data for execution
@ -149,8 +149,8 @@ uint8_t gc_execute_line(char *line)
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.
if (mantissa == 0) { // Ignore G28.1, G30.1, and G92.1
if (axis_explicit) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); } // [Axis word/command conflict]
axis_explicit = AXIS_COMMAND_NON_MODAL;
if (axis_command) { 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:
@ -187,8 +187,8 @@ uint8_t gc_execute_line(char *line)
break;
case 0: case 1: case 2: case 3: case 38:
// Check for G0/1/2/3/38 being called with G10/28/30/92 on same block.
if (axis_explicit) { FAIL(STATUS_GCODE_AXIS_COMMAND_CONFLICT); } // [Axis word/command conflict]
axis_explicit = AXIS_COMMAND_MOTION_MODE;
if (axis_command) { 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;
@ -363,21 +363,10 @@ uint8_t gc_execute_line(char *line)
// [0. Non-specific/common error-checks and miscellaneous setup]:
// Determine how axis words are used and error-check it. Apply implicit conditions and exceptions.
if (axis_explicit) { // Either a non-modal or motion mode axis-explicit command has been passed.
// Axis-words are required (with exceptions) with axis-explicit commands.
// NOTE: G28/30 reserve any axis words as an intermediate motion, but are not required. G2/3 full
// circle arcs don't require axis words, but this aren't supported.
if (!axis_words) {
if ((gc_block.non_modal_command == NON_MODAL_GO_HOME_0) || (gc_block.non_modal_command == NON_MODAL_GO_HOME_1)) {
axis_explicit = AXIS_COMMAND_NONE; // No axis words passed for G28/30.
} else {
FAIL(STATUS_GCODE_NO_AXIS_WORDS); // [No axis words]
}
}
} else {
// If no axis-explicit commands in the block, axis words implicitly activate the current motion mode.
if (axis_words) { axis_explicit = AXIS_COMMAND_MOTION_MODE; } // Assign implicit motion-mode
// 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
}
// Check for valid line number N value.
@ -391,7 +380,7 @@ uint8_t gc_execute_line(char *line)
// 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
// single-meaning value words may be removed as they are used. Also, axis words are treated in the
// same way. If there is an axis explicit/implicit command, XYZ words are always used and are
// same way. If there is an explicit/implicit axis command, XYZ words are always used and are
// are removed at the end of error-checking.
// [1. Comments ]: MSG's NOT SUPPORTED. Comment handling performed by protocol.
@ -400,7 +389,7 @@ uint8_t gc_execute_line(char *line)
// is not defined after switching to G94 from G93.
if (gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
if (axis_explicit == AXIS_COMMAND_MOTION_MODE) {
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))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [F word missing]
}
@ -497,15 +486,16 @@ uint8_t gc_execute_line(char *line)
// [18. Set retract mode ]: NOT SUPPORTED.
// [19. Remaining non-modal actions ]: Check go to predefined position, set G10, or set axis offsets.
// NOTE: We need to separate the non-modal commands that are axis-explicit (G10/G28/G30/G92), as these
// NOTE: We need to separate the non-modal commands that are axis word-using (G10/G28/G30/G92), as these
// commands all treat axis words differently. G10 as absolute offsets or computes current position as
// 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:
// [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 (done.)
// [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing (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,((1<<WORD_P)|(1<<WORD_L)))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P/L word missing]
int_value = trunc(gc_block.values.p); // Convert p value to int.
if (int_value > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
@ -533,7 +523,8 @@ uint8_t gc_execute_line(char *line)
}
break;
case NON_MODAL_SET_COORDINATE_OFFSET:
// [G92 Errors]: No axis words (done.)
// [G92 Errors]: No axis words.
if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
// Update axes defined only in block. Offsets current system to defined value. Does not update when
// active coordinate system is selected, but is still active unless G92.1 disables it.
@ -548,7 +539,7 @@ uint8_t gc_execute_line(char *line)
default:
// At this point, the rest of the axis-explicit commands treat the axis values as the traditional
// At this point, the rest of the explicit axis commands treat the axis values as the traditional
// 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.
@ -603,26 +594,31 @@ uint8_t gc_execute_line(char *line)
// [20. Motion modes ]:
if (gc_block.modal.motion == MOTION_MODE_NONE) {
// [G80 Errors]: Axis word exist and are not used by a non-modal command.
if ((axis_words) && (axis_explicit != AXIS_COMMAND_NON_MODAL)) {
if ((axis_words) && (axis_command != AXIS_COMMAND_NON_MODAL)) {
FAIL(STATUS_GCODE_AXIS_WORDS_EXIST); // [No axis words allowed]
}
// 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_explicit == AXIS_COMMAND_MOTION_MODE ) {
} else if ( axis_command == AXIS_COMMAND_MOTION_MODE ) {
// [G0 Errors]: (All done!) No axis words. Axis letter not configured or without real value.
if (gc_block.modal.motion == MOTION_MODE_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; }
// 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.
if (gc_block.modal.motion != MOTION_MODE_SEEK) {
} else {
// Check if feed rate is defined for the motion modes that require it.
if (gc_block.values.f == 0.0) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [Feed rate undefined]
switch (gc_block.modal.motion) {
case MOTION_MODE_LINEAR:
// [G1 Errors]: (All done!) No axis words and feed rate undefined. Axis letter not configured or without real value.
// [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; }
break;
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
// [G2/3 Errors All-Modes]: Feed rate undefined.
@ -632,6 +628,7 @@ uint8_t gc_execute_line(char *line)
// [G2/3 Full-Circle-Mode Errors]: NOT SUPPORTED. Axis words exist. No offsets programmed. P must be an integer.
// NOTE: Both radius and offsets are required for arc tracing and are pre-computed with the error-checking.
if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
if (!(axis_words & (bit(axis_0)|bit(axis_1)))) { FAIL(STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE); } // [No axis words in plane]
// Calculate the change in position along each selected axis
@ -760,6 +757,7 @@ uint8_t gc_execute_line(char *line)
case MOTION_MODE_PROBE:
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
// is undefined. Probe is triggered.
if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
if (gc_check_same_position(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target]
if (probe_get_state()) { FAIL(STATUS_GCODE_PROBE_TRIGGERED); } // [Probe triggered]
break;
@ -772,7 +770,7 @@ uint8_t gc_execute_line(char *line)
// [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.
bit_false(value_words,(bit(WORD_N)|bit(WORD_F)|bit(WORD_S)|bit(WORD_T))); // Remove single-meaning value words.
if (axis_explicit) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words.
if (axis_command) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words.
if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words]
@ -859,7 +857,7 @@ uint8_t gc_execute_line(char *line)
case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
// Move to intermediate position before going home. Obeys current coordinate system and offsets
// and absolute and incremental modes.
if (axis_explicit) {
if (axis_command) {
#ifdef USE_LINE_NUMBERS
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n);
#else
@ -893,7 +891,7 @@ uint8_t gc_execute_line(char *line)
// 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_explicit == AXIS_COMMAND_MOTION_MODE) {
if (axis_command == AXIS_COMMAND_MOTION_MODE) {
switch (gc_state.modal.motion) {
case MOTION_MODE_SEEK:
#ifdef USE_LINE_NUMBERS