From 832951ec4493da96772386f1177a34ff9c936aee Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Wed, 26 Feb 2020 09:23:55 -0600 Subject: [PATCH] Case-insensitive g-code option (#16932) --- Marlin/Configuration_adv.h | 2 ++ Marlin/src/gcode/parser.cpp | 21 ++++++++++++++------- Marlin/src/gcode/parser.h | 24 ++++++++++++++++++------ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index c9e226cef4..ede35a561e 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2790,6 +2790,8 @@ //#define GCODE_QUOTED_STRINGS // Support for quoted string parameters #endif +//#define GCODE_CASE_INSENSITIVE // Accept G-code sent to the firmware in lowercase + /** * CNC G-code options * Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc. diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 5a473403a3..0fac65300f 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -118,11 +118,18 @@ void GCodeParser::parse(char *p) { reset(); // No codes to report + auto uppercase = [](char c) { + #if ENABLED(GCODE_CASE_INSENSITIVE) + if (WITHIN(c, 'a', 'z')) c += 'A' - 'a'; + #endif + return c; + }; + // Skip spaces while (*p == ' ') ++p; // Skip N[-0-9] if included in the command line - if (*p == 'N' && NUMERIC_SIGNED(p[1])) { + if (uppercase(*p) == 'N' && NUMERIC_SIGNED(p[1])) { #if ENABLED(FASTER_GCODE_PARSER) //set('N', p + 1); // (optional) Set the 'N' parameter value #endif @@ -135,7 +142,7 @@ void GCodeParser::parse(char *p) { command_ptr = p; // Get the command letter, which must be G, M, or T - const char letter = *p++; + const char letter = uppercase(*p++); // Nullify asterisk and trailing whitespace char *starpos = strchr(p, '*'); @@ -271,7 +278,7 @@ void GCodeParser::parse(char *p) { bool quoted_string_arg = false; #endif string_arg = nullptr; - while (const char param = *p++) { // Get the next parameter. A NUL ends the loop + while (const char param = uppercase(*p++)) { // Get the next parameter. A NUL ends the loop // Special handling for M32 [P] !/path/to/file.g# // The path must be the last parameter @@ -289,14 +296,14 @@ void GCodeParser::parse(char *p) { } #endif - // Arguments MUST be uppercase for fast GCode parsing #if ENABLED(FASTER_GCODE_PARSER) - #define PARAM_TEST WITHIN(param, 'A', 'Z') + // Arguments MUST be uppercase for fast GCode parsing + #define PARAM_OK(P) WITHIN((P), 'A', 'Z') #else - #define PARAM_TEST true + #define PARAM_OK(P) true #endif - if (PARAM_TEST) { + if (PARAM_OK(param)) { while (*p == ' ') p++; // Skip spaces between parameters & values diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 70eb85e31e..7c5e1518b3 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -166,7 +166,6 @@ public: #ifdef CPU_32_BIT FORCE_INLINE static bool seen(const char * const str) { return !!(codebits & letter_bits(str)); } #else - // At least one of a list of code letters was seen FORCE_INLINE static bool seen(const char * const str) { const uint32_t letrbits = letter_bits(str); const uint8_t * const cb = (uint8_t*)&codebits; @@ -177,14 +176,27 @@ public: static inline bool seen_any() { return !!codebits; } - #define SEEN_TEST(L) TEST32(codebits, LETTER_BIT(L)) + FORCE_INLINE static bool seen_test(const char c) { return TEST32(codebits, LETTER_BIT(c)); } #else // !FASTER_GCODE_PARSER + #if ENABLED(GCODE_CASE_INSENSITIVE) + FORCE_INLINE static char* strgchr(char *p, char g) { + auto uppercase = [](char c) { + return c + (WITHIN(c, 'a', 'z') ? 'A' - 'a' : 0); + }; + const char d = uppercase(g); + for (char cc; (cc = uppercase(*p)); p++) if (cc == d) return p; + return nullptr; + } + #else + #define strgchr strchr + #endif + // Code is found in the string. If not found, value_ptr is unchanged. // This allows "if (seen('A')||seen('B'))" to use the last-found value. static inline bool seen(const char c) { - char *p = strchr(command_args, c); + char *p = strgchr(command_args, c); const bool b = !!p; if (b) value_ptr = valid_float(&p[1]) ? &p[1] : nullptr; return b; @@ -192,12 +204,12 @@ public: static inline bool seen_any() { return *command_args == '\0'; } - #define SEEN_TEST(L) !!strchr(command_args, L) + FORCE_INLINE static bool seen_test(const char c) { return (bool)strgchr(command_args, c); } // At least one of a list of code letters was seen static inline bool seen(const char * const str) { for (uint8_t i = 0; const char c = str[i]; i++) - if (SEEN_TEST(c)) return true; + if (seen_test(c)) return true; return false; } @@ -205,7 +217,7 @@ public: // Seen any axis parameter static inline bool seen_axis() { - return SEEN_TEST('X') || SEEN_TEST('Y') || SEEN_TEST('Z') || SEEN_TEST('E'); + return seen_test('X') || seen_test('Y') || seen_test('Z') || seen_test('E'); } #if ENABLED(GCODE_QUOTED_STRINGS)