diff --git a/README.md b/README.md index 719aab7..203282c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20241014, see the [changelog](changelog.md) for details. +Latest build date is 20241016, see the [changelog](changelog.md) for details. __NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured. The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds. diff --git a/changelog.md b/changelog.md index 7d13fcc..dfdb7a6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,19 @@ ## grblHAL changelog +Build 20241016 + +Core: + +* Improved parameter handling some more, now allows indirected O-calls and line numbers with O-word. + +* Fix for [issue #609](https://github.com/grblHAL/core/issues/609), homing may cause a controller crash. + +Plugins: + +* Spindle: Fixed compiler warning. Ref. [issue #33](https://github.com/grblHAL/Plugins_spindle/issues/33) + +--- + Build 20241014 Core: diff --git a/gcode.c b/gcode.c index b2d0332..93f5aa1 100644 --- a/gcode.c +++ b/gcode.c @@ -992,45 +992,60 @@ status_code_t gc_execute_block (char *block) if(block[char_counter] == '<') { - char *s = &block[++char_counter]; - - while(*s && *s != '>') - s++; - - if(*s && *(s + 1) == '=') { - char *name = &block[char_counter]; - *s++ = '\0'; - s++; - char_counter += s - name; - if((status = ngc_read_real_value(block, &char_counter, &value)) != Status_OK) - FAIL(status); // [Expected parameter value] - if(!ngc_named_param_set(name, value)) - FAIL(Status_BadNumberFormat); // [Expected equal sign] - } + char name[NGC_MAX_PARAM_LENGTH + 1]; + if((status = ngc_read_name(block, &char_counter, name)) == Status_OK) { + if(block[char_counter++] != '=') + status = Status_BadNumberFormat; // [Expected equal sign] + else if((status = ngc_read_real_value(block, &char_counter, &value)) == Status_OK) { + if(!ngc_named_param_set(name, value)) + status = Status_BadNumberFormat; // [Out of memory or attempt to write RO parameter] + } // else: [Expected value] + } // else: [Expected parameter name] } else { float param; - if((status = ngc_read_real_value(block, &char_counter, ¶m)) != Status_OK) { - FAIL(status); // [Expected parameter number] - } else if(!ngc_param_is_rw((ngc_param_id_t)param)) - FAIL(Status_GcodeValueOutOfRange); // [Parameter does not exist or is read only] - - if(block[char_counter++] != '=') - FAIL(Status_BadNumberFormat); // [Expected equal sign] - - if((status = ngc_read_real_value(block, &char_counter, &value)) != Status_OK) - FAIL(status); // [Expected parameter value] - - if(ngc_param_count < NGC_N_ASSIGN_PARAMETERS_PER_BLOCK && ngc_param_is_rw((ngc_param_id_t)param)) { - ngc_params[ngc_param_count].id = (ngc_param_id_t)param; - ngc_params[ngc_param_count++].value = value; - } else - FAIL(Status_BadNumberFormat); // [Expected parameter value] + if((status = ngc_read_real_value(block, &char_counter, ¶m)) == Status_OK) { + if(!ngc_param_is_rw((ngc_param_id_t)param)) + status = Status_GcodeValueOutOfRange; // [Parameter does not exist or is read only] + else if(block[char_counter++] != '=') + status = Status_BadNumberFormat; // [Expected equal sign] + else if((status = ngc_read_real_value(block, &char_counter, &value)) == Status_OK) { + if(ngc_param_count < NGC_N_ASSIGN_PARAMETERS_PER_BLOCK) { + ngc_params[ngc_param_count].id = (ngc_param_id_t)param; + ngc_params[ngc_param_count++].value = value; + } else + FAIL(Status_BadNumberFormat); // [Too many parameters in block] + } // else: [Expected parameter value] + } // else: [Expected parameter number] } + if(status != Status_OK) + FAIL(status); + continue; + } else if(letter == 'O') { + + gc_block.words.n = Off; // Hack to allow line number with O word + + if(block[char_counter] == '[') { + int32_t value; + if((status = ngc_read_integer_value(block, &char_counter, &value)) == Status_OK) { + gc_block.words.o = On; + gc_block.values.o = (uint32_t)value; + char_counter++; + } else + FAIL(status); + } else if(block[char_counter] == '<') { + /* char o_label[NGC_MAX_PARAM_LENGTH + 1]; + if((status = ngc_read_name(block, &char_counter, o_label)) != Status_OK) + FAIL(status); + gc_block.words.o = On; + gc_block.values.o = 0xFFFFFFFE; + continue;*/ + FAIL(Status_GcodeUnsupportedCommand); // [For now...] + } } if((gc_block.words.mask & o_label.mask) && (gc_block.words.mask & ~o_label.mask) == 0) { diff --git a/grbl.h b/grbl.h index d49bfce..f812d92 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20241014 +#define GRBL_BUILD 20241016 #define GRBL_URL "https://github.com/grblHAL" diff --git a/machine_limits.c b/machine_limits.c index 4231d59..1f2c76b 100644 --- a/machine_limits.c +++ b/machine_limits.c @@ -193,7 +193,6 @@ static bool limits_pull_off (axes_signals_t axis, float distance) plan_data.feed_rate = settings.homing.seek_rate * sqrtf(n_axis); // Adjust so individual axes all move at pull-off rate. plan_data.condition.coolant = gc_state.modal.coolant; - memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t)); #ifdef KINEMATICS_API coord_data_t k_target; @@ -275,13 +274,12 @@ static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_square) plan_line_data_t plan_data; rt_exec_t rt_exec, rt_exec_states = EXEC_SAFETY_DOOR|EXEC_RESET|EXEC_CYCLE_COMPLETE; + // Initialize plan data struct for homing motion. + plan_data_init(&plan_data); plan_data.condition.system_motion = On; plan_data.condition.no_feed_override = On; plan_data.line_number = DEFAULT_HOMING_CYCLE_LINE_NUMBER; - - // Initialize plan data struct for homing motion. - memcpy(&plan_data.spindle, &gc_state.spindle, sizeof(spindle_t)); plan_data.condition.coolant = gc_state.modal.coolant; uint_fast8_t idx = N_AXIS; diff --git a/ngc_expr.c b/ngc_expr.c index 8e132bb..6122ab9 100644 --- a/ngc_expr.c +++ b/ngc_expr.c @@ -571,6 +571,39 @@ static status_code_t read_operation_unary (char *line, uint_fast8_t *pos, ngc_un return status; } +/*! \brief Reads the name of a parameter out of the line +starting at the index given by the pos offset. + +\param line pointer to RS274/NGC code (block). +\param pos offset into line where expression starts. +\param buffer pointer to a character buffer for the name. +\returns #Status_OK enum value if processed without error, appropriate \ref status_code_t enum value if not. +*/ +status_code_t ngc_read_name (char *line, uint_fast8_t *pos, char *buffer) +{ + char *s; + uint_fast8_t len = 0; + status_code_t status = Status_BadNumberFormat; + + if(*(s = line + (*pos)++) == '<') { + + s++; + + while(*s && *s != '>' && len <= NGC_MAX_PARAM_LENGTH) { + *buffer++ = *s++; + (*pos)++; + len++; + } + + if((status = *s == '>' ? Status_OK : Status_FlowControlSyntaxError) == Status_OK) { + *buffer = '\0'; + (*pos)++; + } + } + + return status; +} + /*! \brief Reads the value out of a parameter of the line, starting at the index given by the pos offset. @@ -593,6 +626,7 @@ sequentially, the value of #2 would be 10 after the line was executed. */ status_code_t ngc_read_parameter (char *line, uint_fast8_t *pos, float *value, bool check) { + int32_t param; status_code_t status = Status_BadNumberFormat; if(*(line + *pos) == '#') { @@ -601,34 +635,18 @@ status_code_t ngc_read_parameter (char *line, uint_fast8_t *pos, float *value, b if(*(line + *pos) == '<') { - (*pos)++; - char *param = line + *pos, *arg = line + *pos; + char name[NGC_MAX_PARAM_LENGTH + 1]; - while(*arg && *arg != '>') - arg++; - - *pos += arg - param + 1; - - if(*arg == '>') { - *arg = '\0'; - if(ngc_named_param_get(param, value)) - status = Status_OK; - *arg = '>'; + if((status = ngc_read_name(line, pos, name)) == Status_OK) { + if(!ngc_named_param_get(name, value)) + status = Status_BadNumberFormat; } + } else if((status = ngc_read_integer_value(line, pos, ¶m)) == Status_OK) { - } else if((status = ngc_read_real_value(line, pos, value)) == Status_OK) { - - uint32_t param = (uint32_t)floorf(*value); - - if((*value - (float)param) > 0.9999f) { - param = (uint32_t)ceilf(*value); - } else if((*value - (float)param) > 0.0001f) - status = Status_BadNumberFormat; // not integer - - if(check && !ngc_param_exists((ngc_param_id_t)param)) + if(param < 0 || (check && !ngc_param_exists((ngc_param_id_t)param))) + status = Status_GcodeValueOutOfRange; + else if(!ngc_param_get((ngc_param_id_t)param, value)) status = Status_GcodeValueOutOfRange; - else if(ngc_param_get((ngc_param_id_t)param, value)) - status = Status_OK; } } @@ -761,6 +779,52 @@ status_code_t ngc_read_real_value (char *line, uint_fast8_t *pos, float *value) return status; } +/*! \brief Reads explicit unsigned (positive) integer out of the line, +starting at the index given by the pos offset. It expects to find one +or more digits. Any character other than a digit terminates reading +the integer. Note that if the first character is a sign (+ or -), +an error will be reported (since a sign is not a digit). + +\param line pointer to RS274/NGC code (block). +\param pos offset into line where expression starts. +\param value pointer to integer where result is to be stored. +\returns #Status_OK enum value if processed without error, appropriate \ref status_code_t enum value if not. +*/ +status_code_t ngc_read_integer_unsigned (char *line, uint_fast8_t *pos, uint32_t *value) +{ + return line[*pos] == '+' ? Status_GcodeCommandValueNotInteger : read_uint(line, pos, value); +} + +/*! \brief Reads an integer (positive, negative or zero) out of the line, +starting at the index given by the pos offset. The value being +read may be written with a decimal point or it may be an expression +involving non-integers, as long as the result comes out within 0.0001 +of an integer. + +This proceeds by calling read_real_value and checking that it is +close to an integer, then returning the integer it is close to. + +\param line pointer to RS274/NGC code (block). +\param pos offset into line where expression starts. +\param value pointer to integer where result is to be stored. +\returns #Status_OK enum value if processed without error, appropriate \ref status_code_t enum value if not. +*/ +status_code_t ngc_read_integer_value (char *line, uint_fast8_t *pos, int32_t *value) +{ + float fvalue; + status_code_t status; + + if((status = ngc_read_real_value(line, pos, &fvalue)) == Status_OK) { + *value = (int32_t)floorf(fvalue); + if((fvalue - (float)*value) > 0.9999f) { + *value = (uint32_t)ceilf(fvalue); + } else if((fvalue - (float)*value) > 0.0001f) + status = Status_GcodeCommandValueNotInteger; // not integer + } + + return status; +} + /*! \brief Evaluate expression and set result if successful. \param line pointer to RS274/NGC code (block). diff --git a/ngc_expr.h b/ngc_expr.h index df8154a..a1e1f77 100644 --- a/ngc_expr.h +++ b/ngc_expr.h @@ -3,8 +3,11 @@ #ifndef _NGC_EXPR_H_ #define _NGC_EXPR_H_ -status_code_t ngc_eval_expression (char *line, uint_fast8_t *pos, float *value); +status_code_t ngc_read_name (char *line, uint_fast8_t *pos, char *buffer); status_code_t ngc_read_real_value (char *line, uint_fast8_t *pos, float *value); +status_code_t ngc_read_integer_value(char *line, uint_fast8_t *pos, int32_t *value); +status_code_t ngc_read_integer_unsigned (char *line, uint_fast8_t *pos, uint32_t *value); status_code_t ngc_read_parameter (char *line, uint_fast8_t *pos, float *value, bool check); +status_code_t ngc_eval_expression (char *line, uint_fast8_t *pos, float *value); #endif diff --git a/ngc_params.c b/ngc_params.c index baa0c87..f5b9697 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -41,9 +41,6 @@ #ifndef NGC_MAX_CALL_LEVEL #define NGC_MAX_CALL_LEVEL 10 #endif -#ifndef NGC_MAX_PARAM_LENGTH -#define NGC_MAX_PARAM_LENGTH 20 -#endif typedef float (*ngc_param_get_ptr)(ngc_param_id_t id); typedef float (*ngc_named_param_get_ptr)(void); @@ -622,7 +619,7 @@ static char *ngc_name_tolower (char *s) uint_fast8_t len = 0; char c, *s1 = s, *s2 = name; - while((c = *s1++) && len < NGC_MAX_PARAM_LENGTH) { + while((c = *s1++) && len <= NGC_MAX_PARAM_LENGTH) { if(c > ' ') { *s2++ = LCAPS(c); len++; @@ -679,7 +676,7 @@ bool ngc_named_param_exists (char *name) } while(idx && !ok); // If not predefined attempt to find it. - if(!ok && rw_global_params && strlen(name) < NGC_MAX_PARAM_LENGTH) { + if(!ok && rw_global_params && strlen(name) <= NGC_MAX_PARAM_LENGTH) { void *context = *name == '_' ? NULL : call_context; ngc_named_rw_param_t *rw_param = rw_global_params; @@ -712,7 +709,7 @@ bool ngc_named_param_set (char *name, float value) } while(idx && !ok); // If not predefined attempt to set it. - if(!ok && (ok = strlen(name) < NGC_MAX_PARAM_LENGTH)) { + if(!ok && (ok = strlen(name) <= NGC_MAX_PARAM_LENGTH)) { void *context = *name == '_' ? NULL : call_context; ngc_named_rw_param_t *rw_param = rw_global_params, *rw_param_last = rw_global_params; diff --git a/ngc_params.h b/ngc_params.h index 977eff8..4f672c7 100644 --- a/ngc_params.h +++ b/ngc_params.h @@ -30,6 +30,10 @@ #include "gcode.h" +#ifndef NGC_MAX_PARAM_LENGTH +#define NGC_MAX_PARAM_LENGTH 20 +#endif + typedef uint16_t ngc_param_id_t; typedef struct {