Add M576 which allows reporting of queue statistics, specifically planner/command buffer space remaining, as well as command buffer underruns, and time the command buffer remained empty since last M576 output
This commit is contained in:
parent
1403260487
commit
e874558381
7 changed files with 149 additions and 1 deletions
|
|
@ -1958,6 +1958,15 @@
|
|||
// Some clients will have this feature soon. This could make the NO_TIMEOUTS unnecessary.
|
||||
//#define ADVANCED_OK
|
||||
|
||||
/**
|
||||
* Buffer monitoring
|
||||
*
|
||||
* To help diagnose print quality issues stemming from command buffers being empty,
|
||||
* we add M576 which enables reporting of buffer empty
|
||||
*/
|
||||
|
||||
#define BUFFER_MONITORING
|
||||
|
||||
// Printrun may have trouble receiving long strings all at once.
|
||||
// This option inserts short delays between lines of serial output.
|
||||
#define SERIAL_OVERRUN_PROTECTION
|
||||
|
|
|
|||
|
|
@ -761,6 +761,10 @@ void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
|
|||
if (!gcode.autoreport_paused) {
|
||||
TERN_(AUTO_REPORT_TEMPERATURES, thermalManager.auto_report_temperatures());
|
||||
TERN_(AUTO_REPORT_SD_STATUS, card.auto_report_sd_status());
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
queue.auto_report_buffer_statistics();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -770,6 +770,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
|
|||
case 575: M575(); break; // M575: Set serial baudrate
|
||||
#endif
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING) // M576: Buffer monitoring
|
||||
case 576: M576(); break;
|
||||
#endif
|
||||
|
||||
#if ENABLED(ADVANCED_PAUSE_FEATURE)
|
||||
case 600: M600(); break; // M600: Pause for Filament Change
|
||||
case 603: M603(); break; // M603: Configure Filament Change
|
||||
|
|
|
|||
|
|
@ -779,6 +779,8 @@ private:
|
|||
|
||||
TERN_(BAUD_RATE_GCODE, static void M575());
|
||||
|
||||
TERN_(BUFFER_MONITORING, static void M576());
|
||||
|
||||
#if ENABLED(ADVANCED_PAUSE_FEATURE)
|
||||
static void M600();
|
||||
static void M603();
|
||||
|
|
|
|||
|
|
@ -85,6 +85,20 @@ static int serial_count[NUM_SERIAL] = { 0 };
|
|||
|
||||
bool send_ok[BUFSIZE];
|
||||
|
||||
/*
|
||||
* Track buffer underruns
|
||||
*/
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
uint32_t GCodeQueue::command_buffer_underruns = 0;
|
||||
bool GCodeQueue::command_buffer_empty = false;
|
||||
|
||||
millis_t GCodeQueue::max_command_buffer_empty_duration = 0;
|
||||
millis_t GCodeQueue::command_buffer_empty_at = 0;
|
||||
|
||||
uint8_t GCodeQueue::auto_buffer_report_interval;
|
||||
millis_t GCodeQueue::next_buffer_report_ms;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Next Injected PROGMEM Command pointer. (nullptr == empty)
|
||||
* Internal commands are enqueued ahead of serial / SD commands.
|
||||
|
|
@ -613,7 +627,26 @@ void GCodeQueue::advance() {
|
|||
if (process_injected_command_P() || process_injected_command()) return;
|
||||
|
||||
// Return if the G-code buffer is empty
|
||||
if (!length) return;
|
||||
if (!length) {
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
if (!command_buffer_empty) {
|
||||
command_buffer_empty = true;
|
||||
command_buffer_underruns++;
|
||||
command_buffer_empty_at = millis();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
static millis_t command_buffer_empty_duration;
|
||||
command_buffer_empty_duration = millis() - command_buffer_empty_at;
|
||||
if (command_buffer_empty_duration > max_command_buffer_empty_duration) {
|
||||
max_command_buffer_empty_duration = command_buffer_empty_duration;
|
||||
}
|
||||
command_buffer_empty = false;
|
||||
#endif
|
||||
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
|
|
@ -658,3 +691,27 @@ void GCodeQueue::advance() {
|
|||
if (++index_r >= BUFSIZE) index_r = 0;
|
||||
|
||||
}
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
void GCodeQueue::report_buffer_statistics() {
|
||||
SERIAL_ECHO("M576");
|
||||
SERIAL_ECHOLNPAIR(SP_P_STR, int(planner.moves_free()),
|
||||
SP_B_STR, int(BUFSIZE - length),
|
||||
" BU", queue.command_buffer_underruns,
|
||||
" BD", queue.max_command_buffer_empty_duration,
|
||||
);
|
||||
|
||||
command_buffer_underruns = 0;
|
||||
max_command_buffer_empty_duration = 0;
|
||||
}
|
||||
|
||||
void GCodeQueue::auto_report_buffer_statistics() {
|
||||
if (queue.auto_buffer_report_interval && ELAPSED(millis(), queue.next_buffer_report_ms)) {
|
||||
queue.next_buffer_report_ms = millis() + 1000UL * queue.auto_buffer_report_interval;
|
||||
PORT_REDIRECT(SERIAL_BOTH);
|
||||
report_buffer_statistics();
|
||||
PORT_RESTORE();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -147,6 +147,35 @@ public:
|
|||
*/
|
||||
static void flush_and_request_resend();
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
/*
|
||||
* Track buffer underruns
|
||||
*/
|
||||
static uint32_t command_buffer_underruns;
|
||||
static bool command_buffer_empty;
|
||||
static millis_t max_command_buffer_empty_duration;
|
||||
static millis_t command_buffer_empty_at;
|
||||
|
||||
/**
|
||||
* Report buffer statistics to the host to be able to detect buffer underruns
|
||||
*
|
||||
* Returns "M576 " followed by:
|
||||
* P<uint> Planner space remaining
|
||||
* B<uint> Command buffer space remaining
|
||||
* U<uint> Number of command buffer underruns since last report
|
||||
*/
|
||||
static void report_buffer_statistics();
|
||||
|
||||
static uint8_t auto_buffer_report_interval;
|
||||
static millis_t next_buffer_report_ms;
|
||||
static void auto_report_buffer_statistics();
|
||||
static inline void set_auto_report_interval(uint8_t v) {
|
||||
NOMORE(v, 60);
|
||||
auto_buffer_report_interval = v;
|
||||
next_buffer_report_ms = millis() + 1000UL * v;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
static uint8_t index_w; // Ring buffer write position
|
||||
|
|
|
|||
43
Marlin/src/gcode/stats/M576.cpp
Normal file
43
Marlin/src/gcode/stats/M576.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
#include "../../MarlinCore.h" // for SP_P/B_STR, etc.
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../queue.h"
|
||||
|
||||
/**
|
||||
* M576: Return buffer stats, and optionally set auto-report interval. M576 [S<seconds>]
|
||||
*/
|
||||
void GcodeSuite::M576() {
|
||||
if (parser.seenval('S')) {
|
||||
queue.set_auto_report_interval((uint8_t)parser.value_byte());
|
||||
}
|
||||
|
||||
queue.report_buffer_statistics();
|
||||
}
|
||||
|
||||
#endif // BUFFER_MONITORING
|
||||
Loading…
Add table
Add a link
Reference in a new issue