From 25789966316195f779f6578f9a18c5f7068f6dc4 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <thinkyhead@users.noreply.github.com>
Date: Wed, 25 Apr 2018 20:58:00 -0500
Subject: [PATCH] [2.0.x] Emergency parser for multiple serial ports (#10524)

---
 Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp       |  6 +-
 Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp   |  6 +-
 Marlin/src/HAL/HAL_LPC1768/HardwareSerial.cpp |  8 +-
 Marlin/src/HAL/HAL_LPC1768/HardwareSerial.h   | 13 ++-
 Marlin/src/HAL/HAL_LPC1768/include/serial.h   | 10 +++
 Marlin/src/feature/emergency_parser.cpp       | 86 +-----------------
 Marlin/src/feature/emergency_parser.h         | 90 ++++++++++++++++++-
 frameworks/CMSIS/LPC1768/lib/usb/cdcuser.cpp  |  8 +-
 8 files changed, 121 insertions(+), 106 deletions(-)

diff --git a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp
index a9ce865ca2b..7d10ca74b8a 100644
--- a/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp
+++ b/Marlin/src/HAL/HAL_AVR/MarlinSerial.cpp
@@ -85,6 +85,10 @@
 
   FORCE_INLINE void store_rxd_char() {
 
+    #if ENABLED(EMERGENCY_PARSER)
+      static EmergencyParser::State emergency_state; // = EP_RESET
+    #endif
+
     const ring_buffer_pos_t h = rx_buffer.head,
                             i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
 
@@ -160,7 +164,7 @@
     #endif // SERIAL_XON_XOFF
 
     #if ENABLED(EMERGENCY_PARSER)
-      emergency_parser.update(c);
+      emergency_parser.update(emergency_state, c);
     #endif
   }
 
diff --git a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp
index 22f33d89c6d..8413c002ab9 100644
--- a/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp
+++ b/Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp
@@ -112,6 +112,10 @@
 
   FORCE_INLINE void store_rxd_char() {
 
+    #if ENABLED(EMERGENCY_PARSER)
+      static EmergencyParser::State emergency_state; // = EP_RESET
+    #endif
+
     const ring_buffer_pos_t h = rx_buffer.head,
                             i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
 
@@ -182,7 +186,7 @@
     #endif // SERIAL_XON_XOFF
 
     #if ENABLED(EMERGENCY_PARSER)
-      emergency_parser.update(c);
+      emergency_parser.update(emergency_state, c);
     #endif
   }
 
diff --git a/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.cpp b/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.cpp
index fc2358b7036..98ea4f8fc60 100644
--- a/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.cpp
+++ b/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.cpp
@@ -24,12 +24,6 @@
 
 #include "HardwareSerial.h"
 
-#include "../../inc/MarlinConfigPre.h"
-
-#if ENABLED(EMERGENCY_PARSER)
-  #include "../../feature/emergency_parser.h"
-#endif
-
 #if SERIAL_PORT == 0 || SERIAL_PORT_2 == 0
   HardwareSerial Serial = HardwareSerial(LPC_UART0);
 #elif SERIAL_PORT == 1 || SERIAL_PORT_2 == 1
@@ -254,7 +248,7 @@ void HardwareSerial::IRQHandler() {
     // Clear the FIFO
     while (UART_Receive(UARTx, &byte, 1, NONE_BLOCKING)) {
       #if ENABLED(EMERGENCY_PARSER)
-        emergency_parser.update(byte);
+        emergency_parser.update(emergency_state, byte);
       #endif
       if ((RxQueueWritePos + 1) % RX_BUFFER_SIZE != RxQueueReadPos) {
         RxBuffer[RxQueueWritePos] = byte;
diff --git a/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.h b/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.h
index 33358d207ce..0f96652410b 100644
--- a/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.h
+++ b/Marlin/src/HAL/HAL_LPC1768/HardwareSerial.h
@@ -23,6 +23,11 @@
 #ifndef HARDWARE_SERIAL_H_
 #define HARDWARE_SERIAL_H_
 
+#include "../../inc/MarlinConfigPre.h"
+#if ENABLED(EMERGENCY_PARSER)
+  #include "../../feature/emergency_parser.h"
+#endif
+
 #include <stdarg.h>
 #include <stdio.h>
 #include <Stream.h>
@@ -32,8 +37,6 @@ extern "C" {
   #include "lpc17xx_pinsel.h"
 }
 
-#include "../../inc/MarlinConfigPre.h"
-
 class HardwareSerial : public Stream {
 private:
   LPC_UART_TypeDef *UARTx;
@@ -48,6 +51,9 @@ private:
     uint32_t TxQueueWritePos;
     uint32_t TxQueueReadPos;
   #endif
+  #if ENABLED(EMERGENCY_PARSER)
+    EmergencyParser::State emergency_state;
+  #endif
 
 public:
   HardwareSerial(LPC_UART_TypeDef *UARTx)
@@ -59,6 +65,9 @@ public:
       , TxQueueWritePos(0)
       , TxQueueReadPos(0)
     #endif
+    #if ENABLED(EMERGENCY_PARSER)
+      , emergency_state(EmergencyParser::State::EP_RESET)
+    #endif
   {
   }
 
diff --git a/Marlin/src/HAL/HAL_LPC1768/include/serial.h b/Marlin/src/HAL/HAL_LPC1768/include/serial.h
index 782db40536d..fd5c58254c6 100644
--- a/Marlin/src/HAL/HAL_LPC1768/include/serial.h
+++ b/Marlin/src/HAL/HAL_LPC1768/include/serial.h
@@ -23,6 +23,11 @@
 #ifndef _HAL_SERIAL_H_
 #define _HAL_SERIAL_H_
 
+#include "../../../inc/MarlinConfigPre.h"
+#if ENABLED(EMERGENCY_PARSER)
+  #include "../../../feature/emergency_parser.h"
+#endif
+
 #include <stdarg.h>
 #include <stdio.h>
 
@@ -73,6 +78,11 @@ private:
 
 class HalSerial {
 public:
+
+  #if ENABLED(EMERGENCY_PARSER)
+    EmergencyParser::State emergency_state;
+  #endif
+
   HalSerial() { host_connected = false; }
 
   void begin(int32_t baud) {
diff --git a/Marlin/src/feature/emergency_parser.cpp b/Marlin/src/feature/emergency_parser.cpp
index c914e2dab00..3c9cbf12e56 100644
--- a/Marlin/src/feature/emergency_parser.cpp
+++ b/Marlin/src/feature/emergency_parser.cpp
@@ -30,92 +30,10 @@
 
 #include "emergency_parser.h"
 
-extern volatile bool wait_for_user, wait_for_heatup;
-void quickstop_stepper();
-
-EmergencyParser::State EmergencyParser::state = EP_RESET;
+// Static data members
 bool EmergencyParser::killed_by_M112; // = false
 
+// Global instance
 EmergencyParser emergency_parser;
 
-void EmergencyParser::update(const uint8_t c) {
-
-  switch (state) {
-    case EP_RESET:
-      switch (c) {
-        case ' ': break;
-        case 'N': state = EP_N;      break;
-        case 'M': state = EP_M;      break;
-        default: state  = EP_IGNORE;
-      }
-      break;
-
-    case EP_N:
-      switch (c) {
-        case '0': case '1': case '2':
-        case '3': case '4': case '5':
-        case '6': case '7': case '8':
-        case '9': case '-': case ' ':   break;
-        case 'M': state = EP_M;      break;
-        default:  state = EP_IGNORE;
-      }
-      break;
-
-    case EP_M:
-      switch (c) {
-        case ' ': break;
-        case '1': state = EP_M1;     break;
-        case '4': state = EP_M4;     break;
-        default: state  = EP_IGNORE;
-      }
-      break;
-
-    case EP_M1:
-      switch (c) {
-        case '0': state = EP_M10;    break;
-        case '1': state = EP_M11;    break;
-        default: state  = EP_IGNORE;
-      }
-      break;
-
-    case EP_M10:
-      state = (c == '8') ? EP_M108 : EP_IGNORE;
-      break;
-
-    case EP_M11:
-      state = (c == '2') ? EP_M112 : EP_IGNORE;
-      break;
-
-    case EP_M4:
-      state = (c == '1') ? EP_M41 : EP_IGNORE;
-      break;
-
-    case EP_M41:
-      state = (c == '0') ? EP_M410 : EP_IGNORE;
-      break;
-
-    case EP_IGNORE:
-      if (c == '\n') state = EP_RESET;
-      break;
-
-    default:
-      if (c == '\n') {
-        switch (state) {
-          case EP_M108:
-            wait_for_user = wait_for_heatup = false;
-            break;
-          case EP_M112:
-            killed_by_M112 = true;
-            break;
-          case EP_M410:
-            quickstop_stepper();
-            break;
-          default:
-            break;
-        }
-        state = EP_RESET;
-      }
-  }
-}
-
 #endif // EMERGENCY_PARSER
diff --git a/Marlin/src/feature/emergency_parser.h b/Marlin/src/feature/emergency_parser.h
index be2bf3d7a22..127b5c20daf 100644
--- a/Marlin/src/feature/emergency_parser.h
+++ b/Marlin/src/feature/emergency_parser.h
@@ -27,8 +27,14 @@
 #ifndef _EMERGENCY_PARSER_H_
 #define _EMERGENCY_PARSER_H_
 
+// External references
+extern volatile bool wait_for_user, wait_for_heatup;
+void quickstop_stepper();
+
 class EmergencyParser {
 
+public:
+
   // Currently looking for: M108, M112, M410
   enum State : char {
     EP_RESET,
@@ -45,14 +51,90 @@ class EmergencyParser {
     EP_IGNORE // to '\n'
   };
 
-public:
-
-  static EmergencyParser::State state;
   static bool killed_by_M112;
 
   EmergencyParser() {}
 
-  static void update(const uint8_t c);
+  __attribute__((always_inline)) inline
+  static void update(State &state, const uint8_t c) {
+
+    switch (state) {
+      case EP_RESET:
+        switch (c) {
+          case ' ': break;
+          case 'N': state = EP_N;      break;
+          case 'M': state = EP_M;      break;
+          default: state  = EP_IGNORE;
+        }
+        break;
+
+      case EP_N:
+        switch (c) {
+          case '0': case '1': case '2':
+          case '3': case '4': case '5':
+          case '6': case '7': case '8':
+          case '9': case '-': case ' ':   break;
+          case 'M': state = EP_M;      break;
+          default:  state = EP_IGNORE;
+        }
+        break;
+
+      case EP_M:
+        switch (c) {
+          case ' ': break;
+          case '1': state = EP_M1;     break;
+          case '4': state = EP_M4;     break;
+          default: state  = EP_IGNORE;
+        }
+        break;
+
+      case EP_M1:
+        switch (c) {
+          case '0': state = EP_M10;    break;
+          case '1': state = EP_M11;    break;
+          default: state  = EP_IGNORE;
+        }
+        break;
+
+      case EP_M10:
+        state = (c == '8') ? EP_M108 : EP_IGNORE;
+        break;
+
+      case EP_M11:
+        state = (c == '2') ? EP_M112 : EP_IGNORE;
+        break;
+
+      case EP_M4:
+        state = (c == '1') ? EP_M41 : EP_IGNORE;
+        break;
+
+      case EP_M41:
+        state = (c == '0') ? EP_M410 : EP_IGNORE;
+        break;
+
+      case EP_IGNORE:
+        if (c == '\n') state = EP_RESET;
+        break;
+
+      default:
+        if (c == '\n') {
+          switch (state) {
+            case EP_M108:
+              wait_for_user = wait_for_heatup = false;
+              break;
+            case EP_M112:
+              killed_by_M112 = true;
+              break;
+            case EP_M410:
+              quickstop_stepper();
+              break;
+            default:
+              break;
+          }
+          state = EP_RESET;
+        }
+    }
+  }
 
 };
 
diff --git a/frameworks/CMSIS/LPC1768/lib/usb/cdcuser.cpp b/frameworks/CMSIS/LPC1768/lib/usb/cdcuser.cpp
index 9aa8cd61143..8fd08f00eb5 100644
--- a/frameworks/CMSIS/LPC1768/lib/usb/cdcuser.cpp
+++ b/frameworks/CMSIS/LPC1768/lib/usb/cdcuser.cpp
@@ -39,12 +39,6 @@ unsigned short CDC_DepInEmpty = 1;                   // Data IN EP is empty
 unsigned short CDC_LineState = 0;
 unsigned short CDC_SerialState = 0;
 
-#include "../../../../../Marlin/src/inc/MarlinConfigPre.h"
-
-#if ENABLED(EMERGENCY_PARSER)
-  #include "../../../../../Marlin/src/feature/emergency_parser.h"
-#endif
-
 extern HalSerial usb_serial;
 /*----------------------------------------------------------------------------
  write data to CDC_OutBuf
@@ -58,7 +52,7 @@ uint32_t CDC_WrOutBuf(const char *buffer, uint32_t *length) {
 
   while (bytesToWrite) {
     #if ENABLED(EMERGENCY_PARSER)
-      emergency_parser.update(*buffer);
+      emergency_parser.update(usb_serial.emergency_state, *buffer);
     #endif
     usb_serial.receive_buffer.write(*buffer++);           // Copy Data to buffer
     bytesToWrite--;