Macros: fix wrong-file race, suppress HOOK message popups, preprocess at load
Three fixes for macro/W-axis interaction:
1. run_macro raced the file selection. The frontend mutated
state.selected client-side and immediately fired api.put('start').
Selection on the server is a side effect of GET /api/file/<name>
(FileHandler.get calls state.select_file). The GET request was
often still in flight when start ran, so mach.start() executed
whichever file was selected last - pressing W Down would re-run
W Up. Now run_macro awaits the file fetch before starting.
2. (MSG,HOOK:aux:N) lines, used as the IPC channel between the
W-axis preprocessor and the Hooks system, were leaking to the
user as message popups (because the planner forwards every
(MSG,...) comment to state.messages). Filter HOOK: messages in
Planner._add_message: still pushed through state.messages so
Hooks._on_state_change can dispatch them, but immediately
acked so the UI doesn't render them.
3. AuxPreprocessor only ran at upload time (FileHandler.put_ok and
Mach.mdi). Files written via scp, restored from a config backup,
or hand-edited still contained raw W tokens that the planner
couldn't parse. Run preprocess_file in Planner.load() too. It's
idempotent (no-op when no W tokens remain) so re-loading a
already-rewritten file is free.
This commit is contained in:
@@ -564,23 +564,32 @@ module.exports = {
|
||||
override_feed: function () { api.put(`override/feed/${this.feed_override}`); },
|
||||
override_speed: function () { api.put(`override/speed/${this.speed_override}`); },
|
||||
|
||||
run_macro: function (id) {
|
||||
run_macro: async function (id) {
|
||||
if (this.state.macros[id].file_name == "default") {
|
||||
this.showNoGcodeMessage = true;
|
||||
} else {
|
||||
if (this.state.macros[id].file_name != this.state.selected) {
|
||||
this.state.selected = this.state.macros[id].file_name;
|
||||
return;
|
||||
}
|
||||
const file_name = this.state.macros[id].file_name;
|
||||
try {
|
||||
// Selecting a file on the server is a side effect of
|
||||
// GET /api/file/<name>. The macro button used to mutate
|
||||
// state.selected client-side and immediately call start, which
|
||||
// raced the file fetch: if the server hadn't seen the new
|
||||
// selection yet, mach.start() ran whichever file was selected
|
||||
// last. Do it explicitly and await so start always sees the
|
||||
// right file.
|
||||
if (file_name != this.state.selected) {
|
||||
this.state.selected = file_name;
|
||||
await api.get(`file/${encodeURIComponent(file_name)}`);
|
||||
}
|
||||
this.load();
|
||||
if (this.state.macros[id].alert == true) {
|
||||
this.macrosLoading = true;
|
||||
} else {
|
||||
setImmediate(() => this.start_pause());
|
||||
await this.start_pause();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Error running program: ", error);
|
||||
}
|
||||
console.warn("Error running macro: ", error);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -196,12 +196,29 @@ class Planner():
|
||||
|
||||
|
||||
def _add_message(self, text):
|
||||
self.ctrl.state.add_message(text)
|
||||
|
||||
# HOOK:<event>:<data> messages are an internal IPC channel
|
||||
# between the gcode preprocessor and Hooks; they should not
|
||||
# surface as user-visible message popups. Hooks._on_state_change
|
||||
# will still see them via the messages list before we filter.
|
||||
line = self.ctrl.state.get('line', 0)
|
||||
if 0 <= line: where = '%s:%d' % (self.where, line)
|
||||
else: where = self.where
|
||||
|
||||
if isinstance(text, str) and text.startswith('HOOK:'):
|
||||
# Push it through state.messages so Hooks._on_state_change
|
||||
# can see and dispatch it, then immediately ack it so the UI
|
||||
# doesn't render a popup.
|
||||
self.ctrl.state.add_message(text)
|
||||
try:
|
||||
msgs = self.ctrl.state.get('messages', []) or []
|
||||
if msgs:
|
||||
self.ctrl.state.ack_message(msgs[-1].get('id', -1))
|
||||
except Exception:
|
||||
pass
|
||||
self.log.info('HOOK msg: %s' % text, where = where)
|
||||
return
|
||||
|
||||
self.ctrl.state.add_message(text)
|
||||
self.log.message(text, where = where)
|
||||
|
||||
|
||||
@@ -369,6 +386,17 @@ class Planner():
|
||||
self.where = path
|
||||
path = self.ctrl.get_path('upload', path)
|
||||
self.log.info('GCode:' + path)
|
||||
# Make sure W-axis tokens are rewritten before the planner sees
|
||||
# the file. preprocess_file is a no-op for files without W and
|
||||
# for files already rewritten (no W tokens remain after the
|
||||
# first pass), so this is safe to run on every load.
|
||||
try:
|
||||
from bbctrl.AuxPreprocessor import preprocess_file
|
||||
if preprocess_file(path, log = self.log):
|
||||
self.log.info('Rewrote W-axis tokens in %s' % path)
|
||||
except Exception:
|
||||
self.log.exception('W-axis preprocess at load failed; '
|
||||
'attempting to load file unchanged')
|
||||
self._sync_position()
|
||||
self.planner.load(path, self.get_config(False, True))
|
||||
self.reset_times()
|
||||
|
||||
Reference in New Issue
Block a user