Browse Source

Merge pull request #2113 from thinkyhead/command_sanitizer

Command sanitizer
Scott Lahteine 10 years ago
parent
commit
4d11b29959
1 changed files with 118 additions and 122 deletions
  1. 118
    122
      Marlin/Marlin_main.cpp

+ 118
- 122
Marlin/Marlin_main.cpp View File

141
  * M112 - Emergency stop
141
  * M112 - Emergency stop
142
  * M114 - Output current position to serial port
142
  * M114 - Output current position to serial port
143
  * M115 - Capabilities string
143
  * M115 - Capabilities string
144
- * M117 - display message
144
+ * M117 - Display a message on the controller screen
145
  * M119 - Output Endstop status to serial port
145
  * M119 - Output Endstop status to serial port
146
  * M120 - Enable endstop detection
146
  * M120 - Enable endstop detection
147
  * M121 - Disable endstop detection
147
  * M121 - Disable endstop detection
236
 
236
 
237
 static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
237
 static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
238
 
238
 
239
+static char *current_command, *current_command_args;
239
 static int cmd_queue_index_r = 0;
240
 static int cmd_queue_index_r = 0;
240
 static int cmd_queue_index_w = 0;
241
 static int cmd_queue_index_w = 0;
241
 static int commands_in_queue = 0;
242
 static int commands_in_queue = 0;
265
 static char serial_char;
266
 static char serial_char;
266
 static int serial_count = 0;
267
 static int serial_count = 0;
267
 static boolean comment_mode = false;
268
 static boolean comment_mode = false;
268
-static char *strchr_pointer; ///< A pointer to find chars in the command string (X, Y, Z, E, etc.)
269
+static char *seen_pointer; ///< A pointer to find chars in the command string (X, Y, Z, E, etc.)
269
 const char* queued_commands_P= NULL; /* pointer to the current line in the active sequence of commands, or NULL when none */
270
 const char* queued_commands_P= NULL; /* pointer to the current line in the active sequence of commands, or NULL when none */
270
 const int sensitive_pins[] = SENSITIVE_PINS; ///< Sensitive pin list for M42
271
 const int sensitive_pins[] = SENSITIVE_PINS; ///< Sensitive pin list for M42
271
 // Inactivity shutdown
272
 // Inactivity shutdown
785
         fromsd[cmd_queue_index_w] = false;
786
         fromsd[cmd_queue_index_w] = false;
786
       #endif
787
       #endif
787
 
788
 
788
-      if (strchr(command, 'N') != NULL) {
789
-        strchr_pointer = strchr(command, 'N');
790
-        gcode_N = (strtol(strchr_pointer + 1, NULL, 10));
789
+      char *npos = strchr(command, 'N');
790
+      char *apos = strchr(command, '*');
791
+      if (npos) {
792
+        gcode_N = strtol(npos + 1, NULL, 10);
791
         if (gcode_N != gcode_LastN + 1 && strstr_P(command, PSTR("M110")) == NULL) {
793
         if (gcode_N != gcode_LastN + 1 && strstr_P(command, PSTR("M110")) == NULL) {
792
           gcode_line_error(PSTR(MSG_ERR_LINE_NO));
794
           gcode_line_error(PSTR(MSG_ERR_LINE_NO));
793
           return;
795
           return;
794
         }
796
         }
795
 
797
 
796
-        if (strchr(command, '*') != NULL) {
797
-          byte checksum = 0;
798
-          byte count = 0;
798
+        if (apos) {
799
+          byte checksum = 0, count = 0;
799
           while (command[count] != '*') checksum ^= command[count++];
800
           while (command[count] != '*') checksum ^= command[count++];
800
-          strchr_pointer = strchr(command, '*');
801
 
801
 
802
-          if (strtol(strchr_pointer + 1, NULL, 10) != checksum) {
802
+          if (strtol(apos + 1, NULL, 10) != checksum) {
803
             gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH));
803
             gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH));
804
             return;
804
             return;
805
           }
805
           }
813
         gcode_LastN = gcode_N;
813
         gcode_LastN = gcode_N;
814
         // if no errors, continue parsing
814
         // if no errors, continue parsing
815
       }
815
       }
816
-      else {  // if we don't receive 'N' but still see '*'
817
-        if ((strchr(command, '*') != NULL)) {
818
-          gcode_line_error(PSTR(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM), false);
819
-          return;
820
-        }
816
+      else if (apos) { // No '*' without 'N'
817
+        gcode_line_error(PSTR(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM), false);
818
+        return;
821
       }
819
       }
822
 
820
 
823
-      if (strchr(command, 'G') != NULL) {
824
-        strchr_pointer = strchr(command, 'G');
825
-        switch (strtol(strchr_pointer + 1, NULL, 10)) {
826
-          case 0:
827
-          case 1:
828
-          case 2:
829
-          case 3:
830
-            if (IsStopped()) {
821
+      // Movement commands alert when stopped
822
+      if (IsStopped()) {
823
+        char *gpos = strchr(command, 'G');
824
+        if (gpos) {
825
+          int codenum = strtol(gpos + 1, NULL, 10);
826
+          switch (codenum) {
827
+            case 0:
828
+            case 1:
829
+            case 2:
830
+            case 3:
831
               SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
831
               SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
832
               LCD_MESSAGEPGM(MSG_STOPPED);
832
               LCD_MESSAGEPGM(MSG_STOPPED);
833
-            }
834
-            break;
835
-          default:
836
-            break;
837
-        }
833
+              break;
834
+          }
835
+        }        
838
       }
836
       }
839
 
837
 
840
       // If command was e-stop process now
838
       // If command was e-stop process now
916
 
914
 
917
 bool code_has_value() {
915
 bool code_has_value() {
918
   int i = 1;
916
   int i = 1;
919
-  char c = strchr_pointer[i];
920
-  if (c == '-' || c == '+') c = strchr_pointer[++i];
921
-  if (c == '.') c = strchr_pointer[++i];
917
+  char c = seen_pointer[i];
918
+  if (c == '-' || c == '+') c = seen_pointer[++i];
919
+  if (c == '.') c = seen_pointer[++i];
922
   return (c >= '0' && c <= '9');
920
   return (c >= '0' && c <= '9');
923
 }
921
 }
924
 
922
 
925
 float code_value() {
923
 float code_value() {
926
   float ret;
924
   float ret;
927
-  char *e = strchr(strchr_pointer, 'E');
925
+  char *e = strchr(seen_pointer, 'E');
928
   if (e) {
926
   if (e) {
929
     *e = 0;
927
     *e = 0;
930
-    ret = strtod(strchr_pointer+1, NULL);
928
+    ret = strtod(seen_pointer+1, NULL);
931
     *e = 'E';
929
     *e = 'E';
932
   }
930
   }
933
   else
931
   else
934
-    ret = strtod(strchr_pointer+1, NULL);
932
+    ret = strtod(seen_pointer+1, NULL);
935
   return ret;
933
   return ret;
936
 }
934
 }
937
 
935
 
938
-long code_value_long() { return strtol(strchr_pointer + 1, NULL, 10); }
936
+long code_value_long() { return strtol(seen_pointer + 1, NULL, 10); }
939
 
937
 
940
-int16_t code_value_short() { return (int16_t)strtol(strchr_pointer + 1, NULL, 10); }
938
+int16_t code_value_short() { return (int16_t)strtol(seen_pointer + 1, NULL, 10); }
941
 
939
 
942
 bool code_seen(char code) {
940
 bool code_seen(char code) {
943
-  strchr_pointer = strchr(command_queue[cmd_queue_index_r], code);
944
-  return (strchr_pointer != NULL);  //Return True if a character was found
941
+  seen_pointer = strchr(current_command_args, code); // +3 since "G0 " is the shortest prefix
942
+  return (seen_pointer != NULL);  //Return True if a character was found
945
 }
943
 }
946
 
944
 
947
 #define DEFINE_PGM_READ_ANY(type, reader)       \
945
 #define DEFINE_PGM_READ_ANY(type, reader)       \
1792
   }
1790
   }
1793
 }
1791
 }
1794
 
1792
 
1793
+void unknown_command_error() {
1794
+  SERIAL_ECHO_START;
1795
+  SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
1796
+  SERIAL_ECHO(current_command);
1797
+  SERIAL_ECHOPGM("\"\n");
1798
+}
1799
+
1795
 /**
1800
 /**
1796
  * G0, G1: Coordinated movement of X Y Z E axes
1801
  * G0, G1: Coordinated movement of X Y Z E axes
1797
  */
1802
  */
2843
    * M1: // M1 - Conditional stop - Wait for user button press on LCD
2848
    * M1: // M1 - Conditional stop - Wait for user button press on LCD
2844
    */
2849
    */
2845
   inline void gcode_M0_M1() {
2850
   inline void gcode_M0_M1() {
2846
-    char *src = strchr_pointer + 2;
2851
+    char *args = current_command_args;
2847
 
2852
 
2848
     millis_t codenum = 0;
2853
     millis_t codenum = 0;
2849
     bool hasP = false, hasS = false;
2854
     bool hasP = false, hasS = false;
2855
       codenum = code_value() * 1000; // seconds to wait
2860
       codenum = code_value() * 1000; // seconds to wait
2856
       hasS = codenum > 0;
2861
       hasS = codenum > 0;
2857
     }
2862
     }
2858
-    char* starpos = strchr(src, '*');
2859
-    if (starpos != NULL) *(starpos) = '\0';
2860
-    while (*src == ' ') ++src;
2861
-    if (!hasP && !hasS && *src != '\0')
2862
-      lcd_setstatus(src, true);
2863
+
2864
+    if (!hasP && !hasS && *args != '\0')
2865
+      lcd_setstatus(args, true);
2863
     else {
2866
     else {
2864
       LCD_MESSAGEPGM(MSG_USERWAIT);
2867
       LCD_MESSAGEPGM(MSG_USERWAIT);
2865
       #if defined(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
2868
       #if defined(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
2932
    * M23: Select a file
2935
    * M23: Select a file
2933
    */
2936
    */
2934
   inline void gcode_M23() {
2937
   inline void gcode_M23() {
2935
-    char* codepos = strchr_pointer + 4;
2936
-    char* starpos = strchr(codepos, '*');
2937
-    if (starpos) *starpos = '\0';
2938
-    card.openFile(codepos, true);
2938
+    card.openFile(current_command_args, true);
2939
   }
2939
   }
2940
 
2940
 
2941
   /**
2941
   /**
2972
    * M28: Start SD Write
2972
    * M28: Start SD Write
2973
    */
2973
    */
2974
   inline void gcode_M28() {
2974
   inline void gcode_M28() {
2975
-    char* codepos = strchr_pointer + 4;
2976
-    char* starpos = strchr(codepos, '*');
2977
-    if (starpos) {
2978
-      char* npos = strchr(command_queue[cmd_queue_index_r], 'N');
2979
-      strchr_pointer = strchr(npos, ' ') + 1;
2980
-      *(starpos) = '\0';
2981
-    }
2982
-    card.openFile(codepos, false);
2975
+    card.openFile(current_command_args, false);
2983
   }
2976
   }
2984
 
2977
 
2985
   /**
2978
   /**
2996
   inline void gcode_M30() {
2989
   inline void gcode_M30() {
2997
     if (card.cardOK) {
2990
     if (card.cardOK) {
2998
       card.closefile();
2991
       card.closefile();
2999
-      char* starpos = strchr(strchr_pointer + 4, '*');
3000
-      if (starpos) {
3001
-        char* npos = strchr(command_queue[cmd_queue_index_r], 'N');
3002
-        strchr_pointer = strchr(npos, ' ') + 1;
3003
-        *(starpos) = '\0';
3004
-      }
3005
-      card.removeFile(strchr_pointer + 4);
2992
+      card.removeFile(current_command_args);
3006
     }
2993
     }
3007
   }
2994
   }
3008
 
2995
 
3032
     if (card.sdprinting)
3019
     if (card.sdprinting)
3033
       st_synchronize();
3020
       st_synchronize();
3034
 
3021
 
3035
-    char* codepos = strchr_pointer + 4;
3036
-
3037
-    char* namestartpos = strchr(codepos, '!');   //find ! to indicate filename string start.
3038
-    if (! namestartpos)
3039
-      namestartpos = codepos; //default name position, 4 letters after the M
3022
+    char* namestartpos = strchr(current_command_args, '!');  // Find ! to indicate filename string start.
3023
+    if (!namestartpos)
3024
+      namestartpos = current_command_args; // Default name position, 4 letters after the M
3040
     else
3025
     else
3041
       namestartpos++; //to skip the '!'
3026
       namestartpos++; //to skip the '!'
3042
 
3027
 
3043
-    char* starpos = strchr(codepos, '*');
3044
-    if (starpos) *(starpos) = '\0';
3045
-
3046
-    bool call_procedure = code_seen('P') && (strchr_pointer < namestartpos);
3028
+    bool call_procedure = code_seen('P') && (seen_pointer < namestartpos);
3047
 
3029
 
3048
     if (card.cardOK) {
3030
     if (card.cardOK) {
3049
       card.openFile(namestartpos, true, !call_procedure);
3031
       card.openFile(namestartpos, true, !call_procedure);
3050
 
3032
 
3051
-      if (code_seen('S') && strchr_pointer < namestartpos) // "S" (must occur _before_ the filename!)
3033
+      if (code_seen('S') && seen_pointer < namestartpos) // "S" (must occur _before_ the filename!)
3052
         card.setIndex(code_value_short());
3034
         card.setIndex(code_value_short());
3053
 
3035
 
3054
       card.startFileprint();
3036
       card.startFileprint();
3061
    * M928: Start SD Write
3043
    * M928: Start SD Write
3062
    */
3044
    */
3063
   inline void gcode_M928() {
3045
   inline void gcode_M928() {
3064
-    char* starpos = strchr(strchr_pointer + 5, '*');
3065
-    if (starpos) {
3066
-      char* npos = strchr(command_queue[cmd_queue_index_r], 'N');
3067
-      strchr_pointer = strchr(npos, ' ') + 1;
3068
-      *(starpos) = '\0';
3069
-    }
3070
-    card.openLogFile(strchr_pointer + 5);
3046
+    card.openLogFile(current_command_args);
3071
   }
3047
   }
3072
 
3048
 
3073
 #endif // SDSUPPORT
3049
 #endif // SDSUPPORT
3864
   SERIAL_PROTOCOLPGM(MSG_M115_REPORT);
3840
   SERIAL_PROTOCOLPGM(MSG_M115_REPORT);
3865
 }
3841
 }
3866
 
3842
 
3867
-#ifdef ULTIPANEL
3868
-
3869
-  /**
3870
-   * M117: Set LCD Status Message
3871
-   */
3872
-  inline void gcode_M117() {
3873
-    lcd_setstatus(strchr_pointer + 5);
3874
-  }
3875
-
3876
-#endif
3843
+/**
3844
+ * M117: Set LCD Status Message
3845
+ */
3846
+inline void gcode_M117() {
3847
+  lcd_setstatus(current_command_args);
3848
+}
3877
 
3849
 
3878
 /**
3850
 /**
3879
  * M119: Output endstop states to serial output
3851
  * M119: Output endstop states to serial output
4161
           autoretract_enabled = true;
4133
           autoretract_enabled = true;
4162
           break;
4134
           break;
4163
         default:
4135
         default:
4164
-          SERIAL_ECHO_START;
4165
-          SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
4166
-          SERIAL_ECHO(command_queue[cmd_queue_index_r]);
4167
-          SERIAL_ECHOLNPGM("\"");
4136
+          unknown_command_error();
4168
           return;
4137
           return;
4169
       }
4138
       }
4170
       for (int i=0; i<EXTRUDERS; i++) retracted[i] = false;
4139
       for (int i=0; i<EXTRUDERS; i++) retracted[i] = false;
5084
  *
5053
  *
5085
  *   F[mm/min] Set the movement feedrate
5054
  *   F[mm/min] Set the movement feedrate
5086
  */
5055
  */
5087
-inline void gcode_T() {
5088
-  uint16_t tmp_extruder = code_value_short();
5056
+inline void gcode_T(uint8_t tmp_extruder) {
5089
   if (tmp_extruder >= EXTRUDERS) {
5057
   if (tmp_extruder >= EXTRUDERS) {
5090
     SERIAL_ECHO_START;
5058
     SERIAL_ECHO_START;
5091
     SERIAL_CHAR('T');
5059
     SERIAL_CHAR('T');
5188
 }
5156
 }
5189
 
5157
 
5190
 /**
5158
 /**
5191
- * Process Commands and dispatch them to handlers
5159
+ * Process a single command and dispatch it to its handler
5192
  * This is called from the main loop()
5160
  * This is called from the main loop()
5193
  */
5161
  */
5194
 void process_next_command() {
5162
 void process_next_command() {
5163
+  current_command = command_queue[cmd_queue_index_r];
5195
 
5164
 
5196
   if ((marlin_debug_flags & DEBUG_ECHO)) {
5165
   if ((marlin_debug_flags & DEBUG_ECHO)) {
5197
     SERIAL_ECHO_START;
5166
     SERIAL_ECHO_START;
5198
-    SERIAL_ECHOLN(command_queue[cmd_queue_index_r]);
5167
+    SERIAL_ECHOLN(current_command);
5168
+  }
5169
+
5170
+  // Sanitize the current command:
5171
+  //  - Skip leading spaces
5172
+  //  - Bypass N...
5173
+  //  - Overwrite * with nul to mark the end
5174
+  while (*current_command == ' ') ++current_command;
5175
+  if (*current_command == 'N' && current_command[1] >= '0' && current_command[1] <= '9') {
5176
+    while (*current_command != ' ') ++current_command;
5177
+    while (*current_command == ' ') ++current_command;
5199
   }
5178
   }
5179
+  char *starpos = strchr(current_command, '*');  // * should always be the last parameter
5180
+  if (starpos) *starpos = '\0';
5181
+
5182
+  // Get the command code, which must be G, M, or T
5183
+  char command_code = *current_command;
5184
+
5185
+  // The code must have a numeric value
5186
+  bool code_is_good = (current_command[1] >= '0' && current_command[1] <= '9');
5187
+
5188
+  int codenum; // define ahead of goto
5200
 
5189
 
5201
-  if (code_seen('G')) {
5190
+  // Bail early if there's no code
5191
+  if (!code_is_good) goto ExitUnknownCommand;
5202
 
5192
 
5203
-    int codenum = code_value_short();
5193
+  // Args pointer optimizes code_seen, especially those taking XYZEF
5194
+  // This wastes a little cpu on commands that expect no arguments.
5195
+  current_command_args = current_command;
5196
+  while (*current_command_args != ' ') ++current_command_args;
5197
+  while (*current_command_args == ' ') ++current_command_args;
5204
 
5198
 
5205
-    switch (codenum) {
5199
+  // Interpret the code int
5200
+  codenum = code_value_short();
5201
+
5202
+  // Handle a known G, M, or T
5203
+  switch(command_code) {
5204
+    case 'G': switch (codenum) {
5206
 
5205
 
5207
     // G0, G1
5206
     // G0, G1
5208
     case 0:
5207
     case 0:
5271
     case 92: // G92
5270
     case 92: // G92
5272
       gcode_G92();
5271
       gcode_G92();
5273
       break;
5272
       break;
5273
+
5274
+    default: code_is_good = false;
5274
     }
5275
     }
5275
-  }
5276
+    break;
5276
 
5277
 
5277
-  else if (code_seen('M')) {
5278
-    switch(code_value_short()) {
5278
+    case 'M': switch (codenum) {
5279
       #ifdef ULTIPANEL
5279
       #ifdef ULTIPANEL
5280
         case 0: // M0 - Unconditional stop - Wait for user button press on LCD
5280
         case 0: // M0 - Unconditional stop - Wait for user button press on LCD
5281
         case 1: // M1 - Conditional stop - Wait for user button press on LCD
5281
         case 1: // M1 - Conditional stop - Wait for user button press on LCD
5350
 
5350
 
5351
       case 105: // M105: Read current temperature
5351
       case 105: // M105: Read current temperature
5352
         gcode_M105();
5352
         gcode_M105();
5353
-        return;
5354
-        break;
5353
+        return; // "ok" already printed
5355
 
5354
 
5356
       case 109: // M109: Wait for temperature
5355
       case 109: // M109: Wait for temperature
5357
         gcode_M109();
5356
         gcode_M109();
5425
       case 115: // M115: Report capabilities
5424
       case 115: // M115: Report capabilities
5426
         gcode_M115();
5425
         gcode_M115();
5427
         break;
5426
         break;
5428
-
5429
-      #ifdef ULTIPANEL
5430
-        case 117: // M117: Set LCD message text
5431
-          gcode_M117();
5432
-          break;
5433
-      #endif
5434
-
5427
+      case 117: // M117: Set LCD message text, if possible
5428
+        gcode_M117();
5429
+        break;
5435
       case 114: // M114: Report current position
5430
       case 114: // M114: Report current position
5436
         gcode_M114();
5431
         gcode_M114();
5437
         break;
5432
         break;
5701
       case 999: // M999: Restart after being Stopped
5696
       case 999: // M999: Restart after being Stopped
5702
         gcode_M999();
5697
         gcode_M999();
5703
         break;
5698
         break;
5699
+
5700
+      default: code_is_good = false;
5704
     }
5701
     }
5705
-  }
5702
+    break;
5706
 
5703
 
5707
-  else if (code_seen('T')) {
5708
-    gcode_T();
5704
+    case 'T':
5705
+      gcode_T(codenum);
5706
+    break;
5709
   }
5707
   }
5710
 
5708
 
5711
-  else {
5712
-    SERIAL_ECHO_START;
5713
-    SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
5714
-    SERIAL_ECHO(command_queue[cmd_queue_index_r]);
5715
-    SERIAL_ECHOLNPGM("\"");
5716
-  }
5709
+ExitUnknownCommand:
5710
+
5711
+  // Still unknown command? Throw an error
5712
+  if (!code_is_good) unknown_command_error();
5717
 
5713
 
5718
   ok_to_send();
5714
   ok_to_send();
5719
 }
5715
 }

Loading…
Cancel
Save