mirror of
https://github.com/grblHAL/core.git
synced 2026-08-20 22:11:38 +08:00
Added experimental support for program flow control, mainly available for use in G65 macros stored on SD card or in littlefs.
This commit is contained in:
@@ -26,6 +26,7 @@ target_sources(grbl INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/errors.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ngc_params.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ngc_expr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ngc_flowctrl.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/regex.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ioports.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/vfs.c
|
||||
|
||||
@@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
|
||||
|
||||
---
|
||||
|
||||
Latest build date is 20230519, see the [changelog](changelog.md) for details.
|
||||
Latest build date is 20230529, see the [changelog](changelog.md) for details.
|
||||
__NOTE:__ A settings reset will be performed on an update of builds earlier than 20230125. Backup and restore of settings is recommended.
|
||||
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in build 20211121.
|
||||
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
## grblHAL changelog
|
||||
|
||||
<a name="20230529"/>Build 20230529
|
||||
|
||||
Core:
|
||||
|
||||
* Added experimental support for [program flow control](https://github.com/grblHAL/core/discussions/309), mainly available for use in [G65 macros](https://github.com/grblHAL/core/wiki/Additional-G--and-M-codes#codes-available-if-driver-or-plugins-supports-them) stored on SD card or in littlefs.
|
||||
|
||||
Drivers:
|
||||
|
||||
* STM32F4xx: fix for [issue # 116](https://github.com/grblHAL/STM32F4xx/issues/116#issuecomment-1565369604), incorrect spindle RPM reported from encoder.
|
||||
|
||||
--
|
||||
|
||||
<a name="20230526"/>Build 20230526
|
||||
|
||||
Core:
|
||||
|
||||
@@ -93,7 +93,13 @@ PROGMEM static const status_detail_t status_detail[] = {
|
||||
#endif
|
||||
{ Status_AuthenticationRequired, "Authentication required." },
|
||||
{ Status_AccessDenied, "Access denied." },
|
||||
{ Status_NotAllowedCriticalEvent, "Not allowed while critical event is active." }
|
||||
{ Status_NotAllowedCriticalEvent, "Not allowed while critical event is active." },
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
{ 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." }
|
||||
#endif
|
||||
};
|
||||
|
||||
static error_details_t details = {
|
||||
|
||||
@@ -107,6 +107,11 @@ typedef enum {
|
||||
Status_AccessDenied = 78,
|
||||
Status_NotAllowedCriticalEvent = 79,
|
||||
|
||||
Status_FlowControlNotExecutingMacro = 80,
|
||||
Status_FlowControlSyntaxError = 81,
|
||||
Status_FlowControlStackOverflow = 82,
|
||||
Status_FlowControlOutOfMemory = 83,
|
||||
|
||||
Status_Unhandled, // For internal use only
|
||||
Status_StatusMax = Status_Unhandled
|
||||
} __attribute__ ((__packed__)) status_code_t;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
#include "ngc_expr.h"
|
||||
#include "ngc_params.h"
|
||||
#include "ngc_flowctrl.h"
|
||||
#endif
|
||||
|
||||
// NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an
|
||||
@@ -458,7 +459,7 @@ char *gc_normalize_block (char *block, char **message)
|
||||
break;
|
||||
|
||||
case ')':
|
||||
if(comment) {
|
||||
if(comment && !gc_state.skip_blocks) {
|
||||
*s1 = '\0';
|
||||
if(!hal.driver_cap.no_gcode_message_handling) {
|
||||
size_t len = s1 - comment - 4;
|
||||
@@ -543,6 +544,8 @@ static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, flo
|
||||
|
||||
#endif
|
||||
|
||||
extern status_code_t ngc_parse_command (uint32_t o_label, char *line, uint_fast8_t *pos, bool *skip);
|
||||
|
||||
// Parses and executes one block (line) of 0-terminated G-Code.
|
||||
// In this function, all units and positions are converted and exported to internal functions
|
||||
// in terms of (mm, mm/min) and absolute machine coordinates, respectively.
|
||||
@@ -600,6 +603,10 @@ status_code_t gc_execute_block (char *block)
|
||||
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
|
||||
static const parameter_words_t o_label = {
|
||||
.o = On
|
||||
};
|
||||
|
||||
uint_fast8_t ngc_param_count = 0;
|
||||
|
||||
// NOTE: this array has to match the parameter_words_t order!
|
||||
@@ -776,12 +783,20 @@ status_code_t gc_execute_block (char *block)
|
||||
continue;
|
||||
}
|
||||
|
||||
if((gc_block.words.mask & o_label.mask) && (gc_block.words.mask & ~o_label.mask) == 0) {
|
||||
char_counter--;
|
||||
return ngc_flowctrl(gc_block.values.o, block, &char_counter, &gc_state.skip_blocks);
|
||||
}
|
||||
|
||||
if((letter < 'A' && letter != '$') || letter > 'Z')
|
||||
FAIL(Status_ExpectedCommandLetter); // [Expected word letter]
|
||||
|
||||
if((status = read_parameter(block, &char_counter, &value)) != Status_OK)
|
||||
return status;
|
||||
|
||||
if(gc_state.skip_blocks && letter != 'O')
|
||||
return Status_OK;
|
||||
|
||||
if(!is_user_mcode && isnanf(value))
|
||||
FAIL(Status_BadNumberFormat); // [Expected word value]
|
||||
|
||||
@@ -3118,6 +3133,10 @@ status_code_t gc_execute_block (char *block)
|
||||
|
||||
case NonModal_MacroCall:
|
||||
{
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
ngc_named_param_set("_value", 0.0f);
|
||||
ngc_named_param_set("_value_returned", 0.0f);
|
||||
#endif
|
||||
status_code_t status = grbl.on_macro_execute((macro_id_t)gc_block.values.p);
|
||||
|
||||
return status == Status_Unhandled ? Status_GcodeValueOutOfRange : status;
|
||||
|
||||
@@ -530,6 +530,7 @@ typedef struct {
|
||||
bool is_laser_ppi_mode;
|
||||
bool is_rpm_rate_adjusted;
|
||||
bool tool_change;
|
||||
bool skip_blocks; //!< true if skipping conditional blocks
|
||||
status_code_t last_error; //!< last return value from parser
|
||||
//!< The following variables are not cleared upon warm restart when COMPATIBILITY_LEVEL <= 1
|
||||
bool g92_coord_offset_applied; //!< true when G92 offset applied
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20230526
|
||||
#define GRBL_BUILD 20230529
|
||||
|
||||
#define GRBL_URL "https://github.com/grblHAL"
|
||||
|
||||
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
ngc_flowctrl.c - An embedded CNC Controller with rs274/ngc (g-code) support
|
||||
|
||||
Program flow control, for filesystem macros
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
|
||||
Grbl 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "ngc_expr.h"
|
||||
#include "ngc_params.h"
|
||||
|
||||
typedef enum {
|
||||
NGCFlowCtrl_NoOp = 0,
|
||||
NGCFlowCtrl_If,
|
||||
NGCFlowCtrl_ElseIf,
|
||||
NGCFlowCtrl_Else,
|
||||
NGCFlowCtrl_EndIf,
|
||||
NGCFlowCtrl_Do,
|
||||
NGCFlowCtrl_Continue,
|
||||
NGCFlowCtrl_Break,
|
||||
NGCFlowCtrl_While,
|
||||
NGCFlowCtrl_EndWhile,
|
||||
NGCFlowCtrl_Repeat,
|
||||
NGCFlowCtrl_EndRepeat,
|
||||
NGCFlowCtrl_Return,
|
||||
NGCFlowCtrl_RaiseAlarm,
|
||||
NGCFlowCtrl_RaiseError
|
||||
} ngc_cmd_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t o_label;
|
||||
ngc_cmd_t operation;
|
||||
vfs_file_t *file;
|
||||
size_t file_pos;
|
||||
char *expr;
|
||||
uint32_t repeats;
|
||||
bool skip;
|
||||
bool handled;
|
||||
} ngc_cmd_stack_t;
|
||||
|
||||
static ngc_cmd_stack_t stack[10] = {0};
|
||||
static int_fast8_t stack_index = -1;
|
||||
|
||||
static status_code_t read_command (char *line, uint_fast8_t *pos, ngc_cmd_t *operation)
|
||||
{
|
||||
char c = line[*pos];
|
||||
status_code_t status = Status_OK;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
switch(c) {
|
||||
|
||||
case 'A':
|
||||
if (!strncmp(line + *pos, "LARM", 4)) {
|
||||
*operation = NGCFlowCtrl_RaiseAlarm;
|
||||
*pos += 4;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with G
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
if (!strncmp(line + *pos, "REAK", 4)) {
|
||||
*operation = NGCFlowCtrl_Break;
|
||||
*pos += 4;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with G
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (!strncmp(line + *pos, "ONTINUE", 7)) {
|
||||
*operation = NGCFlowCtrl_Continue;
|
||||
*pos += 7;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with G
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (line[*pos] == 'O') {
|
||||
*operation = NGCFlowCtrl_Do;
|
||||
(*pos)++;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with R
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
if (!strncmp(line + *pos, "LSEIF", 5)) {
|
||||
*operation = NGCFlowCtrl_ElseIf;
|
||||
*pos += 5;
|
||||
} else if (!strncmp(line + *pos, "LSE", 3)) {
|
||||
*operation = NGCFlowCtrl_Else;
|
||||
*pos += 3;
|
||||
} else if (!strncmp(line + *pos, "NDIF", 4)) {
|
||||
*operation = NGCFlowCtrl_EndIf;
|
||||
*pos += 4;
|
||||
} else if (!strncmp(line + *pos, "NDWHILE", 7)) {
|
||||
*operation = NGCFlowCtrl_EndWhile;
|
||||
*pos += 7;
|
||||
} else if (!strncmp(line + *pos, "NDREPEAT", 8)) {
|
||||
*operation = NGCFlowCtrl_EndRepeat;
|
||||
*pos += 8;
|
||||
} else if (!strncmp(line + *pos, "RROR", 4)) {
|
||||
*operation = NGCFlowCtrl_RaiseError;
|
||||
*pos += 4;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with G
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
if(line[*pos] == 'F') {
|
||||
*operation = NGCFlowCtrl_If;
|
||||
(*pos)++;
|
||||
} else
|
||||
*operation = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (!strncmp(line + *pos, "EPEAT", 5)) {
|
||||
*operation = NGCFlowCtrl_Repeat;
|
||||
*pos += 5;
|
||||
} else if (!strncmp(line + *pos, "ETURN", 5)) {
|
||||
*operation = NGCFlowCtrl_Return;
|
||||
*pos += 5;
|
||||
} else
|
||||
*operation = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
if (!strncmp(line + *pos, "HILE", 4)) {
|
||||
*operation = NGCFlowCtrl_While;
|
||||
*pos += 4;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name starting with G
|
||||
break;
|
||||
|
||||
default:
|
||||
status = Status_FlowControlSyntaxError; // Unknown operation name
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ngc_flowctrl_init (void)
|
||||
{
|
||||
if(stack_index >= 0) do {
|
||||
if(stack[stack_index].expr)
|
||||
free(stack[stack_index].expr);
|
||||
} while(--stack_index != -1);
|
||||
|
||||
memset(stack, 0, sizeof(stack));
|
||||
}
|
||||
|
||||
status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, bool *skip)
|
||||
{
|
||||
float value;
|
||||
bool skipping;
|
||||
ngc_cmd_t operation, last_op;
|
||||
|
||||
status_code_t status;
|
||||
|
||||
if((status = read_command(line, pos, &operation)) != Status_OK)
|
||||
return status;
|
||||
|
||||
skipping = stack_index >= 0 && stack[stack_index].skip;
|
||||
last_op = stack_index >= 0 ? stack[stack_index].operation : NGCFlowCtrl_NoOp;
|
||||
|
||||
switch(operation) {
|
||||
|
||||
case NGCFlowCtrl_If:
|
||||
if(!skipping && (status = ngc_eval_expression(line, pos, &value)) == Status_OK) {
|
||||
stack[++stack_index].o_label = o_label;
|
||||
stack[stack_index].operation = operation;
|
||||
stack[stack_index].o_label = o_label;
|
||||
stack[stack_index].file = sys.macro_file;
|
||||
stack[stack_index].skip = value == 0.0f;
|
||||
stack[stack_index].handled = !stack[stack_index].skip;
|
||||
}
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_ElseIf:
|
||||
if(last_op == NGCFlowCtrl_If || last_op == NGCFlowCtrl_ElseIf) {
|
||||
if(o_label == stack[stack_index].o_label &&
|
||||
!(stack[stack_index].skip = stack[stack_index].handled) && !stack[stack_index].handled &&
|
||||
(status = ngc_eval_expression(line, pos, &value)) == Status_OK) {
|
||||
if(!(stack[stack_index].skip = value == 0.0f)) {
|
||||
stack[stack_index].operation = operation;
|
||||
stack[stack_index].handled = true;
|
||||
}
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Else:
|
||||
if(last_op == NGCFlowCtrl_If || last_op == NGCFlowCtrl_ElseIf) {
|
||||
if(o_label == stack[stack_index].o_label) {
|
||||
if(!(stack[stack_index].skip = stack[stack_index].handled))
|
||||
stack[stack_index].operation = operation;
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_EndIf:
|
||||
if(last_op == NGCFlowCtrl_If || last_op == NGCFlowCtrl_ElseIf || last_op == NGCFlowCtrl_Else) {
|
||||
if(o_label == stack[stack_index].o_label)
|
||||
stack_index--;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Do:
|
||||
if(sys.macro_file) {
|
||||
if(!skipping) {
|
||||
stack[++stack_index].operation = operation;
|
||||
stack[stack_index].o_label = o_label;
|
||||
stack[stack_index].file = sys.macro_file;
|
||||
stack[stack_index].file_pos = vfs_tell(sys.macro_file);
|
||||
stack[stack_index].skip = false;
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_While:
|
||||
if(sys.macro_file) {
|
||||
char *expr = line + *pos;
|
||||
if(!skipping && (status = ngc_eval_expression(line, pos, &value)) == Status_OK) {
|
||||
if(last_op == NGCFlowCtrl_Do) {
|
||||
if(o_label == stack[stack_index].o_label) {
|
||||
if(value != 0.0f)
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
else
|
||||
stack_index--;
|
||||
}
|
||||
} else {
|
||||
stack[++stack_index].operation = operation;
|
||||
stack[stack_index].o_label = o_label;
|
||||
if(!(stack[stack_index].skip = value == 0.0f)) {
|
||||
if((stack[stack_index].expr = malloc(strlen(expr) + 1))) {
|
||||
strcpy(stack[stack_index].expr, expr);
|
||||
stack[stack_index].file = sys.macro_file;
|
||||
stack[stack_index].file_pos = vfs_tell(sys.macro_file);
|
||||
} else
|
||||
status = Status_FlowControlOutOfMemory;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_EndWhile:
|
||||
if(sys.macro_file) {
|
||||
if(last_op == NGCFlowCtrl_While) {
|
||||
if(o_label == stack[stack_index].o_label) {
|
||||
uint_fast8_t pos = 0;
|
||||
if(!stack[stack_index].skip && (status = ngc_eval_expression(stack[stack_index].expr, &pos, &value)) == Status_OK) {
|
||||
if(!(stack[stack_index].skip = value == 0))
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
}
|
||||
if(stack[stack_index].skip) {
|
||||
if(stack[stack_index].expr) {
|
||||
free(stack[stack_index].expr);
|
||||
stack[stack_index].expr = NULL;
|
||||
}
|
||||
stack_index--;
|
||||
}
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Repeat:
|
||||
if(sys.macro_file) {
|
||||
if(!skipping && (status = ngc_eval_expression(line, pos, &value)) == Status_OK) {
|
||||
stack[++stack_index].operation = operation;
|
||||
stack[stack_index].o_label = o_label;
|
||||
if(!(stack[stack_index].skip = value == 0.0f)) {
|
||||
stack[stack_index].file = sys.macro_file;
|
||||
stack[stack_index].file_pos = vfs_tell(sys.macro_file);
|
||||
stack[stack_index].repeats = (uint32_t)value;
|
||||
}
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_EndRepeat:
|
||||
if(sys.macro_file) {
|
||||
if(last_op == NGCFlowCtrl_Repeat) {
|
||||
if(o_label == stack[stack_index].o_label) {
|
||||
if(stack[stack_index].repeats && --stack[stack_index].repeats)
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
else
|
||||
stack_index--;
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Break:
|
||||
if(sys.macro_file) {
|
||||
if(last_op == NGCFlowCtrl_Do || last_op == NGCFlowCtrl_While || last_op == NGCFlowCtrl_Repeat) {
|
||||
if(o_label == stack[stack_index].o_label) {
|
||||
stack[stack_index].repeats = 0;
|
||||
stack[stack_index].skip = true;
|
||||
}
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Continue:
|
||||
if(sys.macro_file) {
|
||||
if(o_label == stack[stack_index].o_label) switch(last_op) {
|
||||
|
||||
case NGCFlowCtrl_Repeat:
|
||||
if(stack[stack_index].repeats && --stack[stack_index].repeats)
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
else
|
||||
stack_index--;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Do:
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_While:
|
||||
{
|
||||
uint_fast8_t pos = 0;
|
||||
if(!stack[stack_index].skip && (status = ngc_eval_expression(stack[stack_index].expr, &pos, &value)) == Status_OK) {
|
||||
if(!(stack[stack_index].skip = value == 0))
|
||||
vfs_seek(sys.macro_file, stack[stack_index].file_pos);
|
||||
}
|
||||
if(stack[stack_index].skip) {
|
||||
if(stack[stack_index].expr) {
|
||||
free(stack[stack_index].expr);
|
||||
stack[stack_index].expr = NULL;
|
||||
}
|
||||
stack_index--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
status = Status_FlowControlSyntaxError;
|
||||
break;
|
||||
} else
|
||||
status = Status_FlowControlSyntaxError;
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_RaiseAlarm:
|
||||
if(ngc_eval_expression(line, pos, &value) == Status_OK)
|
||||
system_raise_alarm((alarm_code_t)value);
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_RaiseError:
|
||||
if(ngc_eval_expression(line, pos, &value) == Status_OK)
|
||||
status = (status_code_t)value;
|
||||
break;
|
||||
|
||||
case NGCFlowCtrl_Return:
|
||||
if(!skipping && grbl.on_macro_return) {
|
||||
stack_index = -1;
|
||||
if(ngc_eval_expression(line, pos, &value) == Status_OK) {
|
||||
ngc_named_param_set("_value", value);
|
||||
ngc_named_param_set("_value_returned", 1.0f);
|
||||
} else
|
||||
ngc_named_param_set("_value_returned", 0.0f);
|
||||
grbl.on_macro_return();
|
||||
} else
|
||||
status = Status_FlowControlNotExecutingMacro;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = Status_FlowControlSyntaxError;
|
||||
}
|
||||
|
||||
if(status != Status_OK) {
|
||||
ngc_flowctrl_init();
|
||||
*skip = false;
|
||||
} else
|
||||
*skip = stack_index >= 0 && stack[stack_index].skip;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // NGC_EXPRESSIONS_ENABLE
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
ngc_flowctrl.h - An embedded CNC Controller with rs274/ngc (g-code) support
|
||||
|
||||
Program flow control, for filesystem macros
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
|
||||
Grbl 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _NGC_FLOWCTRL_H_
|
||||
#define _NGC_FLOWCTRL_H_
|
||||
|
||||
void ngc_flowctrl_init (void);
|
||||
status_code_t ngc_flowctrl (uint32_t o_label, char *line, uint_fast8_t *pos, bool *skip);
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,9 @@
|
||||
#include "probe.h"
|
||||
#include "alarms.h"
|
||||
#include "messages.h"
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
#include "vfs.h"
|
||||
#endif
|
||||
|
||||
/*! @name System executor bit map.
|
||||
\anchor rt_exec
|
||||
@@ -282,7 +285,10 @@ typedef struct system {
|
||||
volatile probing_state_t probing_state; //!< Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile rt_exec_t rt_exec_state; //!< Realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint_fast16_t rt_exec_alarm; //!< Realtime executor bitflag variable for setting various alarms.
|
||||
int32_t var5399; //!< Last result from M66 - wait on input
|
||||
int32_t var5399; //!< Last result from M66 - wait on input.
|
||||
#if NGC_EXPRESSIONS_ENABLE
|
||||
vfs_file_t *macro_file; //!< File handle of current G65 macro executing.
|
||||
#endif
|
||||
#ifdef PID_LOG
|
||||
pid_data_t pid_log;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user