From 4f992eb9ba503de30ebdf3c44b1a7bbbb9ff03c6 Mon Sep 17 00:00:00 2001 From: Silycr Date: Fri, 4 Nov 2022 21:00:14 +1030 Subject: [PATCH 1/7] Adding Line Error Resend Control Initial commit with Line Error Resend control to tackle resend loops with host >> printer high latency allowing GCode in flight. eg, Octoprint>[wifi]>ESP3D>>Printer Existing Resend method, clears RX_Buffer, sends request Unable to clear consecutive N lines already release from Octoprint host(In-flight). Printer receives expecting requested line, triggering additional resend request. Printer eventually receives correct line, multiple times, triggering further resend requests for next line. --- Marlin/Configuration_adv.h | 15 ++++++++++ Marlin/src/gcode/queue.cpp | 58 ++++++++++++++++++++++++++++++++++++-- Marlin/src/gcode/queue.h | 15 ++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 9a54b10b82b1..c82731f485dd 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2405,6 +2405,21 @@ //#define SERIAL_XON_XOFF #endif +/** + * Line Number Error Handler + * + * Add function to delay resend requests for line number + * errors, for Hosts that send N# line number with GCode. + * Prevents resend cycles causing stuttering and failure + * on systems with latency between Host and Printer. + * eg. Octoprint through ESP8266(WIFI) pass-through +*/ +#define RESEND_HANDLER +#if ENABLED(RESEND_HANDLER) + #define RESEND_HANDLER_DROP_GCODE 1 //Number of GCode lines to drop before resend request sent to Host. Octprint>>ESP3D; Min 5 + //#define RESEND_HANDLER_NOTICE //Send additional details to host terminal +#endif + #if ENABLED(SDSUPPORT) // Enable this option to collect and display the maximum // RX queue usage after transferring a file to SD. diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index a390a46d8e31..cc5f94b5d3bc 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -62,6 +62,9 @@ PGMSTR(G28_STR, "G28"); GCodeQueue::SerialState GCodeQueue::serial_state[NUM_SERIAL] = { 0 }; GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 }; +#if ENABLED(RESEND_HANDLER) + GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0 }; +#endif #if NO_TIMEOUTS > 0 static millis_t last_command_time = 0; @@ -280,6 +283,25 @@ void GCodeQueue::flush_and_request_resend(const serial_index_t serial_ind) { SERIAL_ECHOLNPGM(STR_OK); } +/** + * Notify host a resend has been skipped, with the offending and expected Line number + * Or + * send "ok" to keep comms alive +*/ + void GCodeQueue::ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N) { //~8ms to send @500000 through ESP8266(ESP3D WIFI)>>Octoprint + #if HAS_MULTI_SERIAL + if (!serial_ind.valid()) return; // Optimization here, skip if the command came from SD or Flash Drive + PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command + #endif + #if ENABLED(RESEND_HANDLER_NOTICE) + serial_echo_start(); // { serial_print(F("Echo:")); } + SERIAL_ECHOLNPGM("Host sent incorrect line : ", host_gcode_N); + serial_echo_start(); // { serial_print(F("Echo:")); } + SERIAL_ECHOLNPGM("Line expected : ", serial_state[serial_ind.index].last_N + 1); + #endif + SERIAL_ECHOLNPGM(STR_OK); //send Ok to continue action from Host + } + static bool serial_data_available(serial_index_t index) { const int a = SERIAL_IMPL.available(index); #if ENABLED(RX_BUFFER_MONITOR) && RX_BUFFER_SIZE @@ -467,11 +489,41 @@ void GCodeQueue::get_serial_commands() { if (n2pos) npos = n2pos; } - const long gcode_N = strtol(npos + 1, nullptr, 10); - + const long gcode_N = strtol(npos + 1, nullptr, 10); //Host sent GCode Line# from RX_buffer + + /** + * Resend Handler - Received line # != expected line number + * + * Standard behaviour - Clear RX_Buffer; resend request to host + * Extended behaviour - Allow ignore_resend_max # of errors to be ignored. + * Required when latency present between Marlin>>Host allowing GCode in-flight to cause comms issue + * on resend requests, such as stuttering and print failure. + * Ignore_resend_max should not exceed expected in-flight GCode + RX_Buffer. RX_Buffer is cleared in + * gcode_line_error, not ln_num_error_notice as next serial in buffer may be the required line. + */ if (gcode_N != serial.last_N + 1 && !M110) { // In case of error on a serial port, don't prevent other serial port from making progress - gcode_line_error(F(STR_ERR_LINE_NO), p); + #if ENABLED(RESEND_HANDLER) + const serial_index_t serial_ind = p; + + if ((resend_ctrl.ignore_resend_count < resend_ctrl.ignore_resend_max - 1)) { //Threshold eliminated resends + if(serial_state[serial_ind.index].last_N != resend_ctrl.last_error_N){ //Is first error instance + ln_num_error_notice(p, gcode_N); + resend_ctrl.last_error_N = serial_state[serial_ind.index].last_N; //Set last ignored error line + resend_ctrl.ignore_resend_count = 0; //Reset count as first instance + } + else { + ln_num_error_notice(p, gcode_N); + } + resend_ctrl.ignore_resend_count += 1; //Capture anything that doesn't fall in prev if_stmt. Nothing should miss + } + else{ //Exceeded maximum deleted requests or is a new resend request + resend_ctrl.ignore_resend_count = 0; //Reset counter + gcode_line_error(F(STR_ERR_LINE_NO), p); //Send resend request + } + #else + gcode_line_error(F(STR_ERR_LINE_NO), p); //Send resend request + #endif break; } diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index 142283008001..fb46514fcdc7 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -100,6 +100,21 @@ class GCodeQueue { inline char* peek_next_command_string() { return peek_next_command().buffer; } }; + /** + * Resend handler to deal with Host>>Printer latency + */ + #if ENABLED(RESEND_HANDLER) + struct ResendCtrl { + long last_error_N = 0; //Record the last requested resend line number + uint8_t ignore_resend_count = 0; + const uint8_t ignore_resend_max = RESEND_HANDLER_DROP_GCODE; //Number of resends requests deleted //LH this can be constant + }; + + static ResendCtrl resend_ctrl; //resend ctrl variables + + static void ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N); + #endif + /** * The ring buffer of commands */ From ad882f3099746042f275083cf6021c4422ef60bf Mon Sep 17 00:00:00 2001 From: Silycr Date: Thu, 10 Nov 2022 21:19:48 +1030 Subject: [PATCH 2/7] Fixed missing directive --- Marlin/src/gcode/queue.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index cc5f94b5d3bc..bb0514d0cfb2 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -288,19 +288,21 @@ void GCodeQueue::flush_and_request_resend(const serial_index_t serial_ind) { * Or * send "ok" to keep comms alive */ +#if ENABLED(RESEND_HANDLER) void GCodeQueue::ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N) { //~8ms to send @500000 through ESP8266(ESP3D WIFI)>>Octoprint #if HAS_MULTI_SERIAL if (!serial_ind.valid()) return; // Optimization here, skip if the command came from SD or Flash Drive PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command #endif - #if ENABLED(RESEND_HANDLER_NOTICE) + #if ENABLED(RESEND_HANDLER_NOTICE) //Notify Host of issue serial_echo_start(); // { serial_print(F("Echo:")); } SERIAL_ECHOLNPGM("Host sent incorrect line : ", host_gcode_N); serial_echo_start(); // { serial_print(F("Echo:")); } SERIAL_ECHOLNPGM("Line expected : ", serial_state[serial_ind.index].last_N + 1); #endif - SERIAL_ECHOLNPGM(STR_OK); //send Ok to continue action from Host + SERIAL_ECHOLNPGM(STR_OK); //Send Ok to continue action from Host } +#endif static bool serial_data_available(serial_index_t index) { const int a = SERIAL_IMPL.available(index); From 840e0edfd7ec37b4e9eafe1f9e2c96e8b2edbb73 Mon Sep 17 00:00:00 2001 From: Silycr Date: Thu, 10 Nov 2022 22:23:07 +1030 Subject: [PATCH 3/7] Rectified incorrect variables initialisation --- Marlin/src/gcode/queue.cpp | 2 +- Marlin/src/gcode/queue.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index bb0514d0cfb2..4ed164a25839 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -63,7 +63,7 @@ PGMSTR(G28_STR, "G28"); GCodeQueue::SerialState GCodeQueue::serial_state[NUM_SERIAL] = { 0 }; GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 }; #if ENABLED(RESEND_HANDLER) - GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0 }; + GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0 , 0 , RESEND_HANDLER_DROP_GCODE }; #endif #if NO_TIMEOUTS > 0 diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index fb46514fcdc7..48d7c5ce9178 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -105,9 +105,9 @@ class GCodeQueue { */ #if ENABLED(RESEND_HANDLER) struct ResendCtrl { - long last_error_N = 0; //Record the last requested resend line number - uint8_t ignore_resend_count = 0; - const uint8_t ignore_resend_max = RESEND_HANDLER_DROP_GCODE; //Number of resends requests deleted //LH this can be constant + long last_error_N; //Record the last requested resend line number + uint8_t ignore_resend_count; + const uint8_t ignore_resend_max; //Number of resends requests deleted //LH this can be constant }; static ResendCtrl resend_ctrl; //resend ctrl variables From b8ae984d2fb5a67819b325dfb90701fe47b49f1b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 26 Nov 2022 21:34:48 -0600 Subject: [PATCH 4/7] misc. cleanup --- Marlin/Configuration_adv.h | 17 ++++++++--------- Marlin/src/gcode/queue.cpp | 35 +++++++++++++++++------------------ Marlin/src/gcode/queue.h | 8 ++++---- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index c82731f485dd..b65132a18568 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2407,17 +2407,16 @@ /** * Line Number Error Handler - * - * Add function to delay resend requests for line number - * errors, for Hosts that send N# line number with GCode. - * Prevents resend cycles causing stuttering and failure - * on systems with latency between Host and Printer. - * eg. Octoprint through ESP8266(WIFI) pass-through + * + * Add function to delay resend requests for line number errors, for Hosts that + * send N# line number with G-code. Prevents resend cycles causing stuttering + * and failure on systems with Host <-> Printer latency. + * e.g., Octoprint through ESP8266 (WIFI) pass-through. */ -#define RESEND_HANDLER +//#define RESEND_HANDLER #if ENABLED(RESEND_HANDLER) - #define RESEND_HANDLER_DROP_GCODE 1 //Number of GCode lines to drop before resend request sent to Host. Octprint>>ESP3D; Min 5 - //#define RESEND_HANDLER_NOTICE //Send additional details to host terminal + #define RESEND_HANDLER_DROP_GCODE 1 // Number of G-code lines to drop before resend request sent to Host. Octprint>>ESP3D; Min 5 + //#define RESEND_HANDLER_NOTICE // Send additional details to host terminal #endif #if ENABLED(SDSUPPORT) diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 4ed164a25839..06c9e00dacd5 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -63,7 +63,7 @@ PGMSTR(G28_STR, "G28"); GCodeQueue::SerialState GCodeQueue::serial_state[NUM_SERIAL] = { 0 }; GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 }; #if ENABLED(RESEND_HANDLER) - GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0 , 0 , RESEND_HANDLER_DROP_GCODE }; + GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0, 0, RESEND_HANDLER_DROP_GCODE }; #endif #if NO_TIMEOUTS > 0 @@ -491,40 +491,39 @@ void GCodeQueue::get_serial_commands() { if (n2pos) npos = n2pos; } - const long gcode_N = strtol(npos + 1, nullptr, 10); //Host sent GCode Line# from RX_buffer + const long gcode_N = strtol(npos + 1, nullptr, 10); // Host sent G-code Line# from RX_buffer /** * Resend Handler - Received line # != expected line number - * + * * Standard behaviour - Clear RX_Buffer; resend request to host - * Extended behaviour - Allow ignore_resend_max # of errors to be ignored. - * Required when latency present between Marlin>>Host allowing GCode in-flight to cause comms issue + * Extended behaviour - Allow ignore_resend_max # of errors to be ignored. + * Required when latency present between Marlin>>Host allowing G-code in-flight to cause comms issue * on resend requests, such as stuttering and print failure. - * Ignore_resend_max should not exceed expected in-flight GCode + RX_Buffer. RX_Buffer is cleared in + * Ignore_resend_max should not exceed expected in-flight G-code + RX_Buffer. RX_Buffer is cleared in * gcode_line_error, not ln_num_error_notice as next serial in buffer may be the required line. - */ + */ if (gcode_N != serial.last_N + 1 && !M110) { // In case of error on a serial port, don't prevent other serial port from making progress #if ENABLED(RESEND_HANDLER) const serial_index_t serial_ind = p; - if ((resend_ctrl.ignore_resend_count < resend_ctrl.ignore_resend_max - 1)) { //Threshold eliminated resends - if(serial_state[serial_ind.index].last_N != resend_ctrl.last_error_N){ //Is first error instance + if ((resend_ctrl.ignore_resend_count < resend_ctrl.ignore_resend_max - 1)) { // Threshold eliminated resends + if (serial_state[serial_ind.index].last_N != resend_ctrl.last_error_N) { // Is first error instance ln_num_error_notice(p, gcode_N); - resend_ctrl.last_error_N = serial_state[serial_ind.index].last_N; //Set last ignored error line - resend_ctrl.ignore_resend_count = 0; //Reset count as first instance + resend_ctrl.last_error_N = serial_state[serial_ind.index].last_N; // Set last ignored error line + resend_ctrl.ignore_resend_count = 0; // Reset count as first instance } - else { + else ln_num_error_notice(p, gcode_N); - } - resend_ctrl.ignore_resend_count += 1; //Capture anything that doesn't fall in prev if_stmt. Nothing should miss + resend_ctrl.ignore_resend_count += 1; // Capture anything that doesn't fall in prev if_stmt. Nothing should miss } - else{ //Exceeded maximum deleted requests or is a new resend request - resend_ctrl.ignore_resend_count = 0; //Reset counter - gcode_line_error(F(STR_ERR_LINE_NO), p); //Send resend request + else { // Exceeded maximum deleted requests or is a new resend request + resend_ctrl.ignore_resend_count = 0; // Reset counter + gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request } #else - gcode_line_error(F(STR_ERR_LINE_NO), p); //Send resend request + gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request #endif break; } diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index 48d7c5ce9178..5a48bfaeff14 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -102,15 +102,15 @@ class GCodeQueue { /** * Resend handler to deal with Host>>Printer latency - */ + */ #if ENABLED(RESEND_HANDLER) struct ResendCtrl { - long last_error_N; //Record the last requested resend line number + long last_error_N; // Record the last requested resend line number uint8_t ignore_resend_count; - const uint8_t ignore_resend_max; //Number of resends requests deleted //LH this can be constant + const uint8_t ignore_resend_max; // Number of resends requests deleted //LH this can be constant }; - static ResendCtrl resend_ctrl; //resend ctrl variables + static ResendCtrl resend_ctrl; // Resend ctrl variables static void ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N); #endif From cea14751dbb102f024e1a029a8c45e10bb00677b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 27 Nov 2022 22:56:52 -0600 Subject: [PATCH 5/7] tweaks --- Marlin/Configuration_adv.h | 2 +- Marlin/src/core/language.h | 2 ++ Marlin/src/gcode/queue.cpp | 56 ++++++++++++++++++-------------------- Marlin/src/gcode/queue.h | 8 +++--- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index b65132a18568..2c320ad545a0 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2416,7 +2416,7 @@ //#define RESEND_HANDLER #if ENABLED(RESEND_HANDLER) #define RESEND_HANDLER_DROP_GCODE 1 // Number of G-code lines to drop before resend request sent to Host. Octprint>>ESP3D; Min 5 - //#define RESEND_HANDLER_NOTICE // Send additional details to host terminal + //#define RESEND_HANDLER_NOTICE // Echo resend details to the host terminal #endif #if ENABLED(SDSUPPORT) diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 545f9df6410b..eb3e59c00a08 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -119,6 +119,8 @@ #define STR_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line: " #define STR_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: " #define STR_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: " +#define STR_HOST_RESEND_1 "Host sent incorrect line : " +#define STR_HOST_RESEND_2 "Line expected : " #define STR_FILE_PRINTED "Done printing file" #define STR_NO_MEDIA "No media" #define STR_BEGIN_FILE_LIST "Begin file list" diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 06c9e00dacd5..ee7e22dca7f7 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -63,7 +63,7 @@ PGMSTR(G28_STR, "G28"); GCodeQueue::SerialState GCodeQueue::serial_state[NUM_SERIAL] = { 0 }; GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 }; #if ENABLED(RESEND_HANDLER) - GCodeQueue::ResendCtrl GCodeQueue::resend_ctrl = { 0, 0, RESEND_HANDLER_DROP_GCODE }; + GCodeQueue::ResendInfo GCodeQueue::resend_info = { 0, 0, RESEND_HANDLER_DROP_GCODE }; #endif #if NO_TIMEOUTS > 0 @@ -289,18 +289,16 @@ void GCodeQueue::flush_and_request_resend(const serial_index_t serial_ind) { * send "ok" to keep comms alive */ #if ENABLED(RESEND_HANDLER) - void GCodeQueue::ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N) { //~8ms to send @500000 through ESP8266(ESP3D WIFI)>>Octoprint + void GCodeQueue::ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N) { // ~8ms to send @500000 through ESP8266(ESP3D WIFI)>>Octoprint #if HAS_MULTI_SERIAL - if (!serial_ind.valid()) return; // Optimization here, skip if the command came from SD or Flash Drive + //if (!serial_ind.valid()) return; // Optimization here, skip if the command came from SD or Flash Drive PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command #endif - #if ENABLED(RESEND_HANDLER_NOTICE) //Notify Host of issue - serial_echo_start(); // { serial_print(F("Echo:")); } - SERIAL_ECHOLNPGM("Host sent incorrect line : ", host_gcode_N); - serial_echo_start(); // { serial_print(F("Echo:")); } - SERIAL_ECHOLNPGM("Line expected : ", serial_state[serial_ind.index].last_N + 1); + #if ENABLED(RESEND_HANDLER_NOTICE) // Notify the host + SERIAL_ECHO_MSG(STR_HOST_RESEND_1, host_gcode_N); + SERIAL_ECHO_MSG(STR_HOST_RESEND_2, serial_state[serial_ind.index].last_N + 1); #endif - SERIAL_ECHOLNPGM(STR_OK); //Send Ok to continue action from Host + SERIAL_ECHOLNPGM(STR_OK); // Send OK to satisfy the host } #endif @@ -496,35 +494,33 @@ void GCodeQueue::get_serial_commands() { /** * Resend Handler - Received line # != expected line number * - * Standard behaviour - Clear RX_Buffer; resend request to host - * Extended behaviour - Allow ignore_resend_max # of errors to be ignored. - * Required when latency present between Marlin>>Host allowing G-code in-flight to cause comms issue - * on resend requests, such as stuttering and print failure. - * Ignore_resend_max should not exceed expected in-flight G-code + RX_Buffer. RX_Buffer is cleared in + * - Clear RX_Buffer; resend request to host + * + * With RESEND_HANDLER: + * - Ignore errors up to 'ignore_resend_max' times before sending the request + * + * When latency exists between Marlin and the Host, the ongoing G-code stream can cause + * issues on resend requests, such as stuttering layer shifting. + * + * ignore_resend_max should not exceed expected in-flight G-code + RX_Buffer. RX_Buffer is cleared in * gcode_line_error, not ln_num_error_notice as next serial in buffer may be the required line. */ if (gcode_N != serial.last_N + 1 && !M110) { - // In case of error on a serial port, don't prevent other serial port from making progress #if ENABLED(RESEND_HANDLER) + // On serial error try to keep other serial ports alive const serial_index_t serial_ind = p; - - if ((resend_ctrl.ignore_resend_count < resend_ctrl.ignore_resend_max - 1)) { // Threshold eliminated resends - if (serial_state[serial_ind.index].last_N != resend_ctrl.last_error_N) { // Is first error instance - ln_num_error_notice(p, gcode_N); - resend_ctrl.last_error_N = serial_state[serial_ind.index].last_N; // Set last ignored error line - resend_ctrl.ignore_resend_count = 0; // Reset count as first instance + if (resend_info.ignore_resend_count < resend_info.ignore_resend_max - 1) { // Threshold eliminated resends + ln_num_error_notice(p, gcode_N); + if (resend_info.last_error_N != serial_state[serial_ind.index].last_N) { // Is first error instance + resend_info.last_error_N = serial_state[serial_ind.index].last_N; // Set last ignored error line + resend_info.ignore_resend_count = 0; // Reset count for the new line } - else - ln_num_error_notice(p, gcode_N); - resend_ctrl.ignore_resend_count += 1; // Capture anything that doesn't fall in prev if_stmt. Nothing should miss - } - else { // Exceeded maximum deleted requests or is a new resend request - resend_ctrl.ignore_resend_count = 0; // Reset counter - gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request + resend_info.ignore_resend_count += 1; // Capture anything that doesn't fall in prev if_stmt. Nothing should miss + break; } - #else - gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request + resend_info.ignore_resend_count = 0; // Reset counter #endif + gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request break; } diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index 5a48bfaeff14..49dcececd794 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -104,13 +104,13 @@ class GCodeQueue { * Resend handler to deal with Host>>Printer latency */ #if ENABLED(RESEND_HANDLER) - struct ResendCtrl { + struct ResendInfo { long last_error_N; // Record the last requested resend line number - uint8_t ignore_resend_count; - const uint8_t ignore_resend_max; // Number of resends requests deleted //LH this can be constant + uint8_t ignore_resend_count; // Line error counter + const uint8_t ignore_resend_max; // Number of resend requests thrown away (can be constant) }; - static ResendCtrl resend_ctrl; // Resend ctrl variables + static ResendInfo resend_info; // Resend info encapsulated static void ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N); #endif From 180e2ba18c517c83632967e9a5f4aa4f6dd187c8 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 27 Nov 2022 23:14:08 -0600 Subject: [PATCH 6/7] simplified solution --- Marlin/Configuration_adv.h | 14 --------- Marlin/src/core/language.h | 2 -- Marlin/src/gcode/queue.cpp | 62 +++++--------------------------------- Marlin/src/gcode/queue.h | 15 --------- 4 files changed, 7 insertions(+), 86 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 2c320ad545a0..9a54b10b82b1 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2405,20 +2405,6 @@ //#define SERIAL_XON_XOFF #endif -/** - * Line Number Error Handler - * - * Add function to delay resend requests for line number errors, for Hosts that - * send N# line number with G-code. Prevents resend cycles causing stuttering - * and failure on systems with Host <-> Printer latency. - * e.g., Octoprint through ESP8266 (WIFI) pass-through. -*/ -//#define RESEND_HANDLER -#if ENABLED(RESEND_HANDLER) - #define RESEND_HANDLER_DROP_GCODE 1 // Number of G-code lines to drop before resend request sent to Host. Octprint>>ESP3D; Min 5 - //#define RESEND_HANDLER_NOTICE // Echo resend details to the host terminal -#endif - #if ENABLED(SDSUPPORT) // Enable this option to collect and display the maximum // RX queue usage after transferring a file to SD. diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index eb3e59c00a08..545f9df6410b 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -119,8 +119,6 @@ #define STR_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line: " #define STR_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: " #define STR_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: " -#define STR_HOST_RESEND_1 "Host sent incorrect line : " -#define STR_HOST_RESEND_2 "Line expected : " #define STR_FILE_PRINTED "Done printing file" #define STR_NO_MEDIA "No media" #define STR_BEGIN_FILE_LIST "Begin file list" diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index ee7e22dca7f7..c951fc633364 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -62,9 +62,6 @@ PGMSTR(G28_STR, "G28"); GCodeQueue::SerialState GCodeQueue::serial_state[NUM_SERIAL] = { 0 }; GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 }; -#if ENABLED(RESEND_HANDLER) - GCodeQueue::ResendInfo GCodeQueue::resend_info = { 0, 0, RESEND_HANDLER_DROP_GCODE }; -#endif #if NO_TIMEOUTS > 0 static millis_t last_command_time = 0; @@ -283,25 +280,6 @@ void GCodeQueue::flush_and_request_resend(const serial_index_t serial_ind) { SERIAL_ECHOLNPGM(STR_OK); } -/** - * Notify host a resend has been skipped, with the offending and expected Line number - * Or - * send "ok" to keep comms alive -*/ -#if ENABLED(RESEND_HANDLER) - void GCodeQueue::ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N) { // ~8ms to send @500000 through ESP8266(ESP3D WIFI)>>Octoprint - #if HAS_MULTI_SERIAL - //if (!serial_ind.valid()) return; // Optimization here, skip if the command came from SD or Flash Drive - PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command - #endif - #if ENABLED(RESEND_HANDLER_NOTICE) // Notify the host - SERIAL_ECHO_MSG(STR_HOST_RESEND_1, host_gcode_N); - SERIAL_ECHO_MSG(STR_HOST_RESEND_2, serial_state[serial_ind.index].last_N + 1); - #endif - SERIAL_ECHOLNPGM(STR_OK); // Send OK to satisfy the host - } -#endif - static bool serial_data_available(serial_index_t index) { const int a = SERIAL_IMPL.available(index); #if ENABLED(RX_BUFFER_MONITOR) && RX_BUFFER_SIZE @@ -489,38 +467,14 @@ void GCodeQueue::get_serial_commands() { if (n2pos) npos = n2pos; } - const long gcode_N = strtol(npos + 1, nullptr, 10); // Host sent G-code Line# from RX_buffer - - /** - * Resend Handler - Received line # != expected line number - * - * - Clear RX_Buffer; resend request to host - * - * With RESEND_HANDLER: - * - Ignore errors up to 'ignore_resend_max' times before sending the request - * - * When latency exists between Marlin and the Host, the ongoing G-code stream can cause - * issues on resend requests, such as stuttering layer shifting. - * - * ignore_resend_max should not exceed expected in-flight G-code + RX_Buffer. RX_Buffer is cleared in - * gcode_line_error, not ln_num_error_notice as next serial in buffer may be the required line. - */ + const long gcode_N = strtol(npos + 1, nullptr, 10); + + // The line number must be in the correct sequence. if (gcode_N != serial.last_N + 1 && !M110) { - #if ENABLED(RESEND_HANDLER) - // On serial error try to keep other serial ports alive - const serial_index_t serial_ind = p; - if (resend_info.ignore_resend_count < resend_info.ignore_resend_max - 1) { // Threshold eliminated resends - ln_num_error_notice(p, gcode_N); - if (resend_info.last_error_N != serial_state[serial_ind.index].last_N) { // Is first error instance - resend_info.last_error_N = serial_state[serial_ind.index].last_N; // Set last ignored error line - resend_info.ignore_resend_count = 0; // Reset count for the new line - } - resend_info.ignore_resend_count += 1; // Capture anything that doesn't fall in prev if_stmt. Nothing should miss - break; - } - resend_info.ignore_resend_count = 0; // Reset counter - #endif - gcode_line_error(F(STR_ERR_LINE_NO), p); // Send resend request + // A request-for-resend line was already in transit so we got two - oops! + if (WITHIN(gcode_N, serial.last_N - 1, serial.last_N)) continue; + // A corrupted line or too high, indicating a lost line + gcode_line_error(F(STR_ERR_LINE_NO), p); break; } @@ -529,13 +483,11 @@ void GCodeQueue::get_serial_commands() { uint8_t checksum = 0, count = uint8_t(apos - command); while (count) checksum ^= command[--count]; if (strtol(apos + 1, nullptr, 10) != checksum) { - // In case of error on a serial port, don't prevent other serial port from making progress gcode_line_error(F(STR_ERR_CHECKSUM_MISMATCH), p); break; } } else { - // In case of error on a serial port, don't prevent other serial port from making progress gcode_line_error(F(STR_ERR_NO_CHECKSUM), p); break; } diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index 49dcececd794..142283008001 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -100,21 +100,6 @@ class GCodeQueue { inline char* peek_next_command_string() { return peek_next_command().buffer; } }; - /** - * Resend handler to deal with Host>>Printer latency - */ - #if ENABLED(RESEND_HANDLER) - struct ResendInfo { - long last_error_N; // Record the last requested resend line number - uint8_t ignore_resend_count; // Line error counter - const uint8_t ignore_resend_max; // Number of resend requests thrown away (can be constant) - }; - - static ResendInfo resend_info; // Resend info encapsulated - - static void ln_num_error_notice(const serial_index_t serial_ind, const long host_gcode_N); - #endif - /** * The ring buffer of commands */ From ac46b1e977542127e23f9ac621efb580c5aafd66 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sat, 26 Nov 2022 21:40:40 -0600 Subject: [PATCH 7/7] *** CI TEST ONLY *** --- .github/workflows/test-builds.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-builds.yml b/.github/workflows/test-builds.yml index 5a18a2e8bf60..2ec3187da1dc 100644 --- a/.github/workflows/test-builds.yml +++ b/.github/workflows/test-builds.yml @@ -144,7 +144,6 @@ jobs: - name: Install PlatformIO run: | pip install -U platformio - pio upgrade --dev pio pkg update --global - name: Run ${{ matrix.test-platform }} Tests