Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Case-insensitive G-code option #16932

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2791,6 +2791,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.
Expand Down
21 changes: 14 additions & 7 deletions Marlin/src/gcode/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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, '*');
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
24 changes: 18 additions & 6 deletions Marlin/src/gcode/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ class GCodeParser {
#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;
Expand All @@ -177,35 +176,48 @@ class GCodeParser {

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;
}

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;
}

#endif // !FASTER_GCODE_PARSER

// 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)
Expand Down