-
-
Notifications
You must be signed in to change notification settings - Fork 19.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide feedback to hosts when busy #3109
Provide feedback to hosts when busy #3109
Conversation
@@ -129,6 +129,9 @@ | |||
#define MSG_COUNT_A " Count A: " | |||
#define MSG_ERR_KILLED "Printer halted. kill() called!" | |||
#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)" | |||
#define MSG_BUSY_SIGNAL "Busy" | |||
#define MSG_WAITING_FOR_USER "Paused for user" | |||
#define MSG_WAITING_FOR_INPUT "Paused for input" | |||
#define MSG_RESEND "Resend: " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a "Busy: " prefix could simplify parsing for the host - it had to check for only one expression.
Anything containing a "...wait..." is not a good idea - already used.
fa36983
to
0bb6fd8
Compare
@@ -129,6 +129,9 @@ | |||
#define MSG_COUNT_A " Count A: " | |||
#define MSG_ERR_KILLED "Printer halted. kill() called!" | |||
#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)" | |||
#define MSG_BUSY_SIGNAL "Busy: Processing" | |||
#define MSG_WAITING_FOR_USER "Busy: Paused for user" | |||
#define MSG_WAITING_FOR_INPUT "Busy: Paused for input" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Blue-Marlin something more like this?
0bb6fd8
to
6b6dfb6
Compare
@@ -646,6 +646,8 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l | |||
#define EEPROM_CHITCHAT // Please keep turned on if you can. | |||
#endif | |||
|
|||
//#define HOST_KEEPALIVE_FEATURE // Send messages to the host when busy with long operations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand this changes behavior but I believe it shall be active by default, this is one of those "black magic" flags no one will understand the what it exactly does and the Octoprint guys will continue to see issues coming their way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Until there is at least one host supporting this, it makes no sense to activate it by default.
And then we have to find out, if this confuses any other hosts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specified behavior for hosts is that if they can't interpret a message they should print it to console and ignore it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OctoPrint automatically supports this since OctoPrint interprets any output from the printer as "oh, look, it's still alive!" (and has been doing so for quite some time now). So another 👍 for having it enabled by default, it will instantly solve a lot of issues OctoPrint users are currently experiencing with long running commands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well.
In that case let's go for it.
But we need at least a week for tests after merging to RCBugFix, before we can tag RC4.
The nozzle-tune disaster still hurts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Wackerbarth would be around, he'd complain about: "Don't enable anything by default."
How about: //#define DISABLE_HOST_KEEPALIVE_FEATURE ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems sane.
But I would suggest a bit shorter: DISABLE_HOST_KEEPALIVE
Sorry I haven't commented on this more – I thought it would be a while before we had consensus to go forward. I will update this with your suggestions and merge it for the community to digest. I realized this feature will also be important to deal with any (rare, but technically possible) time-consuming immediate commands that could be issued through |
7a80bf9
to
abe95dc
Compare
Would not be calling |
It may be. I moved the code that is now in |
Should I define |
8d89093
to
8670fa5
Compare
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.
8670fa5
to
963a92c
Compare
I kind of want to use the name |
For the written log it will most probably not work as it is written when we receive it. For the viewing side on runtime it should be quite simple to switch to repetition count instead. That is a good idea. Regarding repetition time I vote for 2s as default and and an option to make it worse if user does not believe it is good, also he is wrong. There should also be a method to get the timeout so hosts can ask for correct value. |
Setting the host timeout to 2s tends to produce a lot of "busy" output in everyday circumstances. Anyway, I'm curious. Currently it is quite easy to block the serial input queue for a very long time. For example, just issue a few G28
G1 Z10 F9000
G1 X10 Y10 F5000
G2 I90 J0 F1000
G3 I90 J0 F1000
G2 I90 J0 F1000
G3 I90 J0 F1000
G2 I90 J0 F1000
G3 I90 J0 F1000 |
Thanks for all the good feedback. I've been focused on other sections but will deal with this today. As I patch it up, I will set 2s as the default timeout, but make it configurable through GCode, and I suppose it will be saved to the EEPROM also. |
#3414 applies the necessary changes to give a configurable interval with a 2s default. The code |
The circles are a good example for what I explained earlier. This must also send busy signal when it is blocking input too long, otherwise it makes no sense. Our hosts will not assume printer is gone, but would maybe timeout and then send next command. When printer is ready again it will then encounter checksum error (buffer overflow so new data is partially ignored) and request a resend. So that is a problem but normally gets solved by other error checking routines. |
So the host knows it just sent to the robot a blocking instruction to draw a circle or do a long slow move or whatever.. but he needs confirmation from the fw that indeed the robot is "busy" executing what has been told.. every 2s. Is it just me that finds this inelegant "brute force" ? |
G0/G1/G2/G3 are not registered as long running and the host does not know when they cause a block. They might be buffered and return "ok" directly and 10 commands later a simple short G0 takes 40 seconds because the move buffer is full and the slow g-move is now executing. It is not up to the host to know why and when firmware is blocking. Firmware has just to say that it is in blocking mode. |
Blocking? |
Basically, we can think of any lengthy command as potentially blocking the serial input. After all, the default serial command buffer only requires 4 "unfinished" commands to become filled up and blocked. The movement commands are not immediately blocking in the way that something like Under typical usage conditions and typical GCode files, with a 2 second interval we see "busy" messages constantly. The reason I leapt to 10 seconds was due to the sudden influx of complaints. But at that time there was no option to turn it on and off nor change the interval. Now that there's an |
|
I haven't looked into your implementation but I would not expect busy on normal gcode. From time to time yes, but most moves are shorter than 2s so waiting time is less then 2s and every ok should reset busy timer. So if you check every 0.1s if a busy needs to be send it is ok to send it when blocking exceeds 2s. Hosts will add a safety margin to your value anyway I think (maybe 1s or 0.5s) to compensate round trip times and inaccuracies. |
@jbrazio We shouldn't set too conservative a value, apparently. When I did my 10 second "suggestion" merge I received flak, ridicule, and insult for my efforts. So, as long as we're going for "middle ground" changes I think the best option is to set the default to about 5 seconds. I agree it still makes sense to leave it on by default, because it will still keep hosts thinking Marlin is alive, even those that don't yet have any support for |
Well, here it is in all its glory. Very simple! The void host_keepalive() {
millis_t ms = millis();
if (busy_state != NOT_BUSY) {
if (ms < next_busy_signal_ms) return;
switch (busy_state) {
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;
default:
break;
}
}
next_busy_signal_ms = host_keepalive_interval ? ms + 1000UL * host_keepalive_interval : -1;
} (The |
@thinkyhead Good concept with one little flaw. It will break after 49 days when the timer overflows. To prevent this make next_busy_signal_ms last_busy_signal_ms = ms; at the end and for the timer detection write ms - last_busy_signal_ms > 1000UL * host_keepalive_interval |
@repetier Based on your suggestion, it sounds like we need to change every instance where Marlin uses a Anyway, the only reason we use So… #3443 should do the trick! |
You can come away with less code change if you use next time assuming next time < 20days with I have a busy implementation in repetier-firmware now and am testing it with the next repetier-server release. Last print had only some busy at the beginning from heating/homing. The rest of the print had no busy message so that is good. If you have log open with a host without busy support you see of course the messages. For server I have already added busy messages as ACK so they get filtered. I think it is only a question of time until all hosts will filter it as ACK to not flood the user. It is just the problem of a new feature to get a well known standard. |
Ok, after some struggling I got your code also to work with next server release. Main problem is that you forgot
in the M code selection switch or it was removed meanwhile. Now it is printing with 3s timeout auto configured from M113 and no timeout during heating or slow moves. I did not test the other commands but the principle is proven to work. Repetier-Server 0.75.0 will handle it and Repetier-Host 1.6.2 should also include the correct handling. And with Marlin and Repetier-Firmware using it I think other hosts will soon follow as well. |
@repetier Aha, did I forget something there? Well I'm glad to hear it's all holding together. Are there any other fine points to go over here? If not, I suppose we can "close" this very productive thread! |
I haven't and can't test any slow command but the cases tested and common worked fine. So I guess we can close it. |
OK, @thinkyhead, nice feature... If I understand correctly, wait is when Marlin wants more data so it says "I wait for some to execute" , while when working a command such as M48 that could take too long a time, Marlin says "I am busy, hang-on you will get an OK pretty soon..." Does that mean that we can enable both??? |
@lrpirlet The
|
You should enable both. |
I wish we were solving this problem without using a shovel and pickaxe. |
This PR offers one approach to keep hosts alive, as discussed in #3068
Some things about the Marlin command processor:
while (!lcd_clicked()) idle();
, for example. In fact, anything that blocks for any period of time is already callingidle()
.Bad news for hosts:
G29
orM303
is blocking, host software will simply find Marlin unresponsive.In this solution, whenever Marlin is inside of a command processor, the
idle()
function will keep an additional timer. Every time the timer reaches 2 seconds, a message will be sent to inform the host that Marlin is still alive (but busy, waiting for user input, etc.).Any command handler that calls
idle()
directly or indirectly will invoke the keepalive message if it blocks for more than 2 seconds. So that includes:G4
dwell,G29
auto probing,M0
wait for user,M109
andM190
waiting,M226
wait for pin, anything that callsst_synchronize
to wait for moves to finish (M400
orM48
for example), and anything that callsplan_buffer_line
with a full buffer.