🐛 fix spurious notifications
Summary
Grbl may change its system state multiple times between the CYCLE state (running/motion) and the IDLE state during one motion command due to a temporary lack of "checked-out" steps to be generated in the segment buffer. This is because the grbl's stepper (consumer) and the grbl's main program (producer) run on different threads and the stepper may consume data from the segment buffer faster than the grbl's main programme is able to produce and push in it. This behaviour is more evident when the CPU control assigned to grbl-gpiod's process gets reduced.
Explanation
Launching a motion command the grbl's state machine (SM) transits from the IDLE state to the CYCLE state thanks to the protocol_auto_cycle_start by setting the real-time flag EXEC_CYCLE_START
, which is frequently called by the main programme (MP) in various places (like in the main loop).
The Stepper (ST) and the MP run in 2 separate threads and the first acts as "consumer" of (checked-out) steps and the second as "producer" of those steps. They interface with each other via the segment buffer (SBUF) which is filled from time to time using the st_prep_buffer procedure.
That said, it may happen that the ST manages to empty the SBUF before it is refilled by the MP while the motion is not completed. This causes the ST to set the real-time flag EXEC_CYCLE_COMPLETE
(here) and, as a result, grbl's SM switches to IDLE state:
update state -> cycle complete processing -> set IDLE state -> notification
The latter state (IDLE) is extremely short-lived since the planner has others "checked-out" steps to be generated. So, when the MP calls the protocol_auto_cycle_start in the main grbl loop, it re-sets the flag EXEC_CYCLE_START
and SM transits to the CYCLE state again (here).
Also, it seems that these spurious events (-> notifications) occur especially when the schedule for the grbl process (with all its threads) is rather tight, for example, limiting the CPU quota and period for a container through the –cpus=0.05
option in podman (doc).
Solution
A way to solve this issue would be to check whether the motion has actually ended when the SBUF is empty, preventing an unwanted change of the system state if it is not the case. In addition to that, the SBUF can be refilled with st_prep_buffer
.