Split the planner sync code out of planner_abort_hard() so that we can
independently resync the planner position from the counters.
This is needed in xyzcal as we directly modify the stepper counters
(bypassing both planner and stepper).
Call this new function instead of planner_abort_hard() when leaving, so
that motion can resume in the middle of the gcode_M45 instruction.
We already disable the heaters upon entering, and the new temperature
isr doesn't perform any direct movement until we return to the main
loop.
This allows us to remove direct control of the soft_pwm interrupt from
the header, which is dangerous.
printer_smodel_check was incorrectly substituting the final " with a
null in the command to simplify the model string comparison, but in
doing so was also corrupting the next pop from the cmdqueue.
We can modify the current strchr_pointer as long as we *don't* change
it's length. This can cause an incorrect extra read from the queue,
resulting in the last command to be completely ignored.
cmdqueue will run commands when EOF is reached without returning to the
main loop, which is already incorrect.
However, since it needs to ensure the queue is empty, an st_synchronize
call can result in a re-entrant call to get_command, which will
reprocess EOF again. Even if we removed st_synchronize, another command
could be picked by an unsuspecting manage_inactivity() somewhere else.
Short-circuit EOF processing by closing the file early and checking for
the file state early in get_command.
This should fix#3549
Call this variable menu_block_mask instead. We don't need to know the
exact reason of why we're locking the menu.
We will be able to reuse this to prevent menu entry during more
activities in a cleaner way than testing for each condition as it's
currently done for both menu entry and longpress.
This allows us to use "M310 B0 W0.01" as a way to report the current
error continuosly on the serial without 1) more code and 2) without
preventing regular usage.
Use OCTOPRINT_ASK_* for the present form of actions. In these cases the
host will perform the pausing manouvers for us.
Use OCTOPRINT_* instead for the past tense forms when we are in charge.
Also always emit the action, whether we are or not sd-printing. This is
due to the new Stopped handling behaving correctly in either case.
If the user accepted to resume, do not wait for bed temperature when
recovering. This only adds a pointless delay when recovering a short
pause and doesn't really improve the recovery quality after a long
pause.
Do not allow resuming until all thermal and fan errors are clear.
Call the appropriate resume function when resuming a printing depending
on the saved_print state (is saved_print is available, then we always
need to resume from the saved state even when printing via usb).
Clear the Stopped state when resuming, so that commands can be accepted
again.
Ensure we never fall into the boundary values provided by the min/max
limits.
Save/restore the initial guess value, so that a convergence failure
restores the initial model state.
Force processing of the pause and stop "parking" commands _after_ the
main loop completes.
This was/is currently done in lcd_commands, which is a poor place to
continue processing, since it can be called already within an aborted
command. This requires checking for planner_aborted before any action
can be performed.
After calling planner_abort_hard() no motion command can be
scheduled until we return to the main loop since the call can
potentially be scheduled inside a nested process_command call.
Despite previous fixes, bugs keep creeping in due to nested calls not
being obvious to detect at all.
Stop allowing motion _completely_ for the entire processing loop by
default. That is, instead of aborting the current plan_buffer_line call,
abort the entire command until we can actually schedule motion safely
again.
This benefits handling of pretty much all g/m-codes, since this flag
(now "planner_aborted" for clarity) becomes a general "command aborted"
call.
This also now ensures that the flag prevents _any_ new block (including
blocks partially planned while servicing an interrupt) are scheduled
after planner_abort_hard is called.
There are only two exceptions where it's safe to resume in this context:
- Within uvlo_, where we never return to the main processing loop
- When we're intentionally scheduling a new process_command loop for a
MK3 filament recheck (which is *bad*)
Handle those two cases as exceptions.
Do not inhibit motion when Stopped is set.
We actually do need to move to move away the extruder from the bed, and
setting Stopped breaks it without adding any sort of security (M*
commands, such as M600 could still perform moves and still pass
through, while M104 would still set heaters).
During a hard error the internal queue is cleared (and sd file closed,
if any), so no new "unforeseen" command can be read.
Handle "Stopped" instead as a flag to inhibit serial processing and
automatically switch to "paused for user" state. While in this state
simply drop any input without incrementing the processed gcode line
number, behaving as-if the last command was still being processed.
This allows "Stopped" to correctly handle a printer-initiated paused
state and recover as expected by requesting a resend when resuming.
Add a new LCD_MESSAGE_INFO priority which can be overridden by regular
status updates, but only if a certain amount of time has passed.
Assign a time stamp to all message updates, so that the time since the
last update can be determined. Also switch the message type to Status,
so that the message always becomes visibile.
Always show status or info messages when printing via SD if the message
is recent enough.
Remove useless repeated calls to disable heaters and turn on the fans,
since this is done at a higher level.
Avoid repeating messages on the serial. Do it just once.
Make a critical alert sound unconditionally.
Break out of the autotuning if a thermal error condition is detected and
attempt to restore a safe initial state irregardless of the error
handlers.
Also error out if the estimation fails to converge.
Calibrate C/R values via univariate minimization using golden section.
This is done in several passes:
- Bootstrap C by setting an initial high R value
- Calibrate R at the requested working temperature
- Cooldown
- Refine C to the final value
- Estimate R losses for a subset of fan speeds
- Interpolate remaining values to speed-up the process
This results in robust values which are tailored to the current
filtering constants, and avoid having to sample for an extended
time to reach the required resolution.
The refining pass could avoid cooldown if the recording buffer was at
least twice as large, so that we could record both the heating and the
steady-state, saving _considerable_ time.
This currently bypasses the ConfigurationStore, which doesn't fit the
malin model nicely.
temp_model is using it's own private copy directly.
But maybe we should change this in the future.
- Allow all parameters to be changed at runtime through M310
- Move the model prototypes into a separate temp_model.h header
- Allow the checked to be enabled/disabled at runtime
- Introduce a warning threshold
When triggering a thermal error, allow higher-priority errors to
override the initial error source.
This allows a fatal error such as maxtemp to trigger to a full stop even
if thermal runaway has already been triggered.
Reorder error types according to their priority.
Do not overwrite the error source if the error flag is already set.
As checks are performed in priority order, this ensures min/maxtemp
user-level handlers are triggered even if the thermal model can detect
an issue in the same cycle.
This restores MAXTEMP handling, which was simply shadowed.
Setting pid_tuning_finished can result in the heaters stuck to full
power. As a result, we need to ensure that when PID management is
disabled, heaters are also.
Use pid_tuning_finished as a flag to prevent automatic PID management.
As a result, set the default start-up state to true and adjust the
dependent code accordingly.
- Flag the error condition from the temp_mgr_isr
- Handle the error state from the user code
Currently only handles min/maxtemp and relays the error to the original
handler (which is a poor fit for the current design).
Split off setIsrTargetTemperatures and temp_mgr_pid() so that we can
propagate the target temperatures instantaneously down the pid/pwm chain
during emergencies.
This reduces the amount of code in disable_heater() itself, making it
a bit more maintenable.
The bed still isn't disabled on-the-spot yet, due to the heatbed_pwm
automaton. To be improved later.
*_temperature_raw: buffer for the ADC ISR (read by temp ISR)
*_temperature_isr: latest temperatures for PID regulation (copied from
_raw values)
*_temperature: latest temperature for user code
The flow:
- ADC ISR (async)
- perform oversampling
- call ADC callback: copy to _raw (async)
- temp ISR (timer)
- convert to C (_isr values)
- user code (async)
- check temp_meas_ready
- call updateTemperature()
- copy from _isr to current
- syncronize target temperatures
This removes PINDA value averaging (if needed, should be re-implemented
by averaging in user code where needed)
Use a new low-priority "temp_mgr_isr" running at constant rate for
temperature management.
This is done so that the temperatures are sampled at a constant
independent interval *and* with reduced jitter. Likewise for actual
PID management.
This will require further adjustment for the min/max/runaway display,
which cannot be done directly into this function anymore (the code will
need to disable heaters but flag for display to be handled in
manage_heaters).
Read from ADC as fast as possible using the ADC interrupt to get
more accurate instantaneous readings.
Decouple the temperature_isr from the adc reading interval, so that
the two can run independently for future use.
Setting pullups on the ADC should trigger the model-based check, making
this redundant and wasteful.
Keep the DEBUG_PULLUP_CRASH menu so that we can verify this behavior in
the future.
Fallback to use the default HIGH value if a frequency has not been
specified.
This makes the tone of "M300" and "M300 P<x>" identical as a result.
Supersedes #3339
Now that the position is a uint16_t instead of uint32_t, it is simpler to just sort the positions in place without using the uint8_t indices. Also, this approach is considerably lighter on the stack usage and it also removes a delay after the sorting happens