Skip to content

Commit

Permalink
Merge pull request #4226 from thinkyhead/rc_emergency_command_parser
Browse files Browse the repository at this point in the history
MarlinSerial emergency-command parser (with M108)
  • Loading branch information
thinkyhead authored Jul 7, 2016
2 parents 9f42b1a + 2ee4e4f commit 98d0167
Show file tree
Hide file tree
Showing 29 changed files with 294 additions and 56 deletions.
6 changes: 6 additions & 0 deletions Marlin/Conditionals.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@
#define HardwareSerial_h // trick to disable the standard HWserial
#endif

#if ENABLED(EMERGENCY_PARSER)
#define EMERGENCY_PARSER_CAPABILITIES " EMERGENCY_CODES:M108,M112,M410"
#else
#define EMERGENCY_PARSER_CAPABILITIES ""
#endif

#include "Arduino.h"

/**
Expand Down
6 changes: 6 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ const unsigned int dropsegments = 5; //everything with less than this number of
#define MAX_CMD_SIZE 96
#define BUFSIZE 4

// Enable an emergency-command parser to intercept certain commands as they
// enter the serial receive buffer, so they cannot be blocked.
// Currently handles M108, M112, M410
// Does not work on boards using AT90USB (USBCON) processors!
//#define EMERGENCY_PARSER

// Bad Serial-connections can miss a received command by sending an 'ok'
// Therefore some clients abort after 30 seconds in a timeout.
// Some other clients start sending commands while receiving a 'wait'.
Expand Down
5 changes: 2 additions & 3 deletions Marlin/Marlin.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,7 @@ void ok_to_send();
void reset_bed_level();
void kill(const char*);

#if DISABLED(DELTA) && DISABLED(SCARA)
void set_current_position_from_planner();
#endif
void quickstop_stepper();

#if ENABLED(FILAMENT_RUNOUT_SENSOR)
void handle_filament_runout();
Expand Down Expand Up @@ -288,6 +286,7 @@ extern float sw_endstop_min[3]; // axis[n].sw_endstop_min
extern float sw_endstop_max[3]; // axis[n].sw_endstop_max
extern bool axis_known_position[3]; // axis[n].is_known
extern bool axis_homed[3]; // axis[n].is_homed
extern volatile bool wait_for_heatup;

// GCode support for external objects
bool code_seen(char);
Expand Down
106 changes: 106 additions & 0 deletions Marlin/MarlinSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "Marlin.h"
#include "MarlinSerial.h"
#include "stepper.h"

#ifndef USBCON
// this next line disables the entire HardwareSerial.cpp,
Expand All @@ -54,6 +55,10 @@ FORCE_INLINE void store_char(unsigned char c) {
rx_buffer.head = i;
}
CRITICAL_SECTION_END;

#if ENABLED(EMERGENCY_PARSER)
emergency_parser(c);
#endif
}


Expand Down Expand Up @@ -310,3 +315,104 @@ MarlinSerial customizedSerial;
#if defined(USBCON) && ENABLED(BLUETOOTH)
HardwareSerial bluetoothSerial;
#endif

#if ENABLED(EMERGENCY_PARSER)

// Currently looking for: M108, M112, M410
// If you alter the parser please don't forget to update the capabilities in Conditionals.h

void emergency_parser(unsigned char c) {

enum e_parser_state {
state_RESET,
state_N,
state_M,
state_M1,
state_M10,
state_M108,
state_M11,
state_M112,
state_M4,
state_M41,
state_M410,
state_IGNORE // to '\n'
};

static e_parser_state state = state_RESET;

switch (state) {
case state_RESET:
switch (c) {
case ' ': break;
case 'N': state = state_N; break;
case 'M': state = state_M; break;
default: state = state_IGNORE;
}
break;

case state_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 = state_M; break;
default: state = state_IGNORE;
}
break;

case state_M:
switch (c) {
case ' ': break;
case '1': state = state_M1; break;
case '4': state = state_M4; break;
default: state = state_IGNORE;
}
break;

case state_M1:
switch (c) {
case '0': state = state_M10; break;
case '1': state = state_M11; break;
default: state = state_IGNORE;
}
break;

case state_M10:
state = (c == '8') ? state_M108 : state_IGNORE;
break;

case state_M11:
state = (c == '2') ? state_M112 : state_IGNORE;
break;

case state_M4:
state = (c == '1') ? state_M41 : state_IGNORE;
break;

case state_M41:
state = (c == '0') ? state_M410 : state_IGNORE;
break;

case state_IGNORE:
if (c == '\n') state = state_RESET;
break;

default:
if (c == '\n') {
switch (state) {
case state_M108:
wait_for_heatup = false;
break;
case state_M112:
kill(PSTR(MSG_KILLED));
break;
case state_M410:
quickstop_stepper();
break;
}
state = state_RESET;
}
}
}
#endif
9 changes: 9 additions & 0 deletions Marlin/MarlinSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ struct ring_buffer {
extern ring_buffer rx_buffer;
#endif

#if ENABLED(EMERGENCY_PARSER)
#include "language.h"
void emergency_parser(unsigned char c);
#endif

class MarlinSerial { //: public Stream

public:
Expand Down Expand Up @@ -141,6 +146,10 @@ class MarlinSerial { //: public Stream
rx_buffer.head = i;
}
CRITICAL_SECTION_END;

#if ENABLED(EMERGENCY_PARSER)
emergency_parser(c);
#endif
}
}

Expand Down
90 changes: 49 additions & 41 deletions Marlin/Marlin_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@
* M105 - Read current temp
* M106 - Fan on
* M107 - Fan off
* M108 - Cancel heatup and wait for the hotend and bed, this G-code is asynchronously handled in the get_serial_commands() parser
* M108 - Stop the waiting for heaters in M109, M190, M303. Does not affect the target temperature.
* M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating
* Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
* IF AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
Expand Down Expand Up @@ -332,7 +332,7 @@ uint8_t active_extruder = 0;
// Relative Mode. Enable with G91, disable with G90.
static bool relative_mode = false;

bool wait_for_heatup = true;
volatile bool wait_for_heatup = true;

const char errormagic[] PROGMEM = "Error:";
const char echomagic[] PROGMEM = "echo:";
Expand Down Expand Up @@ -1105,9 +1105,12 @@ inline void get_serial_commands() {
}
}

// If command was e-stop process now
if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
if (strcmp(command, "M108") == 0) wait_for_heatup = false;
#if DISABLED(EMERGENCY_PARSER)
// If command was e-stop process now
if (strcmp(command, "M108") == 0) wait_for_heatup = false;
if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
if (strcmp(command, "M410") == 0) { quickstop_stepper(); }
#endif

#if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
last_command_time = ms;
Expand Down Expand Up @@ -4535,10 +4538,29 @@ inline void gcode_M105() {

#endif // FAN_COUNT > 0

/**
* M108: Cancel heatup and wait for the hotend and bed, this G-code is asynchronously handled in the get_serial_commands() parser
*/
inline void gcode_M108() { wait_for_heatup = false; }
#if DISABLED(EMERGENCY_PARSER)

/**
* M108: Stop the waiting for heaters in M109, M190, M303. Does not affect the target temperature.
*/
inline void gcode_M108() { wait_for_heatup = false; }


/**
* M112: Emergency Stop
*/
inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }


/**
* M410: Quickstop - Abort all planned moves
*
* This will stop the carriages mid-move, so most likely they
* will be out of sync with the stepper position after this.
*/
inline void gcode_M410() { quickstop_stepper(); }

#endif

/**
* M109: Sxxx Wait for extruder(s) to reach temperature. Waits only when heating.
Expand Down Expand Up @@ -4810,11 +4832,6 @@ inline void gcode_M111() {
SERIAL_EOL;
}

/**
* M112: Emergency Stop
*/
inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }

#if ENABLED(HOST_KEEPALIVE_FEATURE)

/**
Expand Down Expand Up @@ -5970,8 +5987,9 @@ inline void gcode_M400() { stepper.synchronize(); }

#endif // FILAMENT_WIDTH_SENSOR

#if DISABLED(DELTA) && DISABLED(SCARA)
void set_current_position_from_planner() {
void quickstop_stepper() {
stepper.quick_stop();
#if DISABLED(DELTA) && DISABLED(SCARA)
stepper.synchronize();
#if ENABLED(AUTO_BED_LEVELING_FEATURE)
vector_3 pos = planner.adjusted_position(); // values directly from steppers...
Expand All @@ -5984,23 +6002,9 @@ inline void gcode_M400() { stepper.synchronize(); }
current_position[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS);
#endif
sync_plan_position(); // ...re-apply to planner position
}
#endif

/**
* M410: Quickstop - Abort all planned moves
*
* This will stop the carriages mid-move, so most likely they
* will be out of sync with the stepper position after this.
*/
inline void gcode_M410() {
stepper.quick_stop();
#if DISABLED(DELTA) && DISABLED(SCARA)
set_current_position_from_planner();
#endif
}


#if ENABLED(MESH_BED_LEVELING)

/**
Expand Down Expand Up @@ -6955,9 +6959,21 @@ void process_next_command() {
gcode_M111();
break;

case 112: // M112: Emergency Stop
gcode_M112();
break;
#if DISABLED(EMERGENCY_PARSER)

case 108: // M108: Cancel Waiting
gcode_M108();
break;

case 112: // M112: Emergency Stop
gcode_M112();
break;

case 410: // M410 quickstop - Abort all the planned moves.
gcode_M410();
break;

#endif

#if ENABLED(HOST_KEEPALIVE_FEATURE)

Expand All @@ -6976,10 +6992,6 @@ void process_next_command() {
KEEPALIVE_STATE(NOT_BUSY);
return; // "ok" already printed

case 108:
gcode_M108();
break;

case 109: // M109: Wait for temperature
gcode_M109();
break;
Expand Down Expand Up @@ -7263,10 +7275,6 @@ void process_next_command() {
break;
#endif // ENABLED(FILAMENT_WIDTH_SENSOR)

case 410: // M410 quickstop - Abort all the planned moves.
gcode_M410();
break;

#if ENABLED(MESH_BED_LEVELING)
case 420: // M420 Enable/Disable Mesh Bed Leveling
gcode_M420();
Expand Down
7 changes: 7 additions & 0 deletions Marlin/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,13 @@
#endif

/**
* emergency-command parser
*/
#if ENABLED(EMERGENCY_PARSER) && ENABLED(USBCON)
#error "EMERGENCY_PARSER does not work on boards with AT90USB processors (USBCON)."
#endif

/**
* Warnings for old configurations
*/
#if WATCH_TEMP_PERIOD > 500
Expand Down
5 changes: 1 addition & 4 deletions Marlin/endstops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,7 @@ void Endstops::report_state() {
if (stepper.abort_on_endstop_hit) {
card.sdprinting = false;
card.closefile();
stepper.quick_stop();
#if DISABLED(DELTA) && DISABLED(SCARA)
set_current_position_from_planner();
#endif
quickstop_stepper();
thermalManager.disable_all_heaters(); // switch off all heaters.
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions Marlin/example_configurations/Cartesio/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ const unsigned int dropsegments = 5; //everything with less than this number of
#define MAX_CMD_SIZE 96
#define BUFSIZE 4

// Enable an emergency-command parser to intercept certain commands as they
// enter the serial receive buffer, so they cannot be blocked.
// Currently handles M108, M112, M410
// Does not work on boards using AT90USB (USBCON) processors!
//#define EMERGENCY_PARSER

// Bad Serial-connections can miss a received command by sending an 'ok'
// Therefore some clients abort after 30 seconds in a timeout.
// Some other clients start sending commands while receiving a 'wait'.
Expand Down
Loading

0 comments on commit 98d0167

Please sign in to comment.