Send a Busy signal to hosts during long processes, wait for input, etc

If Marlin is blocking the serial input or command queue for any length
of time (for example more than 2 seconds), it needs to send a message
to serial out to inform the host that it is busy. Marlin should only
send these messages out when busy, and preferably not when trying to
print formatted output.
This commit is contained in:
Scott Lahteine
2016-03-07 03:48:14 -08:00
parent 7d25c107a8
commit 7ec7bb31c4
22 changed files with 234 additions and 3 deletions

View File

@ -426,6 +426,26 @@ static uint8_t target_extruder;
int lpq_len = 20;
#endif
#if ENABLED(HOST_KEEPALIVE_FEATURE)
// States for managing Marlin and host communication
// Marlin sends messages if blocked or busy
enum MarlinBusyState {
NOT_BUSY, // Not in a handler
IN_HANDLER, // Processing a GCode
IN_PROCESS, // Known to be blocking command input (as in G29)
PAUSED_FOR_USER, // Blocking pending any input
PAUSED_FOR_INPUT // Blocking pending text input (concept)
};
static MarlinBusyState busy_state = NOT_BUSY;
static millis_t next_busy_signal_ms = -1;
#define KEEPALIVE_STATE(n) do{ busy_state = n; }while(0)
#else
#define host_keepalive() ;
#define KEEPALIVE_STATE(n) ;
#endif // HOST_KEEPALIVE_FEATURE
//===========================================================================
//================================ Functions ================================
//===========================================================================
@ -2130,6 +2150,35 @@ void unknown_command_error() {
SERIAL_ECHOPGM("\"\n");
}
#if ENABLED(HOST_KEEPALIVE_FEATURE)
void host_keepalive() {
millis_t ms = millis();
if (busy_state != NOT_BUSY) {
if (ms < next_busy_signal_ms) return;
switch (busy_state) {
case NOT_BUSY:
break;
case IN_HANDLER:
case IN_PROCESS:
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_BUSY_PROCESSING);
break;
case PAUSED_FOR_USER:
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_USER);
break;
case PAUSED_FOR_INPUT:
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_INPUT);
break;
}
}
next_busy_signal_ms = ms + 2000UL;
}
#endif //HOST_KEEPALIVE_FEATURE
/**
* G0, G1: Coordinated movement of X Y Z E axes
*/
@ -3219,6 +3268,8 @@ inline void gcode_G28() {
st_synchronize();
#endif
KEEPALIVE_STATE(IN_HANDLER);
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (marlin_debug_flags & DEBUG_LEVELING) {
SERIAL_ECHOLNPGM("<<< gcode_G29");
@ -3325,12 +3376,16 @@ inline void gcode_G92() {
refresh_cmd_timeout();
if (codenum > 0) {
codenum += previous_cmd_ms; // wait until this time for a click
KEEPALIVE_STATE(PAUSED_FOR_USER);
while (millis() < codenum && !lcd_clicked()) idle();
KEEPALIVE_STATE(IN_HANDLER);
lcd_ignore_click(false);
}
else {
if (!lcd_detected()) return;
KEEPALIVE_STATE(PAUSED_FOR_USER);
while (!lcd_clicked()) idle();
KEEPALIVE_STATE(IN_HANDLER);
}
if (IS_SD_PRINTING)
LCD_MESSAGEPGM(MSG_RESUMING);
@ -4963,6 +5018,8 @@ inline void gcode_M303() {
if (e >=0 && e < EXTRUDERS)
target_extruder = e;
KEEPALIVE_STATE(NOT_BUSY);
PID_autotune(temp, e, c);
}
@ -5334,6 +5391,13 @@ inline void gcode_M503() {
#if ENABLED(FILAMENTCHANGEENABLE)
inline void idle2() {
manage_heater();
manage_inactivity(true);
host_keepalive();
lcd_update();
}
/**
* M600: Pause for filament change
*
@ -5412,6 +5476,7 @@ inline void gcode_M503() {
delay(100);
LCD_ALERTMESSAGEPGM(MSG_FILAMENTCHANGE);
millis_t next_tick = 0;
KEEPALIVE_STATE(WAIT_FOR_USER);
while (!lcd_clicked()) {
#if DISABLED(AUTO_FILAMENT_CHANGE)
millis_t ms = millis();
@ -5419,9 +5484,7 @@ inline void gcode_M503() {
lcd_quick_feedback();
next_tick = ms + 2500; // feedback every 2.5s while waiting
}
manage_heater();
manage_inactivity(true);
lcd_update();
idle2();
#else
current_position[E_AXIS] += AUTO_FILAMENT_CHANGE_LENGTH;
destination[E_AXIS] = current_position[E_AXIS];
@ -5429,6 +5492,7 @@ inline void gcode_M503() {
st_synchronize();
#endif
} // while(!lcd_clicked)
KEEPALIVE_STATE(IN_HANDLER);
lcd_quick_feedback(); // click sound feedback
#if ENABLED(AUTO_FILAMENT_CHANGE)
@ -5765,6 +5829,8 @@ void process_next_command() {
seen_pointer = current_command;
codenum = code_value_short();
KEEPALIVE_STATE(IN_HANDLER);
// Handle a known G, M, or T
switch (command_code) {
case 'G': switch (codenum) {
@ -6286,6 +6352,8 @@ void process_next_command() {
default: code_is_good = false;
}
KEEPALIVE_STATE(NOT_BUSY);
ExitUnknownCommand:
// Still unknown command? Throw an error
@ -6975,6 +7043,7 @@ void disable_all_steppers() {
void idle() {
manage_heater();
manage_inactivity();
host_keepalive();
lcd_update();
}