Skip to content

Add auto-dismiss-load-dialog service patch#93

Open
bjan wants to merge 2 commits into
OpenCentauri:mainfrom
bjan:auto-dismiss-load-dialog
Open

Add auto-dismiss-load-dialog service patch#93
bjan wants to merge 2 commits into
OpenCentauri:mainfrom
bjan:auto-dismiss-load-dialog

Conversation

@bjan
Copy link
Copy Markdown

@bjan bjan commented May 7, 2026

Add auto-dismiss-load-dialog service patch

What this does

Auto-dismisses the "Load filament complete" modal that appears on the
touchscreen at the end of a filament-load cycle. With this patch
installed, you can kick off a load and not have to walk back to the printer to tap OK
before queueing the next print.

The unload-complete dialog isn't blocking in the same way; only loads
need this.

How

Service patch under oc-patches/services/auto-dismiss-load-dialog/.

  • synth-tap — bash + xxd helper that writes the recorded input_event sequence (BTN_TOUCH down → ABS_MT_POSITION_X/Y/MAJOR/WIDTH/TRACKING_ID → SYN_MT_REPORT → SYN_REPORT → 150 ms wait → BTN_TOUCH up → SYN_REPORT) to /dev/input/event1
  • auto-dismiss-daemontail -F /board-resource/log1, three-state machine on feed state change : 0 -> 1 / single_command<M729> / feed state change : 1 -> 0, fires synth-tap when the cycle completes and was a load (M729 is the discriminator)
  • S99auto-dismiss — entware service wrapper that detaches via subshell + the daemon's own trap '' HUP (busybox here has neither nohup nor setsid)

patch.sh stages the three files into ${SQUASHFS_ROOT}/app/auto-dismiss-load-dialog/ and adds a hook block to /etc/rc.local that copies them into /opt and starts the service after bootstrap_oc has finished setting up entware.

Detection-signal derivation

Both load and unload end with feed state change : 1 -> 0, so we can't dismiss based solely on that signal — it'd produce phantom taps after an unload (where the dialog isn't up). Diffing the two gcode sequences from a real cycle:

Cycle Heater target Extrude Distinctive command
Unload 140 °C G1 E-60 F240 (negative) SET_MIN_EXTRUDE_TEMP S0/RESET
Load 230 °C G1 E120 F240 (positive) M729

M729 is single-token, atomic, and load-only — much simpler than parsing signed E values or filament-specific heater targets. The daemon flips its is_load flag when it sees M729 between the start (feed state change : 0 -> 1) and end (feed state change : 1 -> 0) of a cycle, and only taps if the flag is set.

Tap coordinates

(289, 182) in the gt9xxnew_ts coordinate space. Captured from a real user tap on V0.3.0-o by reading /dev/input/event1. Held about 13 frames at the same coordinate, then BTN_TOUCH=0 + SYN_REPORT — the synth-tap script replays exactly this shape.

Tested on

V0.3.0-o (OpenCentauri based on stock 1.1.40), Centauri Carbon CC1.

Footprint

~6 KB on disk. One bash process tailing a log; idle CPU is negligible. Only writes to /dev/input/event1 when the load-complete signal is observed.

Caveats / things to consider

  • Tap coordinates are firmware-version-dependent. If a future OC release rearranges the dialog, (289, 182) will hit the wrong thing. Ideally the tap coords (and the M729 discriminator) live in env vars exposed at the top of the init script so users can override.
  • /dev/input/event1 ordinal. The Goodix touchscreen is event1 here; if a future kernel re-enumerates inputs it could shift. The daemon does not currently autodetect by name (e.g., walking /sys/class/input/event*/device/name for gt9xxnew_ts). Easy to add if the maintainers want it.
  • Log-file path. /board-resource/log1 is currently a symlink (/board-resource/log -> /board-resource/log1); if log rotation changes this, the daemon's tail -F should still follow correctly, but worth noting.
  • Origin. Built and verified outside the OC build flow — daemon and helper were live-deployed to a printer for testing. Patch shape matches the bootstrap-oc service example.

I can iterate on any of the above; this is a starting point. Happy to file a separate issue if the team would rather discuss the design first.

Auto-dismisses the 'Load filament complete' modal that appears on the
touchscreen at the end of a filament-load cycle, so remote print
queueing isn't blocked by a local OK-tap.

Detection:
  - tail /board-resource/log1
  - 'feed state change : 0 -> 1' starts a cycle
  - 'single_command<M729>' identifies it as a load (load-only gcode)
  - 'feed state change : 1 -> 0' ends the cycle; if it was a load,
    synthesize a tap.

Action:
  - Replay the recorded gt9xxnew_ts tap sequence on /dev/input/event1
    at (289, 182) — the OK button on the load-complete dialog.

Files installed via patch.sh into /app/auto-dismiss-load-dialog/ at
firmware-build time, then copied into /opt and started by an
rc.local hook (idempotent, hooked after the bootstrap_oc block).

Tested live on V0.3.0-o, Centauri Carbon CC1.
@bjan
Copy link
Copy Markdown
Author

bjan commented May 8, 2026

Heads-up before this gets reviewed in earnest: a real-world test on my own printer just turned up a problem. The user did a filament load, walked away, and came back to find the load-complete dialog still on the screen — the daemon hadn't dismissed it.

What we do know from logs after the fact:

  • Detection worked. /board-resource/log1 recorded the expected sequence (change_filament busy : 1single_command<G1 E120 F240>single_command<M729>change_filament busy : 0feed state change : 1 -> 0).
  • The daemon saw it. logread includes auto-dismiss: load complete detected; tapping (289,182) after 0.7s for that cycle.
  • But the dialog wasn't dismissed. So synth-tap either silently failed, ran but produced no usable input event, or landed somewhere that doesn't activate the OK button.

Things I want to investigate before this is mergeable:

  1. Whether the bash + xxd synth-tap actually produces correct input_event bytes when run from a daemon context (different $PATH, different shell options) vs from an interactive shell.
  2. Whether multiple daemon instances were racing — logread shows 4 simultaneous starting entries from before, suggesting my install left orphans the pidof-based stop didn't catch.
  3. Whether the post-detection sleep 0.7 is enough for the dialog to be tappable — could be a race where the tap lands before the touch handler is wired up.
  4. Whether the OK-button hitbox is actually at (289, 182) (my evdev capture had it there to within ~5 px on two separate user taps, but maybe the synthetic event needs a different position to land in the hitbox).

Holding off on iterating in this branch until I've narrowed it down. Happy to push a fix to bjan:auto-dismiss-load-dialog once we have one, or close and refile later if the design needs to change. Either way, please don't merge as-is.

Field-test on V0.3.0-o turned up that 'feed state change : 1 -> 0'
fires AFTER the dialog dismisses — it's downstream of the tap, so
useless as a trigger (chicken-and-egg).

The dialog actually appears at the moment the load gcode completes,
which corresponds to 'single_command<M82>' in the log. Both load
and unload emit M82 at the end of their gcode, but only loads
precede it with 'single_command<M729>', so the existing is_load
flag keeps the unload cycle untapped. No discriminator change
needed; only the trigger.

Live re-tested end-to-end: dialog auto-dismissed without a manual
tap. Updates PR description and README to document the corrected
detection model. Also adds a comment in S99auto-dismiss explaining
why stop() uses pidof + SIGKILL fallback rather than just PIDFILE
(defensive against tail-F'ing daemons in disk wait at SIGTERM
time).
@bjan
Copy link
Copy Markdown
Author

bjan commented May 8, 2026

Update — fixed the issue I flagged earlier.

Root cause: feed state change : 1 -> 0 was the wrong trigger. Live capture (touchscreen evdev + log + daemon syslog, time-correlated) showed it fires after the user (or our synth-tap) dismisses the dialog — about 159 s of post-gcode silence followed by a feed state change : 1 -> 0 immediately after the OK tap. So the daemon was waiting for a signal that required its own action to fire. Chicken-and-egg.

The dialog actually appears at single_command<M82> — the absolute-extrude gcode that fires immediately after the load extrude completes. Both load and unload emit M82, but only loads precede it with M729, so the existing is_load discriminator does the right thing without changes. Only the trigger Cmd needed to change.

Re-test, end-to-end: initiated a load from the touchscreen, walked away, came back to find the dialog already dismissed. Daemon's syslog logged auto-dismiss: load M82 (gcode complete); tapping (289,182) after 0.7s at the right moment, and a single synthetic tap appeared on /dev/input/event1 at the recorded coordinates ~700 ms after M82 hit the log. No phantom taps in the post-dismiss screen.

Pushed as a separate commit on bjan:auto-dismiss-load-dialog so the diff is reviewable. Also updated the PR description above and the in-tree README.md to reflect the corrected detection model. Thanks for being patient with this; ready for review now.

While I was in there I also added a comment in S99auto-dismiss explaining why stop() uses pidof + SIGKILL fallback rather than just PIDFILE. Saw a transient orphan-daemon situation during one of my mid-session redeploys (almost certainly a tail-F'ing daemon caught in disk-wait at the moment SIGTERM arrived, surviving long enough for a parallel start to spawn a second instance). The defensive stop catches that case cleanly. No pkill in this busybox so we use pidof.

@suchmememanyskill
Copy link
Copy Markdown
Contributor

suchmememanyskill commented May 8, 2026

Not gonna lie, this feels like the wrong solution to fix this issus. Wouldn't it be better if you can start prints while on that screen by patching out checks?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants