Changed safety door/parking handling to be compliant with legacy Grbl.

Added $384 setting for controlling G92 offset persistence.
Improved $help command output and handling.
Moved the optional tool table in non-volatile storage.
Added gcode parameter support and optional expression support.
This commit is contained in:
Terje Io
2021-09-29 10:22:47 +02:00
parent 11640adcd2
commit 71dc5ac333
30 changed files with 2480 additions and 410 deletions
+3
View File
@@ -23,6 +23,9 @@ target_sources(grbl INTERFACE
${CMAKE_CURRENT_LIST_DIR}/tool_change.c
${CMAKE_CURRENT_LIST_DIR}/alarms.c
${CMAKE_CURRENT_LIST_DIR}/errors.c
${CMAKE_CURRENT_LIST_DIR}/ngc_params.c
${CMAKE_CURRENT_LIST_DIR}/ngc_expr.c
${CMAKE_CURRENT_LIST_DIR}/regex.c
)
target_include_directories(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR})
+3 -3
View File
@@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
Latest build date is 20210907, see the [changelog](changelog.md) for details.
Latest build date is 20210928, see the [changelog](changelog.md) for details.
__NOTE:__ Drivers built with more than three axes configured \(`N_AXIS` > `3`\) will force a settings reset when upgraded. Backup and restore of settings is recommended for these.
---
@@ -68,7 +68,7 @@ List of Supported G-Codes:
- Coolant Control: M7, M8, M9
- Spindle Control: M3, M4, M5
- Tool Change: M6* (Two modes possible: manual** - supports jogging, ATC), M61
- Switches: M49, M50, M51, M53
- Switches: M48, M49, M50, M51, M53
- Output control***: M62, M63, M64, M65, M66, M67, M68
- Valid Non-Command Words: A*, B*, C*, F, H*, I, J, K, L, N, P, Q*, R, S, T, X, Y, Z
@@ -80,4 +80,4 @@ List of Supported G-Codes:
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
2021-09-08
2021-09-28
+21
View File
@@ -1,5 +1,26 @@
## grblHAL changelog
Build 20210928:
Core:
* Changed safety door/parking handling to be compliant with legacy Grbl - now a cycle start command has to be issued to resume after the door is closed.
* Added `$384` setting for controlling G92 offset persistence, set to `1` to disable persistence across a reboot, `0` to enable. Only available if [compatibility level](https://github.com/grblHAL/core/wiki/Compatibility-level) is < 2, default value is `0`.
* Improved `$help` command output and handling, added description to `$$=<n>` output.
* Moved the optional tool table in non-volatile storage \(typically EEPROM\) to above the core area. This allows a larger number of tools \(max. 16\) to be defined.
__NOTE:__ If you have tool table support enabled before upgrading the current table will be lost and possibly also all other settings. Backup and restore!
* Added gcode parameter support. All [NIST RS274NGC version 3](https://www.nist.gov/publications/nist-rs274ngc-interpreter-version-3) parameters (see section 3.2.1) and most [LinuxCNC](http://www.linuxcnc.org/docs/html/gcode/overview.html#_parameters) parameters are supported.
The `$#=<n>` or `$#=<name>` commands can be used to output a parameter value. Replace `<n>` with a parameter number, `<name>` with a parameter name.
__NOTE 1:__ Named parameters and parameters in the range 1 to 5160 are volatile and will not persist across a reboot.
__NOTE 2:__ Space for the volatile parameters is allocated at run-time, available memory \(heap\) sets a limit to how many can be set.
__NOTE 3:__ Maximum name length is 20 characters, maximum number of parameters that can be set in a block \(line\) is 10.
* Added gcode [expression](http://www.linuxcnc.org/docs/html/gcode/overview.html#gcode:expressions) support. This has to be enabled in [grbl/config.h](./config.h) by uncommenting `//#define NGC_EXPRESSIONS_ENABLE 1`. _Experimental_.
__NOTE:__ Processors with limited memory may not compile with this enabled.
Drivers & plugins:
* Added [WebUI plugin](https://github.com/grblHAL/Plugin_WebUI) support for some networking capable boards.
* Updated some drivers for internal API changes. Some minor bug fixes.
Build 20210907:
Core:
+21 -3
View File
@@ -83,7 +83,7 @@ __NOTE:__ if switching to a level > 1 please reset non-volatile storage with \a
// immediately forces a feed hold and then safely de-energizes the machine. Resuming is blocked until
// the safety door is re-engaged. When it is, Grbl will re-energize the machine and then resume on the
// previous tool path, as if nothing happened.
// #define ENABLE_SAFETY_DOOR_INPUT_PIN // Default disabled. Uncomment to enable.
//#define ENABLE_SAFETY_DOOR_INPUT_PIN // Default disabled. Uncomment to enable.
// After the safety door switch has been toggled and restored, this setting sets the power-up delay
// between restoring the spindle and coolant and resuming the cycle.
@@ -472,9 +472,24 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
//#define DEFAULT_REPORT_PARSER_STATE
//#define DEFAULT_REPORT_ALARM_SUBSTATE
// G92 offsets is by default stored to non-volatile storage (NVS) on changes and restored on startup
// if COMPATIBILITY_LEVEL is <= 1. If COMPATIBILITY_LEVEL is <= 1 then setting $384 can be used to change this at run-time.
// To allow store/restore of the G92 offset when COMPATIBILITY_LEVEL > 1 uncomment the line below and reset settings with $RST=*.
//#define DISABLE_G92_PERSISTENCE 0
#if COMPATIBILITY_LEVEL == 0
// Number of tools in ATC tool table, comment out to disable
// #define N_TOOLS 8
// Number of tools in tool table, uncomment and edit if neccesary to enable (max. 16 allowed)
//#define N_TOOLS 8
#endif
// Sanity checks - N_TOOLS may have been defined on the compiler command line.
#if defined(N_TOOLS) && N_TOOLS == 0
#undef N_TOOLS
#endif
#if defined(N_TOOLS) && N_TOOLS > 16
#undef N_TOOLS
#define N_TOOLS 16
#endif
// Max number of entries in log for PID data reporting, to be used for tuning
@@ -624,4 +639,7 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
#endif // DEFAULT_HOMING_ENABLE
// Uncomment to enable experimental support for parameters and expressions
//#define NGC_EXPRESSIONS_ENABLE 1
#endif
+14
View File
@@ -37,6 +37,14 @@
// Note: DEFAULT_ACCELERATION is only referenced in this file
#define DEFAULT_ACCELERATION (10.0f * 60.0f * 60.0f) // 10*60*60 mm/min^2 = 10 mm/sec^2
#ifndef DISABLE_G92_PERSISTENCE
#if COMPATIBILITY_LEVEL <= 1
#define DISABLE_G92_PERSISTENCE 0
#else
#define DISABLE_G92_PERSISTENCE 1
#endif
#endif
#ifdef DEFAULT_REPORT_MACHINE_POSITION
#undef DEFAULT_REPORT_MACHINE_POSITION
#define DEFAULT_REPORT_MACHINE_POSITION 1
@@ -609,6 +617,12 @@
#define INVERT_COOLANT_MIST_PIN 0
#endif
#ifndef NGC_EXPRESSIONS_ENABLE
#define NGC_EXPRESSIONS_ENABLE 0
#else
#define NGC_N_ASSIGN_PARAMETERS_PER_BLOCK 10
#endif
// ---------------------------------------------------------------------------------------
// COMPILE-TIME ERROR CHECKING OF DEFINE VALUES:
+1 -1
View File
@@ -240,7 +240,7 @@
#if NETWORK_IPMODE < 0 || NETWORK_IPMODE > 2
#error "Invalid IP mode selected!"
#endif
#if NETWORK_WEBSOCKET_PORT == NETWORK_HTTP_PORT
#if HTTP_ENABLE && NETWORK_WEBSOCKET_PORT == NETWORK_HTTP_PORT
#warning "HTTP and WebSocket protocols cannot share the same port!"
#endif
#endif
+9 -1
View File
@@ -81,7 +81,15 @@ PROGMEM static const status_detail_t status_detail[] = {
{ Status_MotorFault, "Motor fault", "Motor fault." },
{ Status_SettingValueOutOfRange, "Value out of range.", "Setting value is out of range." },
{ Status_SettingDisabled, "Setting disabled", "Setting is not available, possibly due to limited driver support." },
{ Status_GcodeInvalidRetractPosition, "Invalid gcode ID:54", "Retract position is less than drill depth." }
{ Status_GcodeInvalidRetractPosition, "Invalid gcode ID:54", "Retract position is less than drill depth." },
#if NGC_EXPRESSIONS_ENABLE
{ Status_ExpressionUknownOp, "Unknown operation found in expression", "Unknown operation found in expression." },
{ Status_ExpressionDivideByZero, "Divide by zero in expression", "Divide by zero in expression attempted." },
{ Status_ExpressionArgumentOutOfRange, "Expression argument out of range", "Too large or too small argrument provided." },
{ Status_ExpressionInvalidArgument, "Invalid expression argument", "Argument is not valid for the operation" },
{ Status_ExpressionSyntaxError, "Syntax error in expression", "Expression is not valid." },
{ Status_ExpressionInvalidResult, "Invalid result returned from expression", "Either NAN (not a number) or infinity was returned from expression." }
#endif
};
static error_details_t details = {
+9
View File
@@ -93,6 +93,15 @@ typedef enum {
Status_SDFileEmpty = 64,
Status_BTInitError = 70,
//
Status_ExpressionUknownOp = 71,
Status_ExpressionDivideByZero = 72,
Status_ExpressionArgumentOutOfRange = 73,
Status_ExpressionInvalidArgument = 74,
Status_ExpressionSyntaxError = 75,
Status_ExpressionInvalidResult = 76,
Status_Unhandled, // For internal use only
Status_StatusMax = Status_Unhandled
} status_code_t;
+230 -17
View File
@@ -30,6 +30,11 @@
#include "protocol.h"
#include "state_machine.h"
#if NGC_EXPRESSIONS_ENABLE
#include "ngc_expr.h"
#include "ngc_params.h"
#endif
// NOTE: Max line number is defined by the g-code standard to be 99999. It seems to be an
// arbitrary value, and some GUIs may require more. So we increased it based on a max safe
// value when converting a float (7.2 digit precision)s to an integer.
@@ -307,10 +312,8 @@ void gc_init (void)
if (!settings_read_coord_data(gc_state.modal.coord_system.id, &gc_state.modal.coord_system.xyz))
grbl.report.status_message(Status_SettingReadFail);
#if COMPATIBILITY_LEVEL <= 1
if (sys.cold_start && !settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset))
if (sys.cold_start && !settings.flags.g92_is_volatile && !settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset))
grbl.report.status_message(Status_SettingReadFail);
#endif
// if(settings.flags.lathe_mode)
// gc_state.modal.plane_select = PlaneSelect_ZX;
@@ -373,12 +376,126 @@ static status_code_t init_sync_motion (plan_line_data_t *pl_data, float pitch)
return Status_OK;
}
// Executes one block (line) of 0-terminated G-Code. The block is assumed to contain only uppercase
// characters and signed floating point values (no whitespace). Comments and block delete
// characters have been removed. In this function, all units and positions are converted and
// exported to grbl's internal functions in terms of (mm, mm/min) and absolute machine
// coordinates, respectively.
status_code_t gc_execute_block(char *block, char *message)
// Remove whitespace, control characters, comments and if block delete is active block delete lines
// else the block delete character. Remaining characters are converted to upper case.
// 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 c, *s1, *s2, *comment = NULL;
// Remove leading whitespace & control characters
while(*block && *block <= ' ')
block++;
if(*block == ';' || (*block == '/' && sys.flags.block_delete_enabled)) {
*block = '\0';
return block;
}
if(*block == '/')
block++;
s1 = s2 = block;
while((c = *s1) != '\0') {
if(c > ' ') switch(c) {
case ';':
if(!comment) {
*s1 = '\0';
continue;
}
break;
case '(':
// TODO: generate error if a left paranthesis is found inside a comment...
comment = s1;
break;
case ')':
if(comment && !hal.driver_cap.no_gcode_message_handling) {
size_t len = s1 - comment - 4;
if(message && *message == NULL && !strncmp(comment, "(MSG,", 5) && (*message = malloc(len))) {
*s1 = '\0';
memcpy(*message, comment + 5, len);
}
}
comment = NULL;
break;
default:
if(comment == NULL)
*s2++ = CAPS(c);
break;
}
if(comment && s1 - comment < 5)
*s1 = CAPS(c);
s1++;
}
*s2 = '\0';
return block;
}
#if NGC_EXPRESSIONS_ENABLE
#define NGC_N_ASSIGN_PARAMETERS_PER_BLOCK 10
static ngc_param_t ngc_params[NGC_N_ASSIGN_PARAMETERS_PER_BLOCK];
static status_code_t read_parameter (char *line, uint_fast8_t *char_counter, float *value)
{
char c = *(line + *char_counter);
status_code_t status = Status_OK;
if(c == '#') {
(*char_counter)++;
if(*(line + *char_counter) == '<') {
(*char_counter)++;
char *pos = line + *char_counter;
while(*line && *line != '>')
line++;
*char_counter += line - pos + 1;
if(*line == '>') {
*line = '\0';
if(!ngc_named_param_get(pos, value))
status = Status_BadNumberFormat;
} else
status = Status_BadNumberFormat;
} else if (read_float(line, char_counter, value)) {
if(!ngc_param_get((ngc_param_id_t)*value, value))
status = Status_BadNumberFormat;
} else
status = Status_BadNumberFormat;
} else if(c == '[')
status = ngc_eval_expression(line, char_counter, value);
else if(!read_float(line, char_counter, value))
*value = NAN;
return status;
}
#endif
// 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.
status_code_t gc_execute_block(char *block)
{
static const parameter_words_t axis_words_mask = {
.x = On,
@@ -428,6 +545,22 @@ status_code_t gc_execute_block(char *block, char *message)
static parser_block_t gc_block;
#if NGC_EXPRESSIONS_ENABLE
uint_fast8_t ngc_param_count = 0;
#endif
char *message = NULL;
block = gc_normalize_block(block, &message);
if(block[0] == '\0') {
if(message) {
report_message(message, Message_Plain);
free(message);
}
return Status_OK;
}
// Determine if the line is a program start/end marker.
// Old comment from protocol.c:
// NOTE: This maybe installed to tell Grbl when a program is running vs manual input,
@@ -436,6 +569,10 @@ status_code_t gc_execute_block(char *block, char *message)
// functions that empty the planner buffer to execute its task on-time.
if (block[0] == CMD_PROGRAM_DEMARCATION && block[1] == '\0') {
gc_state.file_run = !gc_state.file_run;
if(message) {
report_message(message, Message_Plain);
free(message);
}
return Status_OK;
}
@@ -490,6 +627,64 @@ status_code_t gc_execute_block(char *block, char *message)
while ((letter = block[char_counter++]) != '\0') { // Loop until no more g-code words in block.
// Import the next g-code word, expecting a letter followed by a value. Otherwise, error out.
#if NGC_EXPRESSIONS_ENABLE
status_code_t status;
if(letter == '#') {
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 = read_parameter(block, &char_counter, &value)) != Status_OK)
FAIL(status); // [Expected parameter value]
if(!ngc_named_param_set(name, value))
FAIL(Status_BadNumberFormat); // [Expected equal sign]
}
} else {
float param;
if (!read_float(block, &char_counter, &param))
FAIL(Status_BadNumberFormat); // [Expected parameter number]
if (block[char_counter++] != '=')
FAIL(Status_BadNumberFormat); // [Expected equal sign]
if((status = read_parameter(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]
}
continue;
}
if((letter < 'A') || (letter > 'Z'))
FAIL(Status_ExpectedCommandLetter); // [Expected word letter]
if((status = read_parameter(block, &char_counter, &value)) != Status_OK)
return status;
if(!is_user_mcode && isnanf(value))
FAIL(Status_BadNumberFormat); // [Expected word value]
#else
if((letter < 'A') || (letter > 'Z'))
FAIL(Status_ExpectedCommandLetter); // [Expected word letter]
@@ -500,6 +695,8 @@ status_code_t gc_execute_block(char *block, char *message)
FAIL(Status_BadNumberFormat); // [Expected word value]
}
#endif
// Convert values to smaller uint8 significand and mantissa values for parsing this word.
// NOTE: Mantissa is multiplied by 100 to catch non-integer command values. This is more
// accurate than the NIST gcode requirement of x10 when used for commands, but not quite
@@ -805,7 +1002,7 @@ status_code_t gc_execute_block(char *block, char *message)
if(!settings.parking.flags.enable_override_control) // TODO: check if enabled?
FAIL(Status_GcodeUnsupportedCommand); // [Unsupported M command]
// no break;
case 49: case 50: case 51: case 53:
case 48: case 49: case 50: case 51: case 53:
word_bit.modal_group.M9 = On;
gc_block.override_command = (override_mode_t)int_value;
break;
@@ -1309,9 +1506,14 @@ status_code_t gc_execute_block(char *block, char *message)
}
switch(gc_block.override_command) {
case Override_FeedSpeed:
gc_block.modal.override_ctrl.feed_rate_disable = gc_block.values.p == 0.0f;
gc_block.modal.override_ctrl.spindle_rpm_disable = gc_block.values.p == 0.0f;
case Override_FeedSpeedEnable:
gc_block.modal.override_ctrl.feed_rate_disable = Off;
gc_block.modal.override_ctrl.spindle_rpm_disable = Off;
break;
case Override_FeedSpeedDisable:
gc_block.modal.override_ctrl.feed_rate_disable = On;
gc_block.modal.override_ctrl.spindle_rpm_disable = On;
break;
case Override_FeedRate:
@@ -2571,25 +2773,29 @@ status_code_t gc_execute_block(char *block, char *message)
break;
case NonModal_SetCoordinateOffset: // G92
gc_state.g92_coord_offset_applied = true; // TODO: check for all zero?
memcpy(gc_state.g92_coord_offset, gc_block.values.xyz, sizeof(gc_state.g92_coord_offset));
#if COMPATIBILITY_LEVEL <= 1
settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage
#endif
if(!settings.flags.g92_is_volatile)
settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage
system_flag_wco_change();
break;
case NonModal_ResetCoordinateOffset: // G92.1
gc_state.g92_coord_offset_applied = false;
clear_vector(gc_state.g92_coord_offset); // Disable G92 offsets by zeroing offset vector.
settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage
if(!settings.flags.g92_is_volatile)
settings_write_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Save G92 offsets to non-volatile storage
system_flag_wco_change();
break;
case NonModal_ClearCoordinateOffset: // G92.2
gc_state.g92_coord_offset_applied = false;
clear_vector(gc_state.g92_coord_offset); // Disable G92 offsets by zeroing offset vector.
system_flag_wco_change();
break;
case NonModal_RestoreCoordinateOffset: // G92.3
gc_state.g92_coord_offset_applied = true; // TODO: check for all zero?
settings_read_coord_data(CoordinateSystem_G92, &gc_state.g92_coord_offset); // Restore G92 offsets from non-volatile storage
system_flag_wco_change();
break;
@@ -2804,6 +3010,13 @@ status_code_t gc_execute_block(char *block, char *message)
gc_state.modal.program_flow = ProgramFlow_Running; // Reset program flow.
}
#if NGC_EXPRESSIONS_ENABLE
if(ngc_param_count) do {
ngc_param_count--;
ngc_param_set(ngc_params[ngc_param_count].id, ngc_params[ngc_param_count].value);
} while(ngc_param_count);
#endif
// TODO: % to denote start of program.
return Status_OK;
+9 -5
View File
@@ -167,8 +167,8 @@ typedef enum {
Do not alter values!
*/
typedef enum {
SpindleSpeedMode_RPM = 0, //!< 0 - G96 - Default, must be zero
SpindleSpeedMode_CSS = 1 //!< 1 - G97
SpindleSpeedMode_RPM = 0, //!< 0 - G97 - Default, must be zero
SpindleSpeedMode_CSS = 1 //!< 1 - G96
} spindle_rpm_mode_t;
/*! Modal Group M4: Program flow
@@ -186,7 +186,8 @@ typedef enum {
// Modal Group M9: Override control
typedef enum {
Override_FeedSpeed = 49, //!< 49 - M49
Override_FeedSpeedEnable = 48, //!< 48 - M48
Override_FeedSpeedDisable = 49, //!< 49 - M49
Override_FeedRate = 50, //!< 50 - M50
Override_SpindleSpeed = 51, //!< 51 - M51
Override_FeedHold = 53, //!< 53 - M53
@@ -397,7 +398,7 @@ typedef union {
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
motion_mode_t motion; //!< {G0,G1,G2,G3,G38.2,G80}
feed_mode_t feed_mode; //!< {G93,G94}
feed_mode_t feed_mode; //!< {G93,G94,G95}
bool units_imperial; //!< {G20,G21}
bool distance_incremental; //!< {G90,G91}
bool diameter_mode; //!< {G7,G8} Lathe diameter mode.
@@ -496,6 +497,7 @@ typedef struct {
bool tool_change;
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
float g92_coord_offset[N_AXIS]; //!< Retains the G92 coordinate offset (work coordinates) relative to
//!< machine zero in mm. Persistent and loaded from non-volatile storage
//!< on boot when COMPATIBILITY_LEVEL <= 1
@@ -534,8 +536,10 @@ typedef struct {
// Initialize the parser
void gc_init (void);
char *gc_normalize_block (char *block, char **message);
// Execute one block of rs275/ngc/g-code
status_code_t gc_execute_block (char *block, char *message);
status_code_t gc_execute_block (char *block);
// Sets g-code parser position in mm. Input in steps. Called by the system abort and hard
// limit pull-off routines.
+1 -1
View File
@@ -34,7 +34,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_VERSION_BUILD "20210907"
#define GRBL_VERSION_BUILD "20210928"
// The following symbols are set here if not already set by the compiler or in config.h
// Do NOT change here!
+1 -6
View File
@@ -54,7 +54,6 @@ struct system sys = {0}; //!< System global variable structure.
grbl_t grbl;
grbl_hal_t hal;
#ifdef KINEMATICS_API
kinematics_t kinematics;
@@ -90,11 +89,6 @@ void dummy_bool_handler (bool arg)
int grbl_enter (void)
{
#ifdef N_TOOLS
assert(NVS_ADDR_GLOBAL + sizeof(settings_t) + NVS_CRC_BYTES < NVS_ADDR_TOOL_TABLE);
#else
assert(NVS_ADDR_GLOBAL + sizeof(settings_t) + NVS_CRC_BYTES < NVS_ADDR_PARAMETERS);
#endif
assert(NVS_ADDR_PARAMETERS + N_CoordinateSystems * (sizeof(coord_data_t) + NVS_CRC_BYTES) < NVS_ADDR_STARTUP_BLOCK);
assert(NVS_ADDR_STARTUP_BLOCK + N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES) < NVS_ADDR_BUILD_INFO);
@@ -106,6 +100,7 @@ int grbl_enter (void)
grbl.enqueue_gcode = protocol_enqueue_gcode;
grbl.enqueue_realtime_command = stream_enqueue_realtime_command;
grbl.on_report_options = dummy_bool_handler;
grbl.on_report_command_help = system_command_help;
// Clear all and set some HAL function pointers
memset(&hal, 0, sizeof(grbl_hal_t));
+796
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
/* ngc_expr.h */
#ifndef _NGC_EXPR_H_
#define _NGC_EXPR_H_
status_code_t ngc_eval_expression (char *line, uint_fast8_t *pos, float *value);
#endif
+662
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
/*
ngc_params.c - get/set NGC parameter value by id or name
Part of grblHAL
Copyright (c) 2021 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/>.
*/
/*
All predefined parameters defined in NIST RS274NGC version 3 (ref section 3.2.1) are implemented.
Most additional predefined parameters defined by LinuxCNC (ref section 5.2.3.1) are implemented.
Currently it is not possible to set any parameters or reference them from gcode.
*/
#ifndef _NGC_PARAMS_H_
#define _NGC_PARAMS_H_
typedef uint16_t ngc_param_id_t;
typedef struct {
ngc_param_id_t id;
float value;
} ngc_param_t;
bool ngc_param_get (ngc_param_id_t id, float *value);
bool ngc_param_set (ngc_param_id_t id, float value);
bool ngc_param_is_rw (ngc_param_id_t id);
bool ngc_param_exists (ngc_param_id_t id);
bool ngc_named_param_get (char *name, float *value);
bool ngc_named_param_set (char *name, float value);
bool ngc_named_param_exists (char *name);
#endif
+5 -1
View File
@@ -39,13 +39,17 @@
#define M_PI 3.14159265358979323846f
#endif
#define TOLERANCE_EQUAL 0.0001f
#define TAN_30 0.57735f // Used for threading calculations (60 degree inserts)
#define RADDEG 0.0174532925f // Radians per degree
#define DEGRAD 57.29577951f // Degrees per radians
#define ABORTED (sys.abort || sys.cancel)
// Convert character to uppercase
#define CAPS(c) ((c >= 'a' && c <= 'z') ? c & 0x5F : c)
#define CAPS(c) ((c >= 'a' && c <= 'z') ? (c & 0x5F) : c)
#define LCAPS(c) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#ifndef STM32F103xB
#ifndef UNUSED
+5 -2
View File
@@ -33,7 +33,7 @@ Minimum 1024 bytes required, more if space for driver and/or plugin data and set
/*! \brief Number of bytes at the start of the NVS area reserved for core settings and parameters.
Minimum 1024 bytes required.
*/
#define GRBL_NVS_SIZE 1024
#define GRBL_NVS_END 1023
//! Number of bytes used for storing CRC values. Do not change this!
#define NVS_CRC_BYTES 1
@@ -50,7 +50,10 @@ __NOTE:__ 1024 bytes of persistent storage is the minimum required.
#define NVS_ADDR_BUILD_INFO 942U
#define NVS_ADDR_STARTUP_BLOCK (NVS_ADDR_BUILD_INFO - 1 - N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES))
#ifdef N_TOOLS
#define NVS_ADDR_TOOL_TABLE (NVS_ADDR_PARAMETERS - 1 - N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES))
#define NVS_ADDR_TOOL_TABLE (GRBL_NVS_END + 1)
#define GRBL_NVS_SIZE (GRBL_NVS_END + 1 + N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES))
#else
#define GRBL_NVS_SIZE (GRBL_NVS_END + 1)
#endif
///@}
+36 -23
View File
@@ -32,6 +32,9 @@
#include "hal.h"
#include "nvs_buffer.h"
#include "protocol.h"
#include "settings.h"
#include "gcode.h"
#include "nvs.h"
static uint8_t *nvsbuffer = NULL;
static nvs_io_t physical_nvs;
@@ -51,6 +54,7 @@ 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))
#ifdef N_TOOLS
@@ -59,19 +63,7 @@ typedef struct {
static const emap_t target[] = {
{NVS_ADDR_GLOBAL, NVS_GROUP_GLOBAL, 0},
#ifdef N_TOOLS
{TOOL_ADDR(0), NVS_GROUP_TOOLS, 0},
{TOOL_ADDR(1), NVS_GROUP_TOOLS, 1},
{TOOL_ADDR(2), NVS_GROUP_TOOLS, 2},
{TOOL_ADDR(3), NVS_GROUP_TOOLS, 3},
{TOOL_ADDR(4), NVS_GROUP_TOOLS, 4},
{TOOL_ADDR(5), NVS_GROUP_TOOLS, 5},
{TOOL_ADDR(6), NVS_GROUP_TOOLS, 6},
{TOOL_ADDR(7), NVS_GROUP_TOOLS, 7},
#if N_TOOLS > 8
#error Increase number of tool entries!
#endif
#endif
{PARAMETER_ADDR(0), NVS_GROUP_PARAMETERS, 0},
{PARAMETER_ADDR(1), NVS_GROUP_PARAMETERS, 1},
{PARAMETER_ADDR(2), NVS_GROUP_PARAMETERS, 2},
@@ -90,6 +82,29 @@ static const emap_t target[] = {
#error Increase number of startup line entries!
#endif
{NVS_ADDR_BUILD_INFO, NVS_GROUP_BUILD, 0},
#ifdef N_TOOLS
{TOOL_ADDR(0), NVS_GROUP_TOOLS, 0},
{TOOL_ADDR(1), NVS_GROUP_TOOLS, 1},
{TOOL_ADDR(2), NVS_GROUP_TOOLS, 2},
{TOOL_ADDR(3), NVS_GROUP_TOOLS, 3},
{TOOL_ADDR(4), NVS_GROUP_TOOLS, 4},
{TOOL_ADDR(5), NVS_GROUP_TOOLS, 5},
{TOOL_ADDR(6), NVS_GROUP_TOOLS, 6},
{TOOL_ADDR(7), NVS_GROUP_TOOLS, 7},
#if N_TOOLS > 8
{TOOL_ADDR(8), NVS_GROUP_TOOLS, 8},
{TOOL_ADDR(9), NVS_GROUP_TOOLS, 9},
{TOOL_ADDR(10), NVS_GROUP_TOOLS, 10},
{TOOL_ADDR(11), NVS_GROUP_TOOLS, 11},
{TOOL_ADDR(12), NVS_GROUP_TOOLS, 12},
{TOOL_ADDR(13), NVS_GROUP_TOOLS, 13},
{TOOL_ADDR(14), NVS_GROUP_TOOLS, 14},
{TOOL_ADDR(15), NVS_GROUP_TOOLS, 15},
#endif
#if N_TOOLS > 16
#error Increase number of tool entries!
#endif
#endif
{0, 0, 0} // list termination - do not remove
};
@@ -106,8 +121,6 @@ inline static void ram_put_byte (uint32_t addr, uint8_t new_value)
nvsbuffer[addr] = new_value;
}
// Extensions added as part of Grbl
static nvs_transfer_result_t memcpy_to_ram (uint32_t destination, uint8_t *source, uint32_t size, bool with_checksum)
{
if(hal.nvs.driver_area.address && destination > hal.nvs.driver_area.address + hal.nvs.driver_area.size)
@@ -373,14 +386,6 @@ void nvs_memmap (void)
strcat(buf, uitoa(sizeof(settings_t) + NVS_CRC_BYTES));
report_message(buf, Message_Plain);
#ifdef N_TOOLS
strcpy(buf, "Tool table: ");
strcat(buf, uitoa(NVS_ADDR_TOOL_TABLE));
strcat(buf, " ");
strcat(buf, uitoa(N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES)));
report_message(buf, Message_Plain);
#endif
strcpy(buf, "Parameters: ");
strcat(buf, uitoa(NVS_ADDR_PARAMETERS));
strcat(buf, " ");
@@ -399,6 +404,14 @@ void nvs_memmap (void)
strcat(buf, uitoa(sizeof(stored_line_t) + NVS_CRC_BYTES));
report_message(buf, Message_Plain);
#ifdef N_TOOLS
strcpy(buf, "Tool table: ");
strcat(buf, uitoa(NVS_ADDR_TOOL_TABLE));
strcat(buf, " ");
strcat(buf, uitoa(N_TOOLS * (sizeof(tool_data_t) + NVS_CRC_BYTES)));
report_message(buf, Message_Plain);
#endif
strcpy(buf, "Driver: ");
strcat(buf, uitoa(hal.nvs.driver_area.address));
strcat(buf, " ");
+4
View File
@@ -34,8 +34,12 @@ typedef struct {
uint8_t startup_lines;
uint16_t coord_data;
#ifdef N_TOOLS
#if N_TOOLS > 16
uint32_t tool_data;
#else
uint16_t tool_data;
#endif
#endif
} settings_dirty_t;
extern settings_dirty_t settings_dirty;
+27 -74
View File
@@ -45,18 +45,10 @@ typedef union {
uint8_t overflow :1,
comment_parentheses :1,
comment_semicolon :1,
block_delete :1,
unassigned :4;
unassigned :5;
};
} line_flags_t;
typedef struct {
char *message;
uint_fast8_t idx;
uint_fast8_t tracker;
bool show;
} user_message_t;
typedef struct {
volatile uint_fast8_t head;
volatile uint_fast8_t tail;
@@ -67,8 +59,6 @@ static uint_fast16_t char_counter = 0;
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
static char xcommand[LINE_BUFFER_SIZE];
static bool keep_rt_commands = false;
static user_message_t user_message = {NULL, 0, 0, false};
static const char *msg = "(MSG,";
static realtime_queue_t realtime_queue = {0};
static void protocol_exec_rt_suspend ();
@@ -163,10 +153,9 @@ bool protocol_main_loop (void)
int16_t c;
char eol = '\0';
line_flags_t line_flags = {0};
bool nocaps = false, line_is_comment = false;
xcommand[0] = '\0';
user_message.show = keep_rt_commands = false;
keep_rt_commands = false;
while(true) {
@@ -177,7 +166,7 @@ bool protocol_main_loop (void)
if(c == ASCII_CAN) {
eol = xcommand[0] = '\0';
keep_rt_commands = nocaps = line_is_comment = user_message.show = false;
keep_rt_commands = false;
char_counter = line_flags.value = 0;
gc_state.last_error = Status_OK;
@@ -206,7 +195,7 @@ bool protocol_main_loop (void)
// Direct and execute one line of formatted input, and report status of execution.
if (line_flags.overflow) // Report line overflow error.
gc_state.last_error = Status_Overflow;
else if ((line[0] == '\0' || char_counter == 0) && !user_message.show && !line_is_comment) // Empty or comment line. For syncing purposes.
else if(line[0] == '\0') // Empty line. For syncing purposes.
gc_state.last_error = Status_OK;
else if (line[0] == '$') {// Grbl '$' system command
if((gc_state.last_error = system_execute_line(line)) == Status_LimitsEngaged) {
@@ -223,7 +212,7 @@ bool protocol_main_loop (void)
else { // Parse and execute g-code block.
#endif
gc_state.last_error = gc_execute_block(line, user_message.show ? user_message.message : NULL);
gc_state.last_error = gc_execute_block(line);
}
// Add a short delay for each block processed in Check Mode to
@@ -238,74 +227,39 @@ bool protocol_main_loop (void)
grbl.report.status_message(gc_state.last_error);
// Reset tracking data for next line.
keep_rt_commands = nocaps = user_message.show = false;
keep_rt_commands = false;
char_counter = line_flags.value = 0;
} else if (c <= (nocaps ? ' ' - 1 : ' ') || line_flags.value) {
// Throw away all whitepace, control characters, comment characters and overflow characters.
if(c >= ' ' && line_flags.comment_parentheses) {
if(user_message.tracker == 5)
user_message.message[user_message.idx++] = c == ')' ? '\0' : c;
else if(user_message.tracker > 0 && CAPS(c) == msg[user_message.tracker])
user_message.tracker++;
else
user_message.tracker = 0;
if (c == ')') {
// End of '()' comment. Resume line.
line_flags.comment_parentheses = Off;
keep_rt_commands = false;
user_message.show = user_message.show || user_message.tracker == 5;
}
}
} else {
} else if (c <= (char_counter > 0 ? ' ' - 1 : ' '))
continue; // Strip control characters and leading whitespace.
else {
switch(c) {
case '/':
if(char_counter == 0)
line_flags.block_delete = sys.flags.block_delete_enabled;
break;
case '$':
case '[':
// Do not uppercase system or user commands - will destroy passwords etc...
if(char_counter == 0)
nocaps = keep_rt_commands = true;
keep_rt_commands = true;
break;
case '(':
if(char_counter == 0)
line_is_comment = On;
if(!keep_rt_commands) {
// Enable comments flag and ignore all characters until ')' or EOL unless it is a message.
// NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
// In the future, we could simply remove the items within the comments, but retain the
// comment control characters, so that the g-code parser can error-check it.
if((line_flags.comment_parentheses = !line_flags.comment_semicolon)) {
if(!hal.driver_cap.no_gcode_message_handling) {
if(user_message.message == NULL)
user_message.message = malloc(LINE_BUFFER_SIZE);
if(user_message.message) {
user_message.idx = 0;
user_message.tracker = 1;
}
}
keep_rt_commands = true;
}
}
if(!keep_rt_commands && (line_flags.comment_parentheses = !line_flags.comment_semicolon))
keep_rt_commands = !hal.driver_cap.no_gcode_message_handling; // Suspend real-time processing of printable command characters.
break;
case ')':
if(!line_flags.comment_semicolon)
line_flags.comment_parentheses = keep_rt_commands = false;
break;
case ';':
if(char_counter == 0)
line_is_comment = On;
// NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
if(!keep_rt_commands) {
if((line_flags.comment_semicolon = !line_flags.comment_parentheses))
keep_rt_commands = true;
if(!line_flags.comment_parentheses) {
keep_rt_commands = false;
line_flags.comment_semicolon = On;
}
break;
}
if (line_flags.value == 0 && !(line_flags.overflow = char_counter >= (LINE_BUFFER_SIZE - 1)))
line[char_counter++] = nocaps ? c : CAPS(c);
if(!(line_flags.overflow = char_counter >= (LINE_BUFFER_SIZE - 1)))
line[char_counter++] = c;
}
}
@@ -317,7 +271,7 @@ bool protocol_main_loop (void)
else if (state_get() & (STATE_ALARM|STATE_ESTOP|STATE_JOG)) // Everything else is gcode. Block if in alarm, eStop or jog state.
grbl.report.status_message(Status_SystemGClock);
else // Parse and execute g-code block.
gc_execute_block(xcommand, NULL);
gc_execute_block(xcommand);
xcommand[0] = '\0';
}
@@ -518,7 +472,7 @@ bool protocol_exec_rt_system (void)
sync_position();
flush_override_buffers();
if(!((state_get() == STATE_ALARM) && (sys.alarm == Alarm_LimitsEngaged || sys.alarm == Alarm_HomingRequried)))
state_set(STATE_IDLE);
state_set(hal.control.get_state().safety_door_ajar ? STATE_SAFETY_DOOR : STATE_IDLE);
}
// Execute and print status to output stream
@@ -700,9 +654,9 @@ static void protocol_exec_rt_suspend (void)
// Handle spindle overrides during suspend
state_suspend_manager();
// If door closed keep issuing cycle start requests until resumed
// If door closed keep issuing door closed requests until resumed
if(state_get() == STATE_SAFETY_DOOR && !hal.control.get_state().safety_door_ajar)
system_set_exec_state_flag(EXEC_CYCLE_START);
system_set_exec_state_flag(EXEC_DOOR_CLOSED);
// Check for sleep conditions and execute auto-park, if timeout duration elapses.
// Sleep is valid for both hold and door states, if the spindle or coolant are on or
@@ -783,7 +737,7 @@ ISR_CODE bool protocol_enqueue_realtime_command (char c)
break;
case CMD_SAFETY_DOOR:
if(!hal.signals_cap.safety_door_ajar) {
if(state_get() != STATE_SAFETY_DOOR) {
system_set_exec_state_flag(EXEC_SAFETY_DOOR);
drop = true;
}
@@ -933,4 +887,3 @@ void protocol_execute_noop (sys_state_t state)
{
(void)state;
}
+49
View File
@@ -0,0 +1,49 @@
// regex.c - A Regular Expression Matcher
//
// Code by Rob Pike, exegesis by Brian Kernighan
//
// http://genius.cat-v.org/brian-kernighan/articles/beautiful
//
// c matches any literal character c
// . matches any single character
// ^ matches the beginning of the input string
// $ matches the end of the input string
// * matches zero or more occurrences of the previous character
#include "regex.h"
/* match: search for regexp anywhere in text */
int match(char *regexp, char *text)
{
if (regexp[0] == '^')
return matchhere(regexp+1, text);
do { /* must look even if string is empty */
if (matchhere(regexp, text))
return 1;
} while (*text++ != '\0');
return 0;
}
/* matchhere: search for regexp at beginning of text */
int matchhere(char *regexp, char *text)
{
if (regexp[0] == '\0')
return 1;
if (regexp[1] == '*')
return matchstar(regexp[0], regexp+2, text);
if (regexp[0] == '$' && regexp[1] == '\0')
return *text == '\0';
if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
return matchhere(regexp+1, text+1);
return 0;
}
/* matchstar: search for c*regexp at beginning of text */
int matchstar(int c, char *regexp, char *text)
{
do { /* a * matches zero or more instances */
if (matchhere(regexp, text))
return 1;
} while (*text != '\0' && (*text++ == c || c == '.'));
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
// regex.h - A Regular Expression Matcher
//
// Code by Rob Pike, exegesis by Brian Kernighan
//
// http://genius.cat-v.org/brian-kernighan/articles/beautiful
//
// c matches any literal character c
// . matches any single character
// ^ matches the beginning of the input string
// $ matches the end of the input string
// * matches zero or more occurrences of the previous character
#pragma once
/* match: search for regexp anywhere in text */
int match(char *regexp, char *text);
/* matchhere: search for regexp at beginning of text */
int matchhere(char *regexp, char *text);
/* matchstar: search for c*regexp at beginning of text */
int matchstar(int c, char *regexp, char *text);
+103 -49
View File
@@ -38,6 +38,7 @@
#include "nvs_buffer.h"
#include "limits.h"
#include "state_machine.h"
#include "regex.h"
#ifdef ENABLE_SPINDLE_LINEARIZATION
#include <stdio.h>
@@ -353,88 +354,82 @@ void report_grbl_help (void)
hal.stream.write("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H $B ~ ! ? ctrl-x]" ASCII_EOL);
}
#define CAPS(c) ((c >= 'a' && c <= 'z') ? c & 0x5F : c)
static void report_group_settings (const setting_group_detail_t *groups, const uint_fast8_t n_groups, char *lcargs)
static bool report_group_settings (const setting_group_detail_t *groups, const uint_fast8_t n_groups, char *args)
{
bool found = false;
uint_fast8_t idx;
uint_fast8_t len = strlen(lcargs);
char c, *s, group[25];
for(idx = 0; idx < n_groups; idx++) {
if(strlen(groups[idx].name) == len) {
char *s1 = lcargs, *s2 = (char *)groups[idx].name;
while(*s1 && CAPS(*s1) == CAPS(*s2)) {
s1++;
s2++;
}
if(*s1 == '\0') {
report_settings_details(SettingsFormat_HumanReadable, Setting_SettingsAll, groups[idx].id);
break;
}
s = group;
strncpy(group, groups[idx].name, sizeof(group));
// Uppercase group name
while((c = *s))
*s++ = CAPS(c);
if((found = matchhere(args, group))) {
hal.stream.write(ASCII_EOL "---- ");
hal.stream.write(groups[idx].name);
hal.stream.write(":" ASCII_EOL);
report_settings_details(SettingsFormat_HumanReadable, Setting_SettingsAll, groups[idx].id);
break;
}
}
return found;
}
status_code_t report_help (char *args, char *lcargs)
status_code_t report_help (char *args)
{
setting_details_t *settings_info = settings_get_details();
// Strip leading spaces
while(*args == ' ')
args++;
if(*args == '\0') {
hal.stream.write("Help arguments:" ASCII_EOL);
hal.stream.write("Help topics:" ASCII_EOL);
hal.stream.write(" Commands" ASCII_EOL);
hal.stream.write(" Settings" ASCII_EOL);
report_setting_group_details(false, " ");
} else {
if(!strncmp(args, "COMMANDS", 8)) {
hal.stream.write("$I - list system information" ASCII_EOL);
hal.stream.write("$$ - list settings" ASCII_EOL);
hal.stream.write("$# - list offsets, tool table, probing and home position" ASCII_EOL);
hal.stream.write("$G - list parser state" ASCII_EOL);
hal.stream.write("$N - list startup lines" ASCII_EOL);
if(settings.homing.flags.enabled)
hal.stream.write("$H - home configured axes" ASCII_EOL);
if(settings.homing.flags.single_axis_commands)
hal.stream.write("$H<axisletter> - home single axis" ASCII_EOL);
hal.stream.write("$X - unlock machine" ASCII_EOL);
hal.stream.write("$SLP - enter sleep mode" ASCII_EOL);
hal.stream.write("$HELP <arg> - help" ASCII_EOL);
hal.stream.write("$RST=* - restore/reset all" ASCII_EOL);
hal.stream.write("$RST=$ - restore default settings" ASCII_EOL);
if(settings_info->on_get_settings)
hal.stream.write("$RST=& - restore driver and plugin default settings" ASCII_EOL);
#ifdef N_TOOLS
hal.stream.write("$RST=# - reset offsets and tool data" ASCII_EOL);
#else
hal.stream.write("$RST=# - reset offsets" ASCII_EOL);
#endif
char c, *s = args;
// Upper case argument
while((c = *s))
*s++ = CAPS(c);
if(matchhere(args, "COMMANDS")) {
if(grbl.on_report_command_help)
grbl.on_report_command_help();
} else if(!strncmp(args, "SETTINGS", 8))
} else if(matchhere(args, "SETTINGS"))
report_settings_details(SettingsFormat_HumanReadable, Setting_SettingsAll, Group_All);
else {
// Strip leading spaces from lowercase version
while(*lcargs == ' ')
lcargs++;
bool found = false;
setting_details_t *settings_info = settings_get_details();
report_group_settings(settings_info->groups, settings_info->n_groups, lcargs);
found = report_group_settings(settings_info->groups, settings_info->n_groups, args);
if(grbl.on_get_settings) {
if(!found && grbl.on_get_settings) {
on_get_settings_ptr on_get_settings = grbl.on_get_settings;
while(on_get_settings) {
settings_info = on_get_settings();
if(settings_info->groups)
report_group_settings(settings_info->groups, settings_info->n_groups, lcargs);
if(settings_info->groups && (found = report_group_settings(settings_info->groups, settings_info->n_groups, args)))
break;
on_get_settings = settings_info->on_get_settings;
}
}
if(!found)
hal.stream.write( ASCII_EOL "N/A" ASCII_EOL);
}
}
@@ -579,6 +574,41 @@ void report_tool_offsets (void)
hal.stream.write("]" ASCII_EOL);
}
// Prints NIST/LinuxCNC NGC parameter value
status_code_t report_ngc_parameter (ngc_param_id_t id)
{
float value;
hal.stream.write("[PARAM:");
hal.stream.write(uitoa(id));
if(ngc_param_get(id, &value)) {
hal.stream.write("=");
hal.stream.write(ftoa(value, 3));
} else
hal.stream.write("=N/A");
hal.stream.write("]" ASCII_EOL);
return Status_OK;
}
// Prints named LinuxCNC NGC parameter value
status_code_t report_named_ngc_parameter (char *arg)
{
float value;
hal.stream.write("[PARAM:");
hal.stream.write(arg);
if(ngc_named_param_get(arg, &value)) {
hal.stream.write("=");
hal.stream.write(ftoa(value, 3));
} else
hal.stream.write("=N/A");
hal.stream.write("]" ASCII_EOL);
return Status_OK;
}
// Prints Grbl NGC parameters (coordinate offsets, probing, tool table)
void report_ngc_parameters (void)
{
@@ -942,6 +972,10 @@ void report_build_info (char *line, bool extended)
if(settings.mode == Mode_Lathe)
strcat(buf, "LATHE,");
#if NGC_EXPRESSIONS_ENABLE
strcat(buf, "EXPR,");
#endif
#ifdef N_TOOLS
if(hal.driver_cap.atc && hal.tool.change)
strcat(buf, "ATC,");
@@ -1395,7 +1429,7 @@ static void report_settings_detail (settings_format_t format, const setting_deta
switch(format)
{
case SettingsFormat_HumanReadable:
hal.stream.write("$");
hal.stream.write(ASCII_EOL "$");
hal.stream.write(uitoa(setting->id + offset));
hal.stream.write(": ");
if(setting->group == Group_Axis0)
@@ -1454,6 +1488,26 @@ static void report_settings_detail (settings_format_t format, const setting_deta
hal.stream.write(setting->max_value);
}
}
#ifndef NO_SETTINGS_DESCRIPTIONS
// Add description if driver is capable of outputting it...
if(hal.stream.write_n) {
const char *description = setting_get_description(setting->id);
if(description && *description != '\0') {
char *lf;
hal.stream.write(ASCII_EOL);
if((lf = strstr(description, "\\n"))) while(lf) {
hal.stream.write(ASCII_EOL);
hal.stream.write_n(description, lf - description);
description = lf + 2;
lf = strstr(description, "\\n");
}
if(*description != '\0') {
hal.stream.write(ASCII_EOL);
hal.stream.write(description);
}
}
}
#endif
break;
case SettingsFormat_MachineReadable:
+8 -1
View File
@@ -24,6 +24,7 @@
#define _REPORT_H_
#include "system.h"
#include "ngc_params.h"
// Message types for uncoded messages
typedef enum {
@@ -59,7 +60,7 @@ message_code_t report_feedback_message (message_code_t message_code);
void report_init_message (void);
// Prints Grbl help.
status_code_t report_help (char *args, char *lcargs);
status_code_t report_help (char *args);
void report_grbl_help();
// Prints Grbl settings
@@ -80,6 +81,12 @@ void report_probe_parameters (void);
// Prints current tool offsets.
void report_tool_offsets (void);
// Prints NIST/LinuxCNC NGC parameter value
status_code_t report_ngc_parameter (ngc_param_id_t id);
// Prints named LinuxCNC NGC parameter value
status_code_t report_named_ngc_parameter (char *arg);
// Prints Grbl NGC parameters (coordinate offsets, probe).
void report_ngc_parameters (void);
+33 -1
View File
@@ -77,6 +77,11 @@ PROGMEM const settings_t defaults = {
.flags.legacy_rt_commands = DEFAULT_LEGACY_RTCOMMANDS,
.flags.report_inches = DEFAULT_REPORT_INCHES,
.flags.sleep_enable = DEFAULT_SLEEP_ENABLE,
#if DISABLE_G92_PERSISTENCE
.flags.g92_is_volatile = 1,
#else
.flags.g92_is_volatile = 0,
#endif
#if DEFAULT_LASER_MODE
.mode = Mode_Laser,
.flags.disable_laser_during_hold = DEFAULT_ENABLE_LASER_DURING_HOLD,
@@ -355,10 +360,14 @@ static status_code_t set_rotational_axes (setting_id_t id, uint_fast16_t int_val
static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value);
#endif
static status_code_t set_axis_setting (setting_id_t setting, float value);
#if COMPATIBILITY_LEVEL <= 1
static status_code_t set_g92_disable_persistence (setting_id_t id, uint_fast16_t int_value);
#endif
static float get_float (setting_id_t setting);
static uint32_t get_int (setting_id_t id);
static bool is_setting_available (const setting_detail_t *setting);
static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault";
static char spindle_signals[] = "Spindle enable,Spindle direction,PWM";
static char coolant_signals[] = "Flood,Mist";
@@ -481,6 +490,9 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_DualAxisLengthFailPercent, Group_Limits_DualAxis, "Dual axis length fail", "percent", Format_Decimal, "##0.0", "0", "100", Setting_IsExtended, &settings.homing.dual_axis.fail_length_percent, NULL, NULL },
{ Setting_DualAxisLengthFailMin, Group_Limits_DualAxis, "Dual axis length fail min", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_min, NULL, NULL },
{ Setting_DualAxisLengthFailMax, Group_Limits_DualAxis, "Dual axis length fail max", "mm", Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtended, &settings.homing.dual_axis.fail_distance_max, NULL, NULL },
#if COMPATIBILITY_LEVEL <= 1
{ Setting_DisableG92Persistence, Group_General, "Disable G92 persistence", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_g92_disable_persistence, get_int, NULL },
#endif
#if N_AXIS == 4
{ Settings_Axis_Rotational, Group_Stepper, "Rotational axes", NULL, Format_Bitfield, "A-Axis", NULL, NULL, Setting_IsExtendedFn, set_rotational_axes, get_int, NULL }
#elif N_AXIS == 5
@@ -612,7 +624,10 @@ PROGMEM static const setting_descr_t setting_descr[] = {
{ Setting_ToolChangePulloffRate, "Pull-off rate for the retract move before the slower locating phase." },
{ Setting_DualAxisLengthFailPercent, "Dual axis length fail in percent of axis max travel." },
{ Setting_DualAxisLengthFailMin, "Dual axis length fail minimum distance." },
{ Setting_DualAxisLengthFailMax, "Dual axis length fail minimum distance." }
{ Setting_DualAxisLengthFailMax, "Dual axis length fail minimum distance." },
#if COMPATIBILITY_LEVEL <= 1
{ Setting_DisableG92Persistence, "Disables save/restore of G92 offset to non-volatile storage (NVS)." },
#endif
};
#endif
@@ -900,6 +915,15 @@ static status_code_t set_hold_actions (setting_id_t id, uint_fast16_t int_value)
return Status_OK;
}
#if COMPATIBILITY_LEVEL <= 1
static status_code_t set_g92_disable_persistence (setting_id_t id, uint_fast16_t int_value)
{
settings.flags.g92_is_volatile = int_value != 0;
return Status_OK;
}
#endif
static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast16_t int_value)
{
settings.flags.force_initialization_alarm = int_value != 0;
@@ -1231,6 +1255,10 @@ static uint32_t get_int (setting_id_t id)
value = settings.tool_change.mode;
break;
case Setting_DisableG92Persistence:
value = settings.flags.g92_is_volatile;
break;
#if N_AXIS > 3
case Settings_Axis_Rotational:
value = (settings.steppers.is_rotational.mask & AXES_BITMASK) >> 3;
@@ -1475,6 +1503,10 @@ bool read_global_settings ()
if(settings.mode == Mode_Laser && !hal.driver_cap.variable_spindle)
settings.mode = Mode_Standard;
#if COMPATIBILITY_LEVEL > 1 && DISABLE_G92_PERSISTENCE
settings.flags.g92_is_volatile = On;
#endif
return ok && settings.version == SETTINGS_VERSION;
}
+20 -2
View File
@@ -31,7 +31,7 @@
// Version of the persistent storage data. Will be used to migrate existing data from older versions of Grbl
// when firmware is upgraded. Always stored in byte 0 of non-volatile storage
// TODO: add ftp port to network settings
// TODO: add ftp port to network settings, enable safety_door settings
#if N_AXIS > 3 // TODO: remove on next version update
#define SETTINGS_VERSION 20 // NOTE: Check settings_reset() when moving to next version.
@@ -241,6 +241,7 @@ typedef enum {
Setting_CoolantMaxTemp = 381,
Setting_CoolantOffset = 382,
Setting_CoolantGain = 383,
Setting_DisableG92Persistence = 384,
Setting_EncoderSettingsBase = 400, // NOTE: Reserving settings values >= 400 for encoder settings. Up to 449.
Setting_EncoderSettingsMax = 449,
@@ -318,7 +319,8 @@ typedef union {
legacy_rt_commands :1,
restore_after_feed_hold :1,
keep_coolant_state_on_door_open :1,
unassigned :7;
g92_is_volatile :1,
unassigned :6;
};
} settingflags_t;
@@ -354,6 +356,21 @@ typedef union {
};
} reportmask_t;
typedef union {
uint8_t value;
struct {
uint8_t ignore_when_idle :1,
keep_coolant_on :1,
unassigned :6;
};
} safety_door_setting_flags_t;
typedef union {
safety_door_setting_flags_t flags;
float spindle_on_delay;
float coolant_on_delay;
} safety_door_settings_t;
typedef union {
uint8_t value;
struct {
@@ -558,6 +575,7 @@ typedef struct {
homing_settings_t homing;
limit_settings_t limits;
parking_settings_t parking;
// safety_door_settings_t safety_door;
position_pid_t position; // Used for synchronized motion
ioport_signals_t ioport;
} settings_t;
+231 -180
View File
File diff suppressed because it is too large Load Diff
+99 -40
View File
@@ -145,7 +145,7 @@ void system_execute_startup (void)
if (!settings_read_startup_line(n, line))
report_execute_startup_message(line, Status_SettingReadFail);
else if (*line != '\0')
report_execute_startup_message(line, gc_execute_block(line, NULL));
report_execute_startup_message(line, gc_execute_block(line));
}
}
}
@@ -177,7 +177,7 @@ status_code_t read_int (char *s, int32_t *value)
PROGMEM static const sys_command_t sys_commands[] = {
{ "G", true, output_parser_state },
{ "J", false, jog },
{ "#", true, output_ngc_parameters },
{ "#", false, output_ngc_parameters },
{ "$", false, output_settings },
{ "+", false, output_all_settings },
#ifndef NO_SETTINGS_DESCRIPTIONS
@@ -231,6 +231,57 @@ PROGMEM static const sys_command_t sys_commands[] = {
#endif
};
void system_command_help (void)
{
hal.stream.write("$I - output system information" ASCII_EOL);
hal.stream.write("$<n> - output setting <n> value" ASCII_EOL);
hal.stream.write("$<n>=<value> - assign <value> to settings <n>" ASCII_EOL);
hal.stream.write("$I - output system information" ASCII_EOL);
hal.stream.write("$I+ - output extended system information" ASCII_EOL);
hal.stream.write("$$ - output all setting values" ASCII_EOL);
hal.stream.write("$+ - output all setting values" ASCII_EOL);
hal.stream.write("$$=<n> - output setting details for setting <n>" ASCII_EOL);
hal.stream.write("$# - output offsets, tool table, probing and home position" ASCII_EOL);
hal.stream.write("$#=<n> - output value for parameter <n>" ASCII_EOL);
hal.stream.write("$G - output parser state" ASCII_EOL);
hal.stream.write("$N - output startup lines" ASCII_EOL);
if(settings.homing.flags.enabled)
hal.stream.write("$H - home configured axes" ASCII_EOL);
if(settings.homing.flags.single_axis_commands)
hal.stream.write("$H<axisletter> - home single axis" ASCII_EOL);
hal.stream.write("$X - unlock machine" ASCII_EOL);
hal.stream.write("$SLP - enter sleep mode" ASCII_EOL);
hal.stream.write("$HELP - output help topics" ASCII_EOL);
hal.stream.write("$HELP <topic> - output help for <topic>" ASCII_EOL);
hal.stream.write("$RST=* - restore/reset all" ASCII_EOL);
hal.stream.write("$RST=$ - restore default settings" ASCII_EOL);
if(settings_get_details()->on_get_settings)
hal.stream.write("$RST=& - restore driver and plugin default settings" ASCII_EOL);
#ifdef N_TOOLS
hal.stream.write("$RST=# - reset offsets and tool data" ASCII_EOL);
#else
hal.stream.write("$RST=# - reset offsets" ASCII_EOL);
#endif
hal.stream.write("$TLR - set tool offset reference" ASCII_EOL);
hal.stream.write("$TPW - probe tool plate" ASCII_EOL);
hal.stream.write("$EA - enumerate alarms" ASCII_EOL);
hal.stream.write("$EAG - enumerate alarms, Grbl formatted" ASCII_EOL);
hal.stream.write("$EE - enumerate status codes" ASCII_EOL);
hal.stream.write("$EEG - enumerate status codes, Grbl formatted" ASCII_EOL);
hal.stream.write("$ES - enumerate settings" ASCII_EOL);
hal.stream.write("$ESG - enumerate settings, Grbl formatted" ASCII_EOL);
hal.stream.write("$ESH- enumerate settings, grblHAL formatted" ASCII_EOL);
hal.stream.write("$ESG - enumerate alarms" ASCII_EOL);
hal.stream.write("$E* - enumerate alarms, status codes and settings" ASCII_EOL);
if(hal.enumerate_pins)
hal.stream.write("$PINS - enumerate pin bindings" ASCII_EOL);
hal.stream.write("$LEV - output last control signal events" ASCII_EOL);
hal.stream.write("$LIM - output current limit pins state" ASCII_EOL);
#ifndef NO_SETTINGS_DESCRIPTIONS
hal.stream.write("$SED=<n> - output settings description for setting <n>" ASCII_EOL);
#endif
}
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
@@ -248,9 +299,6 @@ status_code_t system_execute_line (char *line)
return Status_OK;
}
if(strlen(line) >= ((LINE_BUFFER_SIZE / 2) - 1))
return Status_Overflow;
sys_commands_t base = {
.n_commands = sizeof(sys_commands) / sizeof(sys_command_t),
.commands = sys_commands,
@@ -258,37 +306,38 @@ status_code_t system_execute_line (char *line)
};
status_code_t retval = Status_Unhandled;
char c, *org = line, *ucline = line, *lcline = line + (LINE_BUFFER_SIZE / 2);
// Uppercase original and copy original out in the buffer
// TODO: create a common function for stripping down uppercase version?
do {
c = *org++;
if(c != ' ') // Remove spaces from uppercase version
*ucline++ = CAPS(c);
*lcline++ = c;
} while(c);
char c, *s1, *s2;
lcline = line + (LINE_BUFFER_SIZE / 2);
s1 = s2 = ++line;
if(!strncmp(&line[1], "HELP", 4))
return report_help(&line[5], &lcline[5]);
char *args = strchr(line, '='), *lcargs = strchr(lcline, '=');
if(args) {
*args++ = '\0';
*lcargs++ = '\0';
c = *s1;
while(c && c != '=') {
if(c != ' ')
*s2++ = CAPS(c);
c = *++s1;
}
while((c = *s1++))
*s2++ = c;
*s2 = '\0';
if(!strncmp(line, "HELP", 4))
return report_help(&line[4]);
char *args = strchr(line, '=');
if(args)
*args++ = '\0';
uint_fast8_t idx;
sys_commands_t *cmd = &base;
do {
for(idx = 0; idx < cmd->n_commands; idx++) {
if(!strcmp(&line[1], cmd->commands[idx].command)) {
if(!cmd->commands[idx].noargs || lcargs == NULL) {
if((retval = cmd->commands[idx].execute(state_get(), lcargs)) != Status_Unhandled)
if(!strcmp(line, cmd->commands[idx].command)) {
if(!cmd->commands[idx].noargs || args == NULL) {
if((retval = cmd->commands[idx].execute(state_get(), args)) != Status_Unhandled)
break;
}
}
@@ -298,26 +347,26 @@ status_code_t system_execute_line (char *line)
// Let user code have a peek at system commands before check for global setting
if(retval == Status_Unhandled && grbl.on_unknown_sys_command) {
if(lcargs)
*(--lcargs) = '=';
if(args)
*(--args) = '=';
retval = grbl.on_unknown_sys_command(state_get(), lcline);
retval = grbl.on_unknown_sys_command(state_get(), line);
if(lcargs)
*lcargs++ = '\0';
if(args)
*args++ = '\0';
}
if (retval == Status_Unhandled) {
// Check for global setting, store if so
if(state_get() == STATE_IDLE || (state_get() & (STATE_ALARM|STATE_ESTOP|STATE_CHECK_MODE))) {
uint_fast8_t counter = 1;
uint_fast8_t counter = 0;
float parameter;
if(!read_float(line, &counter, &parameter))
retval = Status_BadNumberFormat;
else if(!isintf(parameter))
retval = Status_InvalidStatement;
else if(args)
retval = settings_store_setting((setting_id_t)parameter, lcargs);
retval = settings_store_setting((setting_id_t)parameter, args);
else
retval = report_grbl_setting((setting_id_t)parameter, NULL);
} else
@@ -339,7 +388,7 @@ static status_code_t jog (sys_state_t state, char *args)
args -= 2;
}
return args == NULL ? Status_InvalidStatement : gc_execute_block(strcaps(args), NULL); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
return args == NULL ? Status_InvalidStatement : gc_execute_block(args); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
}
static status_code_t enumerate_alarms (sys_state_t state, char *args)
@@ -536,7 +585,7 @@ static status_code_t disable_lock (sys_state_t state, char *args)
static status_code_t output_help (sys_state_t state, char *args)
{
return report_help(args, args);
return report_help(args);
}
static status_code_t go_home (sys_state_t state, axes_signals_t axes)
@@ -667,9 +716,19 @@ static status_code_t tool_probe_workpiece (sys_state_t state, char *args)
static status_code_t output_ngc_parameters (sys_state_t state, char *args)
{
report_ngc_parameters();
status_code_t retval = Status_OK;
return Status_OK;
if(args) {
int32_t id;
retval = read_int(args, &id);
if(retval == Status_OK && id >= 0)
retval = report_ngc_parameter((ngc_param_id_t)id);
else
retval = report_named_ngc_parameter(args);
} else
report_ngc_parameters();
return retval;
}
static status_code_t build_info (sys_state_t state, char *args)
@@ -781,11 +840,11 @@ static status_code_t set_startup_line (sys_state_t state, char *args, uint_fast8
status_code_t retval = Status_OK;
strcaps(args);
args = gc_normalize_block(args, NULL);
if(strlen(args) >= (sizeof(stored_line_t) - 1))
retval = Status_Overflow;
else if ((retval = gc_execute_block(args, NULL)) == Status_OK) // Execute gcode block to ensure block is valid.
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;
+4
View File
@@ -53,6 +53,7 @@ know when there is a realtime command to execute.
#define EXEC_GCODE_REPORT bit(11)
#define EXEC_TLO_REPORT bit(12)
#define EXEC_RT_COMMAND bit(13)
#define EXEC_DOOR_CLOSED bit(14)
///@}
//! \def sys_state
@@ -295,6 +296,9 @@ void system_apply_jog_limits (float *target);
//! Raise and report alarm state
void system_raise_alarm (alarm_code_t alarm);
//! Provide system command help
void system_command_help (void);
// Special handlers for setting and clearing Grbl's real-time execution flags.
#define system_set_exec_state_flag(mask) hal.set_bits_atomic(&sys.rt_exec_state, (mask))
#define system_clear_exec_state_flag(mask) hal.clear_bits_atomic(&sys.rt_exec_state, (mask))