Front-end side of the gplan-integrated A axis (B3).
- a-axis-view.{js,pug}: dedicated settings page that mounts the
AAxisSettings Svelte component and lives at #a-axis in the V09
settings rail.
- AAxisSettings.svelte: aux.json-backed form (axis letter, port,
homing direction, soft limits, ATC pin map, etc.) with master
Save integration via 'onefin:save-all'.
- main.ts + SettingsView.svelte: register AAxisSettings in the
Svelte component map; SettingsView no longer embeds the W axis
fieldset.
- settings-shell-view: 'A Axis' rail entry; route to a-axis-view.
- app.js: extend settings family to include 'a-axis'; broadcast
onefin:save-all from the master Save button.
- control-view: Home All button waits for the gantry cycle to
finish before firing Home A on a non-virtual setup; A jog
buttons; aux_jog/aux_home/aux_jog_incr methods.
- control-view.pug: A row in the DRO (with set-position + zero +
home actions), A- / A+ tiles in the jog grid (gated on
w.enabled || a.enabled), legacy W row kept for installs that
haven't migrated to the gplan integration.
- style.styl: dro-axis.axis-w color.
ATC pneumatics in g-code (drop tool / grab tool / release clamp /
engage clamp) are expressed as M100..M103. AuxPreprocessor rewrites
those into (MSG,HOOK:droptool:) etc on file upload + on planner
load + on MDI input, so the Hooks layer (B1) can dispatch them via
registered ATC handlers in Ctrl.
- AuxPreprocessor.py: regex-based file rewriter, idempotent.
- FileHandler: invoke preprocessor on every upload.
- Planner.init: also re-preprocess on load (catches files written
before this version).
- Mach.mdi: same rewrite for ad-hoc MDI input so M101 typed at the
console produces a HOOK message.
- Ctrl: register the four ATC hooks (droptool/grabtool/release/clamp)
with block_unpause + auto_resume so programs using them pause at
the right point and resume cleanly. aux_home retained as a legacy
alias for older preprocessed files.
ExternalAxis exposes the auxcnc-driven ESP stepper as motor 4 (a
synthetic, host-only motor that gplan sees but the AVR doesn't). The
result is a virtual A axis that is fully integrated with the planner:
G1 A25 F1500 schedules a coordinated S-curve and the ESP runs the
exact same 7-segment trajectory the AVR would have run if A were a
real motor.
- ExternalAxis.py: synthetic-motor state, S-curve LINE block forward
to the ESP, soft-limit enforcement, option-(b) homing (user A=0
at the home limit).
- State: walk motors 0..4 in find_motor; clear both homed and h on
reset; expose synthetic motor vars.
- axis-vars.js: motor-4 guard so the JS computed axis bindings don't
throw when motor 4 has no entry in config.motors; resolve motor_id
for the synthetic axis by scanning state['4an'].
- Ctrl: instantiate ExternalAxis after AuxAxis, share the axis_letter
setting, wire AuxAxis state observer.
- Web: route /api/aux/{home,jog,move} through ExternalAxis when it
is enabled so the DRO and synthetic-motor flags stay in sync.
bbctrl.AuxAxis manages a stepper driven by an auxcnc-style ESP32
over /dev/ttyUSB0 (or whichever serial port). Persistent config in
aux.json; UI talks to it via /api/aux/* endpoints.
- AuxAxis: serial framing, position tracking, soft-limit enforcement,
homing state machine, ATC pneumatic control (M100..M103 wrappers).
- Ctrl: instantiate self.aux alongside the other subsystems and
close it during shutdown.
- Web: handlers for /api/aux/{config,status,home,abort,jog,move,set-zero}.
Adds bbctrl.Hooks: a small dispatch layer for HOOK:<event>:<data>
messages embedded in g-code as (MSG,HOOK:droptool:) etc. Hooks can
block the unpause until the registered callback completes and
auto-resume after.
- bbctrl.Hooks: registry, fire, dispatch_hook_message, persistent
config in hooks.json, REST surface (/api/hooks, /api/hooks/save,
/api/hooks/status, /api/hooks/fire/<event>).
- Ctrl: instantiate self.hooks alongside the other subsystems.
- Planner._add_message: when a (MSG,...) line is HOOK:<event>:<data>,
route it through ctrl.hooks instead of state.messages so it never
surfaces as a UI popup and dispatch is immediate (state.messages
has a 250ms debounce).
- Web: handlers for the /api/hooks routes.
- Drop FA4 font files and font-awesome.min.css.
- Ship FA6 webfonts (solid, regular, brands) and fa6.min.css.
- io-indicator: use FA6 names (fa-circle-plus / -minus / -exclamation).
- static/js/ui.js: no-op the legacy side-menu click handler when menu
links are not present (V09 chrome removes them) so the Settings tab
no longer logs 'cannot set properties of null'.
- scripts/rc.local.fast: minimal rc.local that defers the heavy bits.
- scripts/bbserial-rebind.service: oneshot unit that unbinds ttyAMA0
from pl011 and (re)loads bbserial before bbctrl.service.
- scripts/bbctrl.service: declare the After/Wants on bbserial-rebind
so we can rely on it rather than racing rc.local.
- scripts/install.sh: ship the cold-boot bits with firmware updates
(mask sysstat, replace dphys-swapfile with an fstab swap entry).
- scripts/rc.local + setup_rpi.sh + setup.py: wire updated paths.
bbctrl.Trace records monotonic-anchored events from process start.
Ctrl, Comm, the Web layer and __init__ are instrumented so a single
GET /api/diag/timing returns a full timeline of import, controller
init, AVR connection, first websocket, and first GET /. The
restart-timing.js client posts performance.now() marks back so the
browser side can be aligned in the same view.
Used to drive the cold-boot optimisations that reduce listen latency
on the Pi by ~8s.
Importing camotics.gplan pulls in a C++ extension (libstdc++,
boost::python, etc.) which adds several seconds to bbctrl startup
on the Pi. Defer it to Planner.init() — bbctrl can serve the UI
and accept connections without ever touching the planner, and the
penalty is paid only the first time motion is queued.
Tornado removed @web.asynchronous in 6.x; bbctrl on the Pi runs an
older but compatible async-aware build. Switching to coroutine syntax
keeps the streaming endpoint working across Tornado 5/6.
Recursive _rotate() may have already moved or unlinked the source path
by the time we try to rename it (also tolerates concurrent logrotate
runs from /etc/cron.reboot). Catch FileNotFoundError instead of
crashing bbctrl on startup.
backup/onefinity-backup.sh: dd-based whole-card backup/restore with
shrink/expand support so a Pi image can be moved between SD cards
of different sizes.
- .pi/BUILD.md: end-to-end macOS dev workflow, deploy paths, dphys-swapfile vs fstab, troubleshooting.
- .pi/Dockerfile.gplan + build-gplan.sh: rebuild gplan.so from source on Raspbian Stretch (Bullseye is too new for the toolchain).
- Makefile: ensure trailing newline between concatenated pug templates so Pug doesn't glue file boundaries together.