AuxPreprocessor: precede each HOOK with M0 so atoms block
The ATC M-codes are supposed to behave like proper blocking gcode - M100 should not return until the ejector pulse has actually finished, and the next block should not run until M100 has returned. Without that, the drop macro M102 (release) M100 (eject pulse 1) M100 (eject pulse 2) M100 (eject pulse 3) M100 (eject pulse 4) G53 G0 Z0 (lift Z) M103 (clamp) races: gplan emits all the (MSG,HOOK:...) lines and the Z move in quick succession, the AVR queues them, and Z lifts while V2 is still wiggling. The (MSG,...) transport itself is fire-and-forget by gplan's design. The Hooks framework already implements proper blocking via the block_unpause / auto_resume mechanism - but it only takes effect when the program is actually paused. So precede each hook with M0 (program pause) in the rewritten temp file: M0 (MSG,HOOK:release:) M0 (MSG,HOOK:eject:) ... Sequence becomes: M0 -> machine pauses on the AVR side (MSG..) -> hook fires synchronously in a thread hook does ESP RPC, blocks until [eject] done hook completes; auto_resume unpauses next block streams This also fixes the consecutive-comment-line collapse problem naturally: each M0 is its own block, so back-to-back HOOK lines no longer collide. The M0 lives only in the tempfile gplan loads; the operator's macro source still reads as plain M100/M102/M103.
This commit is contained in:
@@ -394,22 +394,42 @@ class AuxPreprocessor(object):
|
||||
except ValueError: continue
|
||||
event = _ATC_M_CODES.get(num)
|
||||
if event:
|
||||
# gplan only delivers `(MSG,...)` to the
|
||||
# message stream when it's attached to an
|
||||
# executable block (so the host can release
|
||||
# it on the matching cmd-id ack). A bare
|
||||
# comment-only line gets collapsed and the
|
||||
# message is silently dropped, which means
|
||||
# back-to-back hook lines (like 4 ejects in
|
||||
# a row) only deliver the last one.
|
||||
# We need two things here that aren't
|
||||
# naturally provided by the (MSG,...)
|
||||
# transport:
|
||||
#
|
||||
# Pair each HOOK line with an essentially-
|
||||
# zero dwell so it gets a planner block id
|
||||
# of its own. G4 P0.001 = 1us dwell which
|
||||
# is below any timer resolution and has no
|
||||
# observable effect on the machine.
|
||||
fout.write('G4 P0.001 (MSG,HOOK:%s:)\n'
|
||||
% event)
|
||||
# (1) Synchronization. (MSG,HOOK:...) is
|
||||
# fire-and-forget from gplan's view -
|
||||
# gplan emits the message and keeps
|
||||
# streaming subsequent blocks (Z
|
||||
# moves, the next eject, etc.) to the
|
||||
# AVR. Meanwhile the hook handler
|
||||
# runs the actual ESP RPC in a
|
||||
# thread, and Z lifts while V2 is
|
||||
# still wiggling. To make M-codes
|
||||
# behave like proper blocking gcode,
|
||||
# we precede each HOOK with M0
|
||||
# (program pause). The Hooks layer
|
||||
# registers the atom as block_unpause
|
||||
# + auto_resume, so:
|
||||
# M0 -> machine pauses
|
||||
# (MSG,HOOK:event:) fires hook
|
||||
# hook thread runs ESP RPC
|
||||
# hook completes, auto-unpauses
|
||||
# next block streams
|
||||
# End result: M100/M102/M103 block
|
||||
# until the ESP says done, just like
|
||||
# a G-code dwell.
|
||||
#
|
||||
# (2) Block separation. gplan collapses
|
||||
# consecutive comment-only lines
|
||||
# into a single block, so back-to-
|
||||
# back HOOK lines used to drop all
|
||||
# but the last. M0 is its own block
|
||||
# so this falls out automatically -
|
||||
# the (MSG,...) attaches cleanly to
|
||||
# each M0.
|
||||
fout.write('M0 (MSG,HOOK:%s:)\n' % event)
|
||||
code_stripped = _ATC_M_RE.sub('', code).strip()
|
||||
if code_stripped:
|
||||
# Mixed line: keep the residual executable
|
||||
|
||||
Reference in New Issue
Block a user