Browse Source

Case-insensitive g-code option (#16932)

Scott Lahteine 4 years ago
parent
commit
832951ec44
No account linked to committer's email address
3 changed files with 34 additions and 13 deletions
  1. 2
    0
      Marlin/Configuration_adv.h
  2. 14
    7
      Marlin/src/gcode/parser.cpp
  3. 18
    6
      Marlin/src/gcode/parser.h

+ 2
- 0
Marlin/Configuration_adv.h View File

@@ -2790,6 +2790,8 @@
2790 2790
   //#define GCODE_QUOTED_STRINGS  // Support for quoted string parameters
2791 2791
 #endif
2792 2792
 
2793
+//#define GCODE_CASE_INSENSITIVE  // Accept G-code sent to the firmware in lowercase
2794
+
2793 2795
 /**
2794 2796
  * CNC G-code options
2795 2797
  * Support CNC-style G-code dialects used by laser cutters, drawing machine cams, etc.

+ 14
- 7
Marlin/src/gcode/parser.cpp View File

@@ -118,11 +118,18 @@ void GCodeParser::parse(char *p) {
118 118
 
119 119
   reset(); // No codes to report
120 120
 
121
+  auto uppercase = [](char c) {
122
+    #if ENABLED(GCODE_CASE_INSENSITIVE)
123
+      if (WITHIN(c, 'a', 'z')) c += 'A' - 'a';
124
+    #endif
125
+    return c;
126
+  };
127
+
121 128
   // Skip spaces
122 129
   while (*p == ' ') ++p;
123 130
 
124 131
   // Skip N[-0-9] if included in the command line
125
-  if (*p == 'N' && NUMERIC_SIGNED(p[1])) {
132
+  if (uppercase(*p) == 'N' && NUMERIC_SIGNED(p[1])) {
126 133
     #if ENABLED(FASTER_GCODE_PARSER)
127 134
       //set('N', p + 1);     // (optional) Set the 'N' parameter value
128 135
     #endif
@@ -135,7 +142,7 @@ void GCodeParser::parse(char *p) {
135 142
   command_ptr = p;
136 143
 
137 144
   // Get the command letter, which must be G, M, or T
138
-  const char letter = *p++;
145
+  const char letter = uppercase(*p++);
139 146
 
140 147
   // Nullify asterisk and trailing whitespace
141 148
   char *starpos = strchr(p, '*');
@@ -271,7 +278,7 @@ void GCodeParser::parse(char *p) {
271 278
     bool quoted_string_arg = false;
272 279
   #endif
273 280
   string_arg = nullptr;
274
-  while (const char param = *p++) {              // Get the next parameter. A NUL ends the loop
281
+  while (const char param = uppercase(*p++)) {  // Get the next parameter. A NUL ends the loop
275 282
 
276 283
     // Special handling for M32 [P] !/path/to/file.g#
277 284
     // The path must be the last parameter
@@ -289,14 +296,14 @@ void GCodeParser::parse(char *p) {
289 296
       }
290 297
     #endif
291 298
 
292
-    // Arguments MUST be uppercase for fast GCode parsing
293 299
     #if ENABLED(FASTER_GCODE_PARSER)
294
-      #define PARAM_TEST WITHIN(param, 'A', 'Z')
300
+      // Arguments MUST be uppercase for fast GCode parsing
301
+      #define PARAM_OK(P) WITHIN((P), 'A', 'Z')
295 302
     #else
296
-      #define PARAM_TEST true
303
+      #define PARAM_OK(P) true
297 304
     #endif
298 305
 
299
-    if (PARAM_TEST) {
306
+    if (PARAM_OK(param)) {
300 307
 
301 308
       while (*p == ' ') p++;                    // Skip spaces between parameters & values
302 309
 

+ 18
- 6
Marlin/src/gcode/parser.h View File

@@ -166,7 +166,6 @@ public:
166 166
     #ifdef CPU_32_BIT
167 167
       FORCE_INLINE static bool seen(const char * const str) { return !!(codebits & letter_bits(str)); }
168 168
     #else
169
-      // At least one of a list of code letters was seen
170 169
       FORCE_INLINE static bool seen(const char * const str) {
171 170
         const uint32_t letrbits = letter_bits(str);
172 171
         const uint8_t * const cb = (uint8_t*)&codebits;
@@ -177,14 +176,27 @@ public:
177 176
 
178 177
     static inline bool seen_any() { return !!codebits; }
179 178
 
180
-    #define SEEN_TEST(L) TEST32(codebits, LETTER_BIT(L))
179
+    FORCE_INLINE static bool seen_test(const char c) { return TEST32(codebits, LETTER_BIT(c)); }
181 180
 
182 181
   #else // !FASTER_GCODE_PARSER
183 182
 
183
+    #if ENABLED(GCODE_CASE_INSENSITIVE)
184
+      FORCE_INLINE static char* strgchr(char *p, char g) {
185
+        auto uppercase = [](char c) {
186
+          return c + (WITHIN(c, 'a', 'z') ? 'A' - 'a' : 0);
187
+        };
188
+        const char d = uppercase(g);
189
+        for (char cc; (cc = uppercase(*p)); p++) if (cc == d) return p;
190
+        return nullptr;
191
+      }
192
+    #else
193
+      #define strgchr strchr
194
+    #endif
195
+
184 196
     // Code is found in the string. If not found, value_ptr is unchanged.
185 197
     // This allows "if (seen('A')||seen('B'))" to use the last-found value.
186 198
     static inline bool seen(const char c) {
187
-      char *p = strchr(command_args, c);
199
+      char *p = strgchr(command_args, c);
188 200
       const bool b = !!p;
189 201
       if (b) value_ptr = valid_float(&p[1]) ? &p[1] : nullptr;
190 202
       return b;
@@ -192,12 +204,12 @@ public:
192 204
 
193 205
     static inline bool seen_any() { return *command_args == '\0'; }
194 206
 
195
-    #define SEEN_TEST(L) !!strchr(command_args, L)
207
+    FORCE_INLINE static bool seen_test(const char c) { return (bool)strgchr(command_args, c); }
196 208
 
197 209
     // At least one of a list of code letters was seen
198 210
     static inline bool seen(const char * const str) {
199 211
       for (uint8_t i = 0; const char c = str[i]; i++)
200
-        if (SEEN_TEST(c)) return true;
212
+        if (seen_test(c)) return true;
201 213
       return false;
202 214
     }
203 215
 
@@ -205,7 +217,7 @@ public:
205 217
 
206 218
   // Seen any axis parameter
207 219
   static inline bool seen_axis() {
208
-    return SEEN_TEST('X') || SEEN_TEST('Y') || SEEN_TEST('Z') || SEEN_TEST('E');
220
+    return seen_test('X') || seen_test('Y') || seen_test('Z') || seen_test('E');
209 221
   }
210 222
 
211 223
   #if ENABLED(GCODE_QUOTED_STRINGS)

Loading…
Cancel
Save