Prusa MINI Firmware overview
GCodeParser Class Reference

#include <parser.h>

Collaboration diagram for GCodeParser:

Public Member Functions

void unknown_command_error ()
 

Static Public Member Functions

static void reset ()
 
static FORCE_INLINE bool valid_signless (const char *const p)
 
static FORCE_INLINE bool valid_float (const char *const p)
 
static bool seen (const char c)
 
static bool seen_any ()
 
static bool seen (const char *const str)
 
static bool seen_axis ()
 
static void parse (char *p)
 
static FORCE_INLINE bool has_value ()
 
static bool seenval (const char c)
 
static float value_float ()
 
static int32_t value_long ()
 
static uint32_t value_ulong ()
 
static millis_t value_millis ()
 
static millis_t value_millis_from_seconds ()
 
static int16_t value_int ()
 
static uint16_t value_ushort ()
 
static uint8_t value_byte ()
 
static bool value_bool ()
 
static float mm_to_linear_unit (const float mm)
 
static float mm_to_volumetric_unit (const float mm)
 
static float linear_value_to_mm (const float v)
 
static float axis_value_to_mm (const AxisEnum, const float v)
 
static float per_axis_value (const AxisEnum, const float v)
 
static float value_linear_units ()
 
static float value_axis_units (const AxisEnum axis)
 
static float value_per_axis_units (const AxisEnum axis)
 
static float value_celsius ()
 
static float value_celsius_diff ()
 
static feedRate_t value_feedrate ()
 
static float floatval (const char c, const float dval=0.0)
 
static bool boolval (const char c, const bool dval=false)
 
static uint8_t byteval (const char c, const uint8_t dval=0)
 
static int16_t intval (const char c, const int16_t dval=0)
 
static uint16_t ushortval (const char c, const uint16_t dval=0)
 
static int32_t longval (const char c, const int32_t dval=0)
 
static uint32_t ulongval (const char c, const uint32_t dval=0)
 
static float linearval (const char c, const float dval=0)
 
static float celsiusval (const char c, const float dval=0)
 

Static Public Attributes

static bool volumetric_enabled
 
static char * command_ptr
 
static char * string_arg
 
static char command_letter
 
static int codenum
 
static uint8_t subcode
 

Detailed Description

Marlin 3D Printer Firmware Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]

Based on Sprinter and grbl. Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm

This program 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.

This program 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 this program. If not, see http://www.gnu.org/licenses/. parser.h - Parser for a GCode line, providing a parameter interface. Codes like M149 control the way the GCode parser behaves, so settings for these codes are located in this class. GCode parser

  • Parse a single gcode line for its letter, code, subcode, and parameters
  • FASTER_GCODE_PARSER:
    • Flags existing params (1 bit each)
    • Stores value offsets (1 byte each)
  • Provide accessors for parameters:
    • Parameter exists
    • Parameter has value
    • Parameter value in different units and types

Member Function Documentation

◆ reset()

void GCodeParser::reset ( )
static

Clear all code-seen (and value pointers)

Since each param is set/cleared on seen codes, this may be optimized by commenting out ZERO(param)

82  {
83  string_arg = nullptr; // No whole line argument
84  command_letter = '?'; // No command letter
85  codenum = 0; // No command code
86  #if USE_GCODE_SUBCODES
87  subcode = 0; // No command sub-code
88  #endif
89  #if ENABLED(FASTER_GCODE_PARSER)
90  codebits = 0; // No codes yet
91  //ZERO(param); // No parameters (should be safe to comment out this line)
92  #endif
93 }
Here is the caller graph for this function:

◆ valid_signless()

static FORCE_INLINE bool GCodeParser::valid_signless ( const char *const  p)
static
109  {
110  return NUMERIC(p[0]) || (p[0] == '.' && NUMERIC(p[1])); // .?[0-9]
111  }
Here is the caller graph for this function:

◆ valid_float()

static FORCE_INLINE bool GCodeParser::valid_float ( const char *const  p)
static
113  {
114  return valid_signless(p) || ((p[0] == '-' || p[0] == '+') && valid_signless(&p[1])); // [-+]?.?[0-9]
115  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seen() [1/2]

static bool GCodeParser::seen ( const char  c)
static
186  {
187  char *p = strchr(command_args, c);
188  const bool b = !!p;
189  if (b) value_ptr = valid_float(&p[1]) ? &p[1] : nullptr;
190  return b;
191  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seen_any()

static bool GCodeParser::seen_any ( )
static
193 { return *command_args == '\0'; }

◆ seen() [2/2]

static bool GCodeParser::seen ( const char *const  str)
static
198  {
199  for (uint8_t i = 0; const char c = str[i]; i++)
200  if (SEEN_TEST(c)) return true;
201  return false;
202  }

◆ seen_axis()

static bool GCodeParser::seen_axis ( )
static
207  {
208  return SEEN_TEST('X') || SEEN_TEST('Y') || SEEN_TEST('Z') || SEEN_TEST('E');
209  }

◆ parse()

void GCodeParser::parse ( char *  p)
static

Find all parameters, set flags and pointers for fast parsing

Most codes ignore 'string_arg', but those that want a string will get the right pointer. The following loop assigns the first "parameter" having no numeric value to 'string_arg'. This allows M0/M1 with expire time to work: "M0 S5 You Win!" For 'M118' you must use 'E1' and 'A1' rather than just 'E' or 'A'

97  {
98 
99  reset(); // No codes to report
100 
101  // Skip spaces
102  while (*p == ' ') ++p;
103 
104  // Skip N[-0-9] if included in the command line
105  if (*p == 'N' && NUMERIC_SIGNED(p[1])) {
106  #if ENABLED(FASTER_GCODE_PARSER)
107  //set('N', p + 1); // (optional) Set the 'N' parameter value
108  #endif
109  p += 2; // skip N[-0-9]
110  while (NUMERIC(*p)) ++p; // skip [0-9]*
111  while (*p == ' ') ++p; // skip [ ]*
112  }
113 
114  // *p now points to the current command, which should be G, M, or T
115  command_ptr = p;
116 
117  // Get the command letter, which must be G, M, or T
118  const char letter = *p++;
119 
120  // Nullify asterisk and trailing whitespace
121  char *starpos = strchr(p, '*');
122  if (starpos) {
123  --starpos; // *
124  while (*starpos == ' ') --starpos; // spaces...
125  starpos[1] = '\0';
126  }
127 
128  #if ENABLED(GCODE_MOTION_MODES)
129  #if ENABLED(ARC_SUPPORT)
130  #define GTOP 3
131  #else
132  #define GTOP 1
133  #endif
134  #endif
135 
136  // Bail if the letter is not G, M, or T
137  // (or a valid parameter for the current motion mode)
138  switch (letter) {
139 
140  case 'G': case 'M': case 'T':
141 
142  // Skip spaces to get the numeric part
143  while (*p == ' ') p++;
144 
145  #if ENABLED(PRUSA_MMU2)
146  if (letter == 'T') {
147  // check for special MMU2 T?/Tx/Tc commands
148  if (*p == '?' || *p == 'x' || *p == 'c') {
149  command_letter = letter;
150  string_arg = p;
151  return;
152  }
153  }
154  #endif
155 
156  // Bail if there's no command code number
157  if (!NUMERIC(*p)) return;
158 
159  // Save the command letter at this point
160  // A '?' signifies an unknown command
161  command_letter = letter;
162 
163  // Get the code number - integer digits only
164  codenum = 0;
165  do { codenum *= 10, codenum += *p++ - '0'; } while (NUMERIC(*p));
166 
167  // Allow for decimal point in command
168  #if USE_GCODE_SUBCODES
169  if (*p == '.') {
170  p++;
171  while (NUMERIC(*p))
172  subcode *= 10, subcode += *p++ - '0';
173  }
174  #endif
175 
176  // Skip all spaces to get to the first argument, or nul
177  while (*p == ' ') p++;
178 
179  #if ENABLED(GCODE_MOTION_MODES)
180  if (letter == 'G' && (codenum <= GTOP || codenum == 5
181  #if ENABLED(G38_PROBE_TARGET)
182  || codenum == 38
183  #endif
184  )
185  ) {
186  motion_mode_codenum = codenum;
187  #if USE_GCODE_SUBCODES
188  motion_mode_subcode = subcode;
189  #endif
190  }
191  #endif
192 
193  break;
194 
195  #if ENABLED(GCODE_MOTION_MODES)
196  #if ENABLED(ARC_SUPPORT)
197  case 'I': case 'J': case 'R':
198  if (motion_mode_codenum != 2 && motion_mode_codenum != 3) return;
199  #endif
200  case 'P': case 'Q':
201  if (motion_mode_codenum != 5) return;
202  case 'X': case 'Y': case 'Z': case 'E': case 'F':
203  if (motion_mode_codenum < 0) return;
204  command_letter = 'G';
205  codenum = motion_mode_codenum;
206  #if USE_GCODE_SUBCODES
207  subcode = motion_mode_subcode;
208  #endif
209  p--; // Back up one character to use the current parameter
210  break;
211  #endif // GCODE_MOTION_MODES
212 
213  default: return;
214  }
215 
216  // The command parameters (if any) start here, for sure!
217 
218  #if DISABLED(FASTER_GCODE_PARSER)
219  command_args = p; // Scan for parameters in seen()
220  #endif
221 
222  // Only use string_arg for these M codes
223  if (letter == 'M') switch (codenum) {
224  #if ENABLED(GCODE_MACROS)
225  case 810 ... 819:
226  #endif
227  #if ENABLED(EXPECTED_PRINTER_CHECK)
228  case 16:
229  #endif
230  case 23: case 28: case 30: case 117: case 118: case 928: string_arg = p; return;
231  default: break;
232  }
233 
234  #if ENABLED(DEBUG_GCODE_PARSER)
235  const bool debug = codenum == 800;
236  #endif
237 
238  /**
239  * Find all parameters, set flags and pointers for fast parsing
240  *
241  * Most codes ignore 'string_arg', but those that want a string will get the right pointer.
242  * The following loop assigns the first "parameter" having no numeric value to 'string_arg'.
243  * This allows M0/M1 with expire time to work: "M0 S5 You Win!"
244  * For 'M118' you must use 'E1' and 'A1' rather than just 'E' or 'A'
245  */
246  string_arg = nullptr;
247  while (const char code = *p++) { // Get the next parameter. A NUL ends the loop
248 
249  // Special handling for M32 [P] !/path/to/file.g#
250  // The path must be the last parameter
251  if (code == '!' && letter == 'M' && codenum == 32) {
252  string_arg = p; // Name starts after '!'
253  char * const lb = strchr(p, '#'); // Already seen '#' as SD char (to pause buffering)
254  if (lb) *lb = '\0'; // Safe to mark the end of the filename
255  return;
256  }
257 
258  // Arguments MUST be uppercase for fast GCode parsing
259  #if ENABLED(FASTER_GCODE_PARSER)
260  #define PARAM_TEST WITHIN(code, 'A', 'Z')
261  #else
262  #define PARAM_TEST true
263  #endif
264 
265  if (PARAM_TEST) {
266 
267  while (*p == ' ') p++; // Skip spaces between parameters & values
268 
269  const bool has_num = valid_float(p);
270 
271  #if ENABLED(DEBUG_GCODE_PARSER)
272  if (debug) {
273  SERIAL_ECHOPAIR("Got letter ", code, " at index ", (int)(p - command_ptr - 1));
274  if (has_num) SERIAL_ECHOPGM(" (has_num)");
275  }
276  #endif
277 
278  if (!has_num && !string_arg) { // No value? First time, keep as string_arg
279  string_arg = p - 1;
280  #if ENABLED(DEBUG_GCODE_PARSER)
281  if (debug) SERIAL_ECHOPAIR(" string_arg: ", hex_address((void*)string_arg)); // DEBUG
282  #endif
283  }
284 
285  #if ENABLED(DEBUG_GCODE_PARSER)
286  if (debug) SERIAL_EOL();
287  #endif
288 
289  #if ENABLED(FASTER_GCODE_PARSER)
290  set(code, has_num ? p : nullptr); // Set parameter exists and pointer (nullptr for no number)
291  #endif
292  }
293  else if (!string_arg) { // Not A-Z? First time, keep as the string_arg
294  string_arg = p - 1;
295  #if ENABLED(DEBUG_GCODE_PARSER)
296  if (debug) SERIAL_ECHOPAIR(" string_arg: ", hex_address((void*)string_arg)); // DEBUG
297  #endif
298  }
299 
300  if (!WITHIN(*p, 'A', 'Z')) { // Another parameter right away?
301  while (*p && DECIMAL_SIGNED(*p)) p++; // Skip over the value section of a parameter
302  while (*p == ' ') p++; // Skip over all spaces
303  }
304  }
305 }
Here is the call graph for this function:

◆ has_value()

static FORCE_INLINE bool GCodeParser::has_value ( )
static
221 { return value_ptr != nullptr; }
Here is the caller graph for this function:

◆ seenval()

static bool GCodeParser::seenval ( const char  c)
static
224 { return seen(c) && has_value(); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_float()

static float GCodeParser::value_float ( )
static
227  {
228  if (value_ptr) {
229  char *e = value_ptr;
230  for (;;) {
231  const char c = *e;
232  if (c == '\0' || c == ' ') break;
233  if (c == 'E' || c == 'e') {
234  *e = '\0';
235  const float ret = strtof(value_ptr, nullptr);
236  *e = c;
237  return ret;
238  }
239  ++e;
240  }
241  return strtof(value_ptr, nullptr);
242  }
243  return 0;
244  }
Here is the caller graph for this function:

◆ value_long()

static int32_t GCodeParser::value_long ( )
static
247 { return value_ptr ? strtol(value_ptr, nullptr, 10) : 0L; }
Here is the caller graph for this function:

◆ value_ulong()

static uint32_t GCodeParser::value_ulong ( )
static
248 { return value_ptr ? strtoul(value_ptr, nullptr, 10) : 0UL; }
Here is the caller graph for this function:

◆ value_millis()

static millis_t GCodeParser::value_millis ( )
static
251 { return value_ulong(); }
Here is the call graph for this function:

◆ value_millis_from_seconds()

static millis_t GCodeParser::value_millis_from_seconds ( )
static
252 { return (millis_t)(value_float() * 1000); }
Here is the call graph for this function:

◆ value_int()

static int16_t GCodeParser::value_int ( )
static
255 { return (int16_t)value_long(); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_ushort()

static uint16_t GCodeParser::value_ushort ( )
static
256 { return (uint16_t)value_long(); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_byte()

static uint8_t GCodeParser::value_byte ( )
static
257 { return (uint8_t)constrain(value_long(), 0, 255); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_bool()

static bool GCodeParser::value_bool ( )
static
260 { return !has_value() || !!value_byte(); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mm_to_linear_unit()

static float GCodeParser::mm_to_linear_unit ( const float  mm)
static
290 { return mm; }

◆ mm_to_volumetric_unit()

static float GCodeParser::mm_to_volumetric_unit ( const float  mm)
static
291 { return mm; }

◆ linear_value_to_mm()

static float GCodeParser::linear_value_to_mm ( const float  v)
static
293 { return v; }
Here is the caller graph for this function:

◆ axis_value_to_mm()

static float GCodeParser::axis_value_to_mm ( const  AxisEnum,
const float  v 
)
static
294 { return v; }
Here is the caller graph for this function:

◆ per_axis_value()

static float GCodeParser::per_axis_value ( const  AxisEnum,
const float  v 
)
static
295 { return v; }
Here is the caller graph for this function:

◆ value_linear_units()

static float GCodeParser::value_linear_units ( )
static
302 { return linear_value_to_mm(value_float()); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_axis_units()

static float GCodeParser::value_axis_units ( const AxisEnum  axis)
static
303 { return axis_value_to_mm(axis, value_float()); }
Here is the call graph for this function:

◆ value_per_axis_units()

static float GCodeParser::value_per_axis_units ( const AxisEnum  axis)
static
304 { return per_axis_value(axis, value_float()); }
Here is the call graph for this function:

◆ value_celsius()

static float GCodeParser::value_celsius ( )
static
360 { return value_float(); }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_celsius_diff()

static float GCodeParser::value_celsius_diff ( )
static
361 { return value_float(); }
Here is the call graph for this function:

◆ value_feedrate()

static feedRate_t GCodeParser::value_feedrate ( )
static
367 { return MMM_TO_MMS(value_linear_units()); }
Here is the call graph for this function:

◆ unknown_command_error()

void GCodeParser::unknown_command_error ( )
327  {
330 }

◆ floatval()

static float GCodeParser::floatval ( const char  c,
const float  dval = 0.0 
)
static
372 { return seenval(c) ? value_float() : dval; }
Here is the call graph for this function:

◆ boolval()

static bool GCodeParser::boolval ( const char  c,
const bool  dval = false 
)
static
373 { return seenval(c) ? value_bool() : (seen(c) ? true : dval); }
Here is the call graph for this function:

◆ byteval()

static uint8_t GCodeParser::byteval ( const char  c,
const uint8_t  dval = 0 
)
static
374 { return seenval(c) ? value_byte() : dval; }
Here is the call graph for this function:

◆ intval()

static int16_t GCodeParser::intval ( const char  c,
const int16_t  dval = 0 
)
static
375 { return seenval(c) ? value_int() : dval; }
Here is the call graph for this function:

◆ ushortval()

static uint16_t GCodeParser::ushortval ( const char  c,
const uint16_t  dval = 0 
)
static
376 { return seenval(c) ? value_ushort() : dval; }
Here is the call graph for this function:

◆ longval()

static int32_t GCodeParser::longval ( const char  c,
const int32_t  dval = 0 
)
static
377 { return seenval(c) ? value_long() : dval; }
Here is the call graph for this function:

◆ ulongval()

static uint32_t GCodeParser::ulongval ( const char  c,
const uint32_t  dval = 0 
)
static
378 { return seenval(c) ? value_ulong() : dval; }
Here is the call graph for this function:

◆ linearval()

static float GCodeParser::linearval ( const char  c,
const float  dval = 0 
)
static
379 { return seenval(c) ? value_linear_units() : dval; }
Here is the call graph for this function:

◆ celsiusval()

static float GCodeParser::celsiusval ( const char  c,
const float  dval = 0 
)
static
380 { return seenval(c) ? value_celsius() : dval; }
Here is the call graph for this function:

Member Data Documentation

◆ volumetric_enabled

bool GCodeParser::volumetric_enabled
static

Marlin 3D Printer Firmware Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]

Based on Sprinter and grbl. Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm

This program 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.

This program 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 this program. If not, see http://www.gnu.org/licenses/. parser.cpp - Parser for a GCode line, providing a parameter interface.

◆ command_ptr

char * GCodeParser::command_ptr
static

◆ string_arg

char * GCodeParser::string_arg
static

◆ command_letter

char GCodeParser::command_letter
static

◆ codenum

int GCodeParser::codenum
static

◆ subcode

uint8_t GCodeParser::subcode
static
WITHIN
#define WITHIN(N, L, H)
Definition: macros.h:195
GCodeParser::value_int
static int16_t value_int()
Definition: parser.h:255
GCodeParser::command_letter
static char command_letter
Definition: parser.h:84
NUMERIC
#define NUMERIC(a)
Definition: macros.h:196
GCodeParser::per_axis_value
static float per_axis_value(const AxisEnum, const float v)
Definition: parser.h:295
GCodeParser::valid_signless
static FORCE_INLINE bool valid_signless(const char *const p)
Definition: parser.h:109
PARAM_TEST
#define PARAM_TEST
SERIAL_ECHOPAIR
#define SERIAL_ECHOPAIR(V...)
Definition: serial.h:114
SEEN_TEST
#define SEEN_TEST(L)
Definition: parser.h:195
GCodeParser::value_long
static int32_t value_long()
Definition: parser.h:247
i
uint8_t i
Definition: screen_test_graph.c:72
GCodeParser::seenval
static bool seenval(const char c)
Definition: parser.h:224
GCodeParser::linear_value_to_mm
static float linear_value_to_mm(const float v)
Definition: parser.h:293
SERIAL_ECHO_START
#define SERIAL_ECHO_START()
Definition: serial.h:179
strtof
#define strtof
Definition: HAL.h:374
GCodeParser::valid_float
static FORCE_INLINE bool valid_float(const char *const p)
Definition: parser.h:113
GCodeParser::codenum
static int codenum
Definition: parser.h:87
GCodeParser::has_value
static FORCE_INLINE bool has_value()
Definition: parser.h:221
GCodeParser::subcode
static uint8_t subcode
Definition: parser.h:89
GCodeParser::value_float
static float value_float()
Definition: parser.h:227
constrain
#define constrain(amt, low, high)
Definition: wiring_constants.h:79
GCodeParser::reset
static void reset()
Definition: parser.cpp:82
SERIAL_ECHOPGM
#define SERIAL_ECHOPGM(S)
Definition: serial.h:173
GCodeParser::value_ulong
static uint32_t value_ulong()
Definition: parser.h:248
SERIAL_ECHOLNPAIR
#define SERIAL_ECHOLNPAIR(V...)
Definition: serial.h:144
L
#define L(CODE)
Definition: macros.h:76
uint8_t
const uint8_t[]
Definition: 404_html.c:3
MSG_UNKNOWN_COMMAND
#define MSG_UNKNOWN_COMMAND
Definition: language.h:182
GCodeParser::string_arg
static char * string_arg
Definition: parser.h:84
NUMERIC_SIGNED
#define NUMERIC_SIGNED(a)
Definition: macros.h:198
GCodeParser::value_celsius
static float value_celsius()
Definition: parser.h:360
GCodeParser::value_bool
static bool value_bool()
Definition: parser.h:260
DECIMAL_SIGNED
#define DECIMAL_SIGNED(a)
Definition: macros.h:199
GCodeParser::seen
static bool seen(const char c)
Definition: parser.h:186
GCodeParser::value_linear_units
static float value_linear_units()
Definition: parser.h:302
GCodeParser::command_ptr
static char * command_ptr
Definition: parser.h:84
SERIAL_EOL
#define SERIAL_EOL()
Definition: serial.h:181
MMM_TO_MMS
#define MMM_TO_MMS(MM_M)
Definition: types.h:83
GCodeParser::axis_value_to_mm
static float axis_value_to_mm(const AxisEnum, const float v)
Definition: parser.h:294
hex_address
char * hex_address(const void *const w)
Definition: hex_print_routines.cpp:67
code
Definition: inftrees.h:24
GCodeParser::value_ushort
static uint16_t value_ushort()
Definition: parser.h:256
createSpeedLookupTable.b
list b
Definition: createSpeedLookupTable.py:30
GCodeParser::value_byte
static uint8_t value_byte()
Definition: parser.h:257
millis_t
uint32_t millis_t
Definition: millis_t.h:26
ENABLED
#define ENABLED(V...)
Definition: macros.h:177