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 {