From 027a5a872de56c462b260386b0e5cd2aa88c577e Mon Sep 17 00:00:00 2001 From: fedetony <45215920+fedetony@users.noreply.github.com> Date: Fri, 16 Apr 2021 08:59:28 +0200 Subject: [PATCH] Realtime Reporting, S000, P000, R000 (#19330) --- Marlin/Configuration_adv.h | 9 ++ Marlin/src/feature/e_parser.h | 134 +++++++++++++++----------- Marlin/src/gcode/bedlevel/abl/G29.cpp | 5 +- Marlin/src/gcode/bedlevel/mbl/G29.cpp | 4 + Marlin/src/gcode/bedlevel/ubl/G29.cpp | 13 ++- Marlin/src/gcode/calibrate/G28.cpp | 4 + Marlin/src/gcode/calibrate/G33.cpp | 4 + Marlin/src/gcode/gcode.cpp | 11 ++- Marlin/src/gcode/host/M114.cpp | 4 + Marlin/src/gcode/motion/G0_G1.cpp | 4 + Marlin/src/gcode/motion/G2_G3.cpp | 4 + Marlin/src/gcode/parser.cpp | 23 ++++- Marlin/src/module/motion.cpp | 58 +++++++++++ Marlin/src/module/motion.h | 39 +++++++- Marlin/src/module/planner.cpp | 18 ++++ Marlin/src/module/planner.h | 7 ++ buildroot/tests/LPC1768 | 4 +- 17 files changed, 275 insertions(+), 70 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index fa1b470ab..578bf144f 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2115,6 +2115,15 @@ */ //#define EMERGENCY_PARSER +/** + * Realtime Reporting + * Add support for commands S000 State, P000 Pause, and R000 Resume + */ +//#define REALTIME_REPORTING_COMMANDS +#if ENABLED(REALTIME_REPORTING_COMMANDS) + //#define FULL_REPORT_TO_HOST_FEATURE // Auto-report the machine status like Grbl CNC +#endif + // 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'. diff --git a/Marlin/src/feature/e_parser.h b/Marlin/src/feature/e_parser.h index 659e51678..c12fd14ad 100644 --- a/Marlin/src/feature/e_parser.h +++ b/Marlin/src/feature/e_parser.h @@ -34,29 +34,33 @@ // External references extern bool wait_for_user, wait_for_heatup; +#if ENABLED(REALTIME_REPORTING_COMMANDS) + // From motion.h, which cannot be included here + void report_current_position_moving(); + void quickpause_stepper(); + void quickresume_stepper(); +#endif + class EmergencyParser { public: - // Currently looking for: M108, M112, M410, M876 - enum State : char { + // Currently looking for: M108, M112, M410, M876 S[0-9], S000, P000, R000 + enum State : uint8_t { EP_RESET, EP_N, EP_M, EP_M1, - EP_M10, - EP_M108, - EP_M11, - EP_M112, - EP_M4, - EP_M41, - EP_M410, + EP_M10, EP_M108, + EP_M11, EP_M112, + EP_M4, EP_M41, EP_M410, #if ENABLED(HOST_PROMPT_SUPPORT) - EP_M8, - EP_M87, - EP_M876, - EP_M876S, - EP_M876SN, + EP_M8, EP_M87, EP_M876, EP_M876S, EP_M876SN, + #endif + #if ENABLED(REALTIME_REPORTING_COMMANDS) + EP_S, EP_S0, EP_S00, EP_GRBL_STATUS, + EP_R, EP_R0, EP_R00, EP_GRBL_RESUME, + EP_P, EP_P0, EP_P00, EP_GRBL_PAUSE, #endif EP_IGNORE // to '\n' }; @@ -71,7 +75,6 @@ public: EmergencyParser() { enable(); } FORCE_INLINE static void enable() { enabled = true; } - FORCE_INLINE static void disable() { enabled = false; } FORCE_INLINE static void update(State &state, const uint8_t c) { @@ -79,21 +82,45 @@ public: case EP_RESET: switch (c) { case ' ': case '\n': case '\r': break; - case 'N': state = EP_N; break; - case 'M': state = EP_M; break; - default: state = EP_IGNORE; + case 'N': state = EP_N; break; + case 'M': state = EP_M; break; + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': state = EP_S; break; + case 'P': state = EP_P; break; + case 'R': state = EP_R; break; + #endif + default: state = EP_IGNORE; } break; case EP_N: switch (c) { case '0' ... '9': - case '-': case ' ': break; - case 'M': state = EP_M; break; - default: state = EP_IGNORE; + case '-': case ' ': break; + case 'M': state = EP_M; break; + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': state = EP_S; break; + case 'P': state = EP_P; break; + case 'R': state = EP_R; break; + #endif + default: state = EP_IGNORE; } break; + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case EP_S: state = (c == '0') ? EP_S0 : EP_IGNORE; break; + case EP_S0: state = (c == '0') ? EP_S00 : EP_IGNORE; break; + case EP_S00: state = (c == '0') ? EP_GRBL_STATUS : EP_IGNORE; break; + + case EP_R: state = (c == '0') ? EP_R0 : EP_IGNORE; break; + case EP_R0: state = (c == '0') ? EP_R00 : EP_IGNORE; break; + case EP_R00: state = (c == '0') ? EP_GRBL_RESUME : EP_IGNORE; break; + + case EP_P: state = (c == '0') ? EP_P0 : EP_IGNORE; break; + case EP_P0: state = (c == '0') ? EP_P00 : EP_IGNORE; break; + case EP_P00: state = (c == '0') ? EP_GRBL_PAUSE : EP_IGNORE; break; + #endif + case EP_M: switch (c) { case ' ': break; @@ -114,48 +141,34 @@ public: } 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_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; #if ENABLED(HOST_PROMPT_SUPPORT) - case EP_M8: - state = (c == '7') ? EP_M87 : EP_IGNORE; - break; - case EP_M87: - state = (c == '6') ? EP_M876 : EP_IGNORE; - break; + case EP_M8: state = (c == '7') ? EP_M87 : EP_IGNORE; break; + case EP_M87: state = (c == '6') ? EP_M876 : EP_IGNORE; break; - case EP_M876: - switch (c) { - case ' ': break; - case 'S': state = EP_M876S; break; - default: state = EP_IGNORE; break; - } - break; + case EP_M876: + switch (c) { + case ' ': break; + case 'S': state = EP_M876S; break; + default: state = EP_IGNORE; break; + } + break; + + case EP_M876S: + switch (c) { + case ' ': break; + case '0' ... '9': + state = EP_M876SN; + M876_reason = uint8_t(c - '0'); + break; + } + break; - case EP_M876S: - switch (c) { - case ' ': break; - case '0' ... '9': - state = EP_M876SN; - M876_reason = (uint8_t)(c - '0'); - break; - } - break; #endif case EP_IGNORE: @@ -171,6 +184,11 @@ public: #if ENABLED(HOST_PROMPT_SUPPORT) case EP_M876SN: host_response_handler(M876_reason); break; #endif + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case EP_GRBL_STATUS: report_current_position_moving(); break; + case EP_GRBL_PAUSE: quickpause_stepper(); break; + case EP_GRBL_RESUME: quickresume_stepper(); break; + #endif default: break; } state = EP_RESET; diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 423857dbb..a10b2b89b 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -217,9 +217,10 @@ public: * There's no extra effect if you have a fixed Z probe. */ G29_TYPE GcodeSuite::G29() { - TERN_(PROBE_MANUALLY, static) G29_State abl; + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); + reset_stepper_timeout(); const bool seenQ = EITHER(DEBUG_LEVELING_FEATURE, PROBE_MANUALLY) && parser.seen('Q'); @@ -897,6 +898,8 @@ G29_TYPE GcodeSuite::G29() { report_current_position(); + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); + G29_RETURN(ISNAN(abl.measured_z)); } diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index 1ec514c3e..2da584fd4 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -60,6 +60,8 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM(" */ void GcodeSuite::G29() { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); + static int mbl_probe_index = -1; MeshLevelingState state = (MeshLevelingState)parser.byteval('S', (int8_t)MeshReport); @@ -187,6 +189,8 @@ void GcodeSuite::G29() { } report_current_position(); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); } #endif // MESH_BED_LEVELING diff --git a/Marlin/src/gcode/bedlevel/ubl/G29.cpp b/Marlin/src/gcode/bedlevel/ubl/G29.cpp index 2ef3ab4ce..932503d72 100644 --- a/Marlin/src/gcode/bedlevel/ubl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/ubl/G29.cpp @@ -31,6 +31,17 @@ #include "../../gcode.h" #include "../../../feature/bedlevel/bedlevel.h" -void GcodeSuite::G29() { ubl.G29(); } +#if ENABLED(FULL_REPORT_TO_HOST_FEATURE) + #include "../../../module/motion.h" +#endif + +void GcodeSuite::G29() { + + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); + + ubl.G29(); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); +} #endif // AUTO_BED_LEVELING_UBL diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 73bfc3bdc..10e094cba 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -211,6 +211,8 @@ void GcodeSuite::G28() { TERN_(LASER_MOVE_G28_OFF, cutter.set_inline_enabled(false)); // turn off laser + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOMING)); + #if ENABLED(DUAL_X_CARRIAGE) bool IDEX_saved_duplication_state = extruder_duplication_enabled; DualXMode IDEX_saved_mode = dual_x_carriage_mode; @@ -479,6 +481,8 @@ void GcodeSuite::G28() { if (ENABLED(NANODLP_Z_SYNC) && (doZ || ENABLED(NANODLP_ALL_AXIS))) SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP); + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); + #if HAS_L64XX // Set L6470 absolute position registers to counts // constexpr *might* move this to PROGMEM. diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 0bcab206a..db1d456d7 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -387,6 +387,8 @@ static float auto_tune_a() { */ void GcodeSuite::G33() { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_PROBE)); + const int8_t probe_points = parser.intval('P', DELTA_CALIBRATION_DEFAULT_POINTS); if (!WITHIN(probe_points, 0, 10)) { SERIAL_ECHOLNPGM("?(P)oints implausible (0-10)."); @@ -645,6 +647,8 @@ void GcodeSuite::G33() { while (((zero_std_dev < test_precision && iterations < 31) || iterations <= force_iterations) && zero_std_dev > calibration_precision); ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index)); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); } #endif // DELTA_AUTO_CALIBRATION diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 574e93aec..efea08760 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -289,8 +289,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { } #endif - // Handle a known G, M, or T + // Handle a known command or reply "unknown command" + switch (parser.command_letter) { + case 'G': switch (parser.codenum) { case 0: case 1: // G0: Fast Move, G1: Linear Move @@ -995,6 +997,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 'D': D(parser.codenum); break; // Dn: Debug codes #endif + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': case 'P': case 'R': break; // Invalid S, P, R commands already filtered + #endif + default: #if ENABLED(WIFI_CUSTOM_COMMAND) if (wifi_custom_command(parser.command_ptr)) break; @@ -1087,12 +1093,15 @@ void GcodeSuite::process_subcommands_now(char * gcode) { case IN_HANDLER: case IN_PROCESS: SERIAL_ECHO_MSG(STR_BUSY_PROCESSING); + TERN_(FULL_REPORT_TO_HOST_FEATURE, report_current_position_moving()); break; case PAUSED_FOR_USER: SERIAL_ECHO_MSG(STR_BUSY_PAUSED_FOR_USER); + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOLD)); break; case PAUSED_FOR_INPUT: SERIAL_ECHO_MSG(STR_BUSY_PAUSED_FOR_INPUT); + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOLD)); break; default: break; diff --git a/Marlin/src/gcode/host/M114.cpp b/Marlin/src/gcode/host/M114.cpp index 75356ff66..dd62f0ad2 100644 --- a/Marlin/src/gcode/host/M114.cpp +++ b/Marlin/src/gcode/host/M114.cpp @@ -176,6 +176,8 @@ const xyze_float_t diff = from_steppers - leveled; SERIAL_ECHOPGM("Diff: "); report_xyze(diff); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, report_current_grblstate_moving()); } #endif // M114_DETAIL @@ -211,4 +213,6 @@ void GcodeSuite::M114() { TERN_(M114_LEGACY, planner.synchronize()); report_current_position_projected(); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, report_current_grblstate_moving()); } diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 9ac49bd93..64c07d1d8 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -54,6 +54,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { | (parser.seen('Z') ? _BV(Z_AXIS) : 0) ) #endif ) { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING)); #ifdef G0_FEEDRATE feedRate_t old_feedrate; @@ -116,6 +117,9 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { planner.synchronize(); SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP); } + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); + #else + TERN_(FULL_REPORT_TO_HOST_FEATURE, report_current_grblstate_moving()); #endif } } diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 61e50247f..5a8324362 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -306,6 +306,8 @@ void plan_arc( void GcodeSuite::G2_G3(const bool clockwise) { if (MOTION_CONDITIONS) { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING)); + #if ENABLED(SF_ARC_FIX) const bool relative_mode_backup = relative_mode; relative_mode = true; @@ -364,6 +366,8 @@ void GcodeSuite::G2_G3(const bool clockwise) { } else SERIAL_ERROR_MSG(STR_ERR_ARC_ARGS); + + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE)); } } diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index f7812bf3f..9f0d09563 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -106,8 +106,10 @@ void GCodeParser::reset() { #endif -// Populate all fields by parsing a single line of GCode -// 58 bytes of SRAM are used to speed up seen/value +/** + * Populate the command line state (command_letter, codenum, subcode, and string_arg) + * by parsing a single line of GCode. 58 bytes of SRAM are used to speed up seen/value. + */ void GCodeParser::parse(char *p) { reset(); // No codes to report @@ -147,10 +149,12 @@ void GCodeParser::parse(char *p) { #define SIGNED_CODENUM 1 #endif - // Bail if the letter is not G, M, or T - // (or a valid parameter for the current motion mode) + /** + * Screen for good command letters. G, M, and T are always accepted. + * With Motion Modes enabled any axis letter can come first. + * With Realtime Reporting, commands S000, P000, and R000 are allowed. + */ switch (letter) { - case 'G': case 'M': case 'T': TERN_(MARLIN_DEV_MODE, case 'D':) // Skip spaces to get the numeric part while (*p == ' ') p++; @@ -227,6 +231,15 @@ void GCodeParser::parse(char *p) { break; #endif // GCODE_MOTION_MODES + #if ENABLED(REALTIME_REPORTING_COMMANDS) + case 'S': case 'P': case 'R': { + codenum = 0; // The only valid codenum is 0 + uint8_t digits = 0; + while (*p++ == '0') digits++; // Count up '0' characters + command_letter = (digits == 3) ? letter : '?'; // Three '0' digits is a good command + } return; // No parameters, so return + #endif + default: return; } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 6058db37b..584e894ae 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -230,6 +230,50 @@ void report_current_position_projected() { stepper.report_a_position(planner.position); } +#if EITHER(FULL_REPORT_TO_HOST_FEATURE, REALTIME_REPORTING_COMMANDS) + + M_StateEnum M_State_grbl = M_INIT; + + /** + * Output the current grbl compatible state to serial while moving + */ + void report_current_grblstate_moving() { SERIAL_ECHOLNPAIR("S_XYZ:", int(M_State_grbl)); } + + /** + * Output the current position (processed) to serial while moving + */ + void report_current_position_moving() { + + get_cartesian_from_steppers(); + const xyz_pos_t lpos = cartes.asLogical(); + SERIAL_ECHOPAIR("X:", lpos.x, " Y:", lpos.y, " Z:", lpos.z, " E:", current_position.e); + + stepper.report_positions(); + #if IS_SCARA + scara_report_positions(); + #endif + + report_current_grblstate_moving(); + } + + /** + * Set a Grbl-compatible state from the current marlin_state + */ + M_StateEnum grbl_state_for_marlin_state() { + switch (marlin_state) { + case MF_INITIALIZING: return M_INIT; + case MF_SD_COMPLETE: return M_ALARM; + case MF_WAITING: return M_IDLE; + case MF_STOPPED: return M_END; + case MF_RUNNING: return M_RUNNING; + case MF_PAUSED: return M_HOLD; + case MF_KILLED: return M_ERROR; + default: return M_IDLE; + } + } + +#endif + /** * Run out the planner buffer and re-sync the current * position from the last-updated stepper positions. @@ -241,6 +285,20 @@ void quickstop_stepper() { sync_plan_position(); } +#if ENABLED(REALTIME_REPORTING_COMMANDS) + + void quickpause_stepper() { + planner.quick_pause(); + //planner.synchronize(); + } + + void quickresume_stepper() { + planner.quick_resume(); + //planner.synchronize(); + } + +#endif + /** * Set the planner/stepper positions directly from current_position with * no kinematic translation. Used for homing axes and cartesian/core syncing. diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 2cfc8406a..647b3af52 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -211,14 +211,49 @@ void report_real_position(); void report_current_position(); void report_current_position_projected(); +#if EITHER(FULL_REPORT_TO_HOST_FEATURE, REALTIME_REPORTING_COMMANDS) + #define HAS_GRBL_STATE 1 + /** + * Machine states for GRBL or TinyG + */ + enum M_StateEnum : uint8_t { + M_INIT = 0, // 0 machine is initializing + M_RESET, // 1 machine is ready for use + M_ALARM, // 2 machine is in alarm state (soft shut down) + M_IDLE, // 3 program stop or no more blocks (M0, M1, M60) + M_END, // 4 program end via M2, M30 + M_RUNNING, // 5 motion is running + M_HOLD, // 6 motion is holding + M_PROBE, // 7 probe cycle active + M_CYCLING, // 8 machine is running (cycling) + M_HOMING, // 9 machine is homing + M_JOGGING, // 10 machine is jogging + M_ERROR // 11 machine is in hard alarm state (shut down) + }; + extern M_StateEnum M_State_grbl; + M_StateEnum grbl_state_for_marlin_state(); + void report_current_grblstate_moving(); + void report_current_position_moving(); + + #if ENABLED(FULL_REPORT_TO_HOST_FEATURE) + inline void set_and_report_grblstate(const M_StateEnum state) { + M_State_grbl = state; + report_current_grblstate_moving(); + } + #endif + + #if ENABLED(REALTIME_REPORTING_COMMANDS) + void quickpause_stepper(); + void quickresume_stepper(); + #endif +#endif + void get_cartesian_from_steppers(); void set_current_from_steppers_for_axis(const AxisEnum axis); void quickstop_stepper(); /** - * sync_plan_position - * * Set the planner/stepper positions directly from current_position with * no kinematic translation. Used for homing axes and cartesian/core syncing. */ diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index b528eb9d3..f11f27386 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1650,6 +1650,24 @@ void Planner::quick_stop() { stepper.quick_stop(); } +#if ENABLED(REALTIME_REPORTING_COMMANDS) + + void Planner::quick_pause() { + // Suspend until quick_resume is called + // Don't empty buffers or queues + const bool did_suspend = stepper.suspend(); + if (did_suspend) + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOLD)); + } + + // Resume if suspended + void Planner::quick_resume() { + TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(grbl_state_for_marlin_state())); + stepper.wake_up(); + } + +#endif + void Planner::endstop_triggered(const AxisEnum axis) { // Record stepper position and discard the current block stepper.endstop_triggered(axis); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 398339f04..30eeb758a 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -873,6 +873,13 @@ class Planner { // a Full Shutdown is required, or when endstops are hit) static void quick_stop(); + #if ENABLED(REALTIME_REPORTING_COMMANDS) + // Force a quick pause of the machine (e.g., when a pause is required in the middle of move). + // NOTE: Hard-stops will lose steps so encoders are highly recommended if using these! + static void quick_pause(); + static void quick_resume(); + #endif + // Called when an endstop is triggered. Causes the machine to stop inmediately static void endstop_triggered(const AxisEnum axis); diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768 index eef0857da..152a49852 100755 --- a/buildroot/tests/LPC1768 +++ b/buildroot/tests/LPC1768 @@ -26,8 +26,8 @@ restore_configs opt_set MOTHERBOARD BOARD_MKS_SBASE \ EXTRUDERS 2 TEMP_SENSOR_1 1 \ NUM_SERVOS 2 SERVO_DELAY '{ 300, 300 }' -opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR ULTIMAKERCONTROLLER -exec_test $1 $2 "MKS SBASE with SWITCHING_NOZZLE" "$3" +opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR ULTIMAKERCONTROLLER REALTIME_REPORTING_COMMANDS FULL_REPORT_TO_HOST_FEATURE +exec_test $1 $2 "MKS SBASE with SWITCHING_NOZZLE, Grbl Realtime Report" "$3" restore_configs opt_set MOTHERBOARD BOARD_RAMPS_14_RE_ARM_EEB \