From 9a98243fd3a182e578c594fea522457a7d453470 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 27 Oct 2024 07:27:25 +0700 Subject: [PATCH] Changed _vminor named parameter to contain build date in YYMMDD format, previously value was 0. Added support for LinuxCNC style (ABORT,) comment, requires expressions enabled. Terminates gcode program, outputs message and returns error 253. Added PRM[] and PRM[,] functions to expressions, returns $-setting value or value of bit in integer type setting. "hardened" flow control code, fixed bug in repeat...continue handling. Changed signature of grbl.on_gcode_comment event, now returns status code. --- README.md | 2 +- changelog.md | 33 +++++++++++++++++++++++++++++--- core_handlers.h | 2 +- errors.c | 13 +++++++------ errors.h | 18 ++++++++--------- gcode.c | 25 ++++++++++++------------ gcode.h | 2 +- grbl.h | 2 +- messages.h | 1 + ngc_expr.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- ngc_flowctrl.c | 33 +++++++++++++++++++++++++++++--- ngc_params.c | 2 +- nvs_buffer.c | 21 ++++++++++++++------ report.c | 4 ++++ system.c | 12 +++++++----- 15 files changed, 171 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 99c77e3..e1f79c2 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 20241023, see the [changelog](changelog.md) for details. +Latest build date is 20241025, 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 82354cd..4b1d6e9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,22 +1,49 @@ ## grblHAL changelog +Build 20241025 + +Core: + +* Changed `_vminor` named parameter to return build date in YYMMDD format, previously value was 0. + +* Added support for LinuxCNC style `(ABORT,)` comment, requires expressions enabled. +Terminates gcode program, outputs message and returns error 253. + +* Added `PRM[]` and `PRM[,]` functions to expressions, returns $-setting value or value of bit in integer type setting. + +* "hardened" flow control code, fixed bug in `repeat...continue` handling. + +* Changed signature of `grbl.on_gcode_comment` event, now returns status code. + +Drivers: + +* STM32F4xx: fixed typos. + +* Some: added note to _platformio.ino_ file. + +Plugins: + +* SD Card, macros: fixed G65P1 settings read macro when reading some indexed settings. + +--- + Build 20241023 Core: * Fixed some odd bugs in NGC flow control, prepared for file based named O-call subroutines. -* Fixed incorrect comment string passed to passed to `grbl.on_gcode_comment` event. +* Fixed incorrect comment string passed to `grbl.on_gcode_comment` event. * Added generic redirector for temporarily changing input stream to read from a file. Supports nesting. Drivers: -*ESP32: fix for overriding UART0 pins, reverted and fixed tests for ESP32-S3 conditional code. +* ESP32: fix for overriding UART0 pins, reverted and fixed tests for ESP32-S3 conditional code. Plugins: -* File system macros: updated to use new input stream redirector, allows nesting of `G65` calls +* SD Card, macros: updated to use new input stream redirector, allows nesting of `G65` calls \(max 5 levels depending on available memory\). __NOTE:__ Not extensively tested, feedback required. * SD card: updated to work alongside new file redirector. diff --git a/core_handlers.h b/core_handlers.h index 4238145..e4e138b 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -118,7 +118,7 @@ typedef void (*on_reset_ptr)(void); typedef void (*on_jog_cancel_ptr)(sys_state_t state); typedef bool (*on_spindle_select_ptr)(spindle_ptrs_t *spindle); typedef void (*on_spindle_selected_ptr)(spindle_ptrs_t *spindle); -typedef void (*on_gcode_message_ptr)(char *msg); +typedef status_code_t (*on_gcode_message_ptr)(char *msg); typedef void (*on_rt_reports_added_ptr)(report_tracking_flags_t report); typedef const char *(*on_set_axis_setting_unit_ptr)(setting_id_t setting_id, uint_fast8_t axis_idx); typedef status_code_t (*on_file_open_ptr)(const char *fname, vfs_file_t *handle, bool stream); diff --git a/errors.c b/errors.c index 4e9ab08..56a3335 100644 --- a/errors.c +++ b/errors.c @@ -3,22 +3,22 @@ Part of grblHAL - Copyright (c) 2017-2023 Terje Io + Copyright (c) 2017-2024 Terje Io Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2009-2011 Simen Svale Skogsrud - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ #include @@ -102,8 +102,9 @@ PROGMEM static const status_detail_t status_detail[] = { { Status_FlowControlNotExecutingMacro, "Flow statement only allowed in filesystem macro." }, { Status_FlowControlSyntaxError, "Unknown flow statement." }, { Status_FlowControlStackOverflow, "Stack overflow while executing flow statement." }, - { Status_FlowControlOutOfMemory, "Out of memory while executing flow statement." } + { Status_FlowControlOutOfMemory, "Out of memory while executing flow statement." }, #endif + { Status_UserException, "User defined error occured." } #endif // NO_SETTINGS_DESCRIPTIONS }; diff --git a/errors.h b/errors.h index 79299bb..78aba0c 100644 --- a/errors.h +++ b/errors.h @@ -3,22 +3,22 @@ Part of grblHAL - Copyright (c) 2017-2023 Terje Io + Copyright (c) 2017-2024 Terje Io Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC Copyright (c) 2009-2011 Simen Svale Skogsrud - Grbl is free software: you can redistribute it and/or modify + grblHAL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Grbl is distributed in the hope that it will be useful, + grblHAL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Grbl. If not, see . + along with grblHAL. If not, see . */ #ifndef _ERRORS_H_ @@ -26,7 +26,7 @@ #include -// Define Grbl status codes. Valid values (0-255) +// Define grblHAL status codes. Valid values (0-255) typedef enum { Status_OK = 0, Status_ExpectedCommandLetter = 1, @@ -112,10 +112,10 @@ typedef enum { Status_FlowControlSyntaxError = 81, Status_FlowControlStackOverflow = 82, Status_FlowControlOutOfMemory = 83, - + Status_StatusMax = Status_FlowControlOutOfMemory, + Status_UserException = 253, Status_Handled, // For internal use only - Status_Unhandled, // For internal use only - Status_StatusMax = Status_Unhandled + Status_Unhandled // For internal use only } __attribute__ ((__packed__)) status_code_t; typedef struct { diff --git a/gcode.c b/gcode.c index 9b29cfd..5936e92 100644 --- a/gcode.c +++ b/gcode.c @@ -557,7 +557,7 @@ bool gc_modal_state_restore (gc_modal_t *copy) // If the driver handles message comments then the first is extracted and returned in a dynamically // allocated memory block, the caller must free this after the message has been processed. -char *gc_normalize_block (char *block, char **message) +char *gc_normalize_block (char *block, status_code_t *status, char **message) { char c, *s1, *s2, *comment = NULL; @@ -608,12 +608,8 @@ char *gc_normalize_block (char *block, char **message) comment += 6; ngc_substitute_parameters(comment, message); *comment = '\0'; // Do not generate grbl.on_gcode_comment event! - } else if(!strncasecmp(comment, "MSG,", 4)) { - comment += 4; - ngc_substitute_parameters(comment, message); - } - } -#else + } else { +#endif size_t len = s1 - comment - 3; if(!strncasecmp(comment, "MSG,", 4) && (*message = malloc(len))) { @@ -625,12 +621,13 @@ char *gc_normalize_block (char *block, char **message) } memcpy(*message, comment, len); } - } +#if NGC_EXPRESSIONS_ENABLE + } #endif + } } - if(*comment && *message == NULL && grbl.on_gcode_comment) - grbl.on_gcode_comment(comment); + *status = grbl.on_gcode_comment(comment); } comment = NULL; break; @@ -773,6 +770,7 @@ status_code_t gc_execute_block (char *block) #endif char *message = NULL; + status_code_t status = Status_OK; struct { float f; uint32_t o; @@ -780,12 +778,15 @@ status_code_t gc_execute_block (char *block) tool_id_t t; } single_meaning_value = {0}; - block = gc_normalize_block(block, &message); + block = gc_normalize_block(block, &status, &message); + + if(status != Status_OK) + FAIL(status); if(block[0] == '\0') { if(message) gc_output_message(message); - return Status_OK; + return status; } // Determine if the line is a program start/end marker. diff --git a/gcode.h b/gcode.h index ec551ba..3564dc5 100644 --- a/gcode.h +++ b/gcode.h @@ -655,7 +655,7 @@ typedef struct { // Initialize the parser void gc_init (void); -char *gc_normalize_block (char *block, char **message); +char *gc_normalize_block (char *block, status_code_t *status, char **message); // Execute one block of rs275/ngc/g-code status_code_t gc_execute_block (char *block); diff --git a/grbl.h b/grbl.h index ae69882..7453bae 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20241023 +#define GRBL_BUILD 20241025 #define GRBL_URL "https://github.com/grblHAL" diff --git a/messages.h b/messages.h index 3983fed..353579d 100644 --- a/messages.h +++ b/messages.h @@ -54,6 +54,7 @@ typedef enum { Message_Plain = 0, Message_Info, Message_Warning, + Message_Error, Message_Debug } message_type_t; diff --git a/ngc_expr.c b/ngc_expr.c index 16ce699..2202a4f 100644 --- a/ngc_expr.c +++ b/ngc_expr.c @@ -28,6 +28,7 @@ #include #include "errors.h" +#include "settings.h" #include "ngc_expr.h" #include "ngc_params.h" @@ -70,7 +71,8 @@ typedef enum { NGCUnaryOp_SIN, NGCUnaryOp_SQRT, NGCUnaryOp_TAN, - NGCUnaryOp_Exists + NGCUnaryOp_Exists, + NGCUnaryOp_Parameter // read setting/setting bit } ngc_unary_op_t; /*! \brief Executes the operations: /, MOD, ** (POW), *. @@ -564,6 +566,14 @@ static status_code_t read_operation_unary (char *line, uint_fast8_t *pos, ngc_un status = Status_ExpressionUknownOp; break; + case 'P': + if(!strncmp(line + *pos, "RM", 2)) { + *operation = NGCUnaryOp_Parameter; + *pos += 2; + } else + status = Status_ExpressionUknownOp; + break; + default: status = Status_ExpressionUknownOp; } @@ -722,6 +732,45 @@ static status_code_t read_unary (char *line, uint_fast8_t *pos, float *value) } else status = Status_ExpressionSyntaxError; + } else if(operation == NGCUnaryOp_Parameter) { + + // get setting value or bit in value + + bool get_bit; + int32_t setting_id, bitnum; + const setting_detail_t *setting; + + (*pos)++; + if((status = ngc_read_integer_value(line, pos, &setting_id)) == Status_OK) { + + if((get_bit = line[*pos] == ',')) { + (*pos)++; + if((status = ngc_read_integer_value(line, pos, &bitnum)) != Status_OK) + return status; + if(bitnum < 0 || bitnum > 31) + return Status_ExpressionArgumentOutOfRange; + } + + if(line[*pos] != ']') + return Status_ExpressionSyntaxError; // Left bracket missing after slash with ATAN; + + (*pos)++; + + if((setting = setting_get_details((setting_id_t)setting_id, NULL))) { + + uint_fast8_t offset = setting_id - setting->id; + + if(setting->datatype == Format_Decimal) + *value = setting_get_float_value(setting, offset); + else if(setting_is_integer(setting) || setting_is_list(setting)) { + *value = (float)setting_get_int_value(setting, offset); + if(get_bit) + *value = (((uint32_t)*value >> bitnum) & 0x1) ? 1.0f : 0.0f; + } else + status = Status_ExpressionArgumentOutOfRange; + } else + status = Status_ExpressionArgumentOutOfRange; + } } else if((status = ngc_eval_expression(line, pos, value)) == Status_OK) { if(operation == NGCUnaryOp_ATAN) status = read_atan(line, pos, value); diff --git a/ngc_flowctrl.c b/ngc_flowctrl.c index eba578c..749b8a7 100644 --- a/ngc_flowctrl.c +++ b/ngc_flowctrl.c @@ -84,6 +84,7 @@ static volatile int_fast8_t stack_idx = -1; static bool skip_sub = false; static ngc_sub_t *subs = NULL, *exec_sub = NULL; static ngc_stack_entry_t stack[NGC_STACK_DEPTH] = {0}; +static on_gcode_message_ptr on_gcode_comment; static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *operation) { @@ -294,8 +295,34 @@ void ngc_flowctrl_unwind_stack (vfs_file_t *file) stack_pull(); } +static status_code_t onGcodeComment (char *comment) +{ + uint_fast8_t pos = 6; + status_code_t status = Status_OK; + + if(!strncasecmp(comment, "ABORT,", 6)) { + char *buf = NULL; + if(ngc_substitute_parameters(comment + pos, &buf)) { + report_message(buf, Message_Error); + free(buf); + } + status = Status_UserException; + } else if(on_gcode_comment) + status = on_gcode_comment(comment); + + return status; +} + void ngc_flowctrl_init (void) { + static bool init_ok = false; + + if(!init_ok) { + init_ok = true; + on_gcode_comment = grbl.on_gcode_comment; + grbl.on_gcode_comment = onGcodeComment; + } + clear_subs(NULL); while(stack_idx >= 0) stack_pull(); @@ -523,7 +550,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(stack[stack_idx].repeats && --stack[stack_idx].repeats) vfs_seek(stack[stack_idx].file, stack[stack_idx].file_pos); else - stack_pull(); + stack[stack_idx].skip = true; break; case NGCFlowCtrl_Do: @@ -606,7 +633,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo if(!skipping) { - ngc_sub_t *sub = subs; + ngc_sub_t *sub; if(o_label > NGC_MAX_PARAM_ID) { #if 0 @@ -631,7 +658,7 @@ status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, boo status = Status_FlowControlOutOfMemory; // file not found... } #endif - } else do { + } else if((sub = subs)) do { if(sub->o_label == o_label && sub->file == hal.stream.file) break; } while((sub = sub->next)); diff --git a/ngc_params.c b/ngc_params.c index f5b9697..1ce1527 100644 --- a/ngc_params.c +++ b/ngc_params.c @@ -414,7 +414,7 @@ float ngc_named_param_get_by_id (ncg_name_param_id_t id) break; case NGCParam_vminor: - value = 0.0f; // TODO: derive from version letter? + value = (float)(GRBL_BUILD - 20000000); break; case NGCParam_line: diff --git a/nvs_buffer.c b/nvs_buffer.c index 45e0436..e0c10e7 100644 --- a/nvs_buffer.c +++ b/nvs_buffer.c @@ -39,7 +39,7 @@ static uint8_t *nvsbuffer = NULL; static nvs_io_t physical_nvs; static bool dirty; - +uint32_t nvs_size_max = NVS_SIZE; settings_dirty_t settings_dirty; typedef struct { @@ -54,7 +54,6 @@ typedef struct { #define NVS_GROUP_STARTUP 3 #define NVS_GROUP_BUILD 4 - #define PARAMETER_ADDR(n) (NVS_ADDR_PARAMETERS + n * (sizeof(coord_data_t) + NVS_CRC_BYTES)) #define STARTLINE_ADDR(n) (NVS_ADDR_STARTUP_BLOCK + n * (sizeof(stored_line_t) + NVS_CRC_BYTES)) #if N_TOOLS @@ -215,10 +214,20 @@ static nvs_transfer_result_t memcpy_from_ram (uint8_t *destination, uint32_t sou // Try to allocate RAM from heap for buffer/emulation. bool nvs_buffer_alloc (void) { - assert(NVS_SIZE >= GRBL_NVS_SIZE); + static uint32_t nvs_size = NVS_SIZE; - if((nvsbuffer = malloc(NVS_SIZE))) - memset(nvsbuffer, 0xFF, NVS_SIZE); + if(hal.nvs.size_max > nvs_size) { + nvs_size_max = min(4096, hal.nvs.size_max); // Limit to 4K for now + if(nvsbuffer) + free(nvsbuffer); + } + + assert(nvs_size_max >= GRBL_NVS_SIZE); + + if((nvsbuffer = malloc(nvs_size_max))) { + nvs_size = nvs_size_max; + memset(nvsbuffer, 0xFF, nvs_size_max); + } return nvsbuffer != NULL; } @@ -294,7 +303,7 @@ nvs_address_t nvs_alloc (size_t size) } size += NVS_CRC_BYTES; // add room for checksum. - if(hal.nvs.driver_area.size + size < (NVS_SIZE - GRBL_NVS_SIZE)) { + if(hal.nvs.driver_area.size + size < (nvs_size_max - GRBL_NVS_SIZE)) { mem_address = (uint8_t *)((uint32_t)(mem_address - 1) | 0x03) + 1; // Align to word boundary addr = mem_address - nvsbuffer; mem_address += size; diff --git a/report.c b/report.c index 3f615a4..d105292 100644 --- a/report.c +++ b/report.c @@ -270,6 +270,10 @@ void report_message (const char *msg, message_type_t type) hal.stream.write("Warning: "); break; + case Message_Error: + hal.stream.write("Error: "); + break; + case Message_Debug: hal.stream.write("Debug: "); break; diff --git a/system.c b/system.c index aa28eab..c8366b3 100644 --- a/system.c +++ b/system.c @@ -683,12 +683,14 @@ static status_code_t set_startup_line (sys_state_t state, char *args, uint_fast8 status_code_t retval = Status_OK; - args = gc_normalize_block(args, NULL); + args = gc_normalize_block(args, &retval, NULL); - if(strlen(args) >= (sizeof(stored_line_t) - 1)) - retval = Status_Overflow; - else if ((retval = gc_execute_block(args)) == Status_OK) // Execute gcode block to ensure block is valid. - settings_write_startup_line(lnr, args); + if(retval == Status_OK) { + if(strlen(args) >= (sizeof(stored_line_t) - 1)) + retval = Status_Overflow; + else if ((retval = gc_execute_block(args)) == Status_OK) // Execute gcode block to ensure block is valid. + settings_write_startup_line(lnr, args); + } return retval; }