Commit Graph

1180 Commits

Author SHA1 Message Date
01e39722d3 Jog: detailed event/state logging + dry-run env var
Adds visibility into the gamepad event path so future regressions
can be diagnosed without the gantry attached. AJOG EV logs every
incoming KEY event and any ABS event matching the trigger codes;
AJOG STATE logs every transition; the would-be JOG / JOGSTOP is
also logged.

BBCTRL_AJOG_DRYRUN=1 in the bbctrl env disables actuation while
keeping the logging, so the host-side state machine can be tested
without driving the ESP.

Default is live actuation (dry-run off). Used this to prove the
host side was correct on hardware where the firmware bug was
hiding -- pendant taps produced perfect press/release pairs at
~200 ms while the ESP was the one ignoring JOGSTOP.
2026-05-03 17:44:36 +02:00
b63e5bb55a Jog: drive A-axis hold-to-jog through ESP JOG / JOGSTOP
Previous attempts (small STEPS chunks per 250 ms tick, then a
single-big-STEPS plus ABORT-on-release) both gave a jerky ride: the
chunked path produced staccato accel/decel ladders, and the
ABORT-on-release path raced with task creation, frequently letting
STEPS run to its full target.

The auxcnc ESP gained a continuous-rate JOG / JOGSTOP pair (see
auxcnc commit 'Add JOG / JOGSTOP for smooth hold-to-jog'). On
press we issue JOG dir=+/- maxrate=... accel=... and the ESP ramps
up and cruises until JOGSTOP, which triggers a controlled decel.

AuxAxis additions:
  - jog_start(direction, max_rate_sps=, accel_sps2=, ignore_limits=)
    sends JOG and waits only for the immediate '[jog] started' ack.
  - jog_stop() sends JOGSTOP fire-and-forget (no RPC lock so it can
    interrupt anything in flight, mirroring abort()).
  - _on_line picks up async '[jog] done|aborted ...' lines and
    resyncs _pos_steps so subsequent moves compute the correct
    delta.

Jog.py:
  - On Xbox 360 pad RB (BTN_TR) -> A+ press, RT (ABS_RZ) -> A-
    press; release -> JOGSTOP. Speed buttons (X/A/B/Y) scale max
    rate by 1/128, 1/32, 1/4, 1.0x.
  - safe=0 only when A is unhomed; otherwise the ESP enforces
    limit-toward-home_dir abort.
  - On release, schedules a 200 ms-deferred ext_axis._pos_mm
    refresh so any subsequent gplan-driven A motion sees the new
    position.

Verified end-to-end on hardware: smooth ramp-cruise-ramp on
press/release, no overshoot on quick taps, soft limits respected
when homed.
2026-05-03 16:55:48 +02:00
99b5af56cc Jog: bind right back buttons (R1/R2) to A axis hold-to-jog
The default USB pendant config exposed A only via the right stick
X axis (ABS_RX). Most Onefinity-shipped pendants only have one
usable stick, so A was effectively unreachable.

Map BTN_TR (0x137, upper-right back) to A+ and BTN_TR2 (0x139,
lower-right back) to A- while held. Speed scaling matches the
sticks (1/128, 1/32, 1/4, 1x via X/A/B/Y).

R1 was the vertical-axis-lock toggle; horizontal lock on L1 is
preserved, vertical lock is dropped to free R1.
2026-05-03 16:12:42 +02:00
9d7bc57056 Z-A coupling: drop active jog/MDI auto-coordination, keep refuse-only check
The active rewriter for jogs/MDI didn't help anyway because the
continuous-jog buttons send rate-based /api/jog commands to the AVR
and bypass the planner+MDI path entirely. Rather than build out
continuous-jog coupling on the ESP firmware or fake it with browser
ticks, simplify back to:

  * Runtime check (Planner.__encode + ExternalAxis motion entry
    points) refuses any move that would worsen the Z-A gap. Already
    improvement-aware so X/Y jogs and Z-up/A-down recoveries pass.
  * File preprocessor (AuxPreprocessor) injects pre-position A
    moves into uploaded gcode so well-formed programs run without
    operator intervention.

Operator workflow: jog freely down to the safe band; if you need to
go deeper, lower A first (aux jog mm) or use a step-jog MDI like
'G91 G0 Z-10 A-10' that includes the A delta. Programs do the right
thing on their own.
2026-05-03 15:14:25 +02:00
90fd8533fe AuxAxis: push home_preclear_mm via HOMECFG
Tells the auxcnc ESP how far (in steps) to back off if HOME is
invoked while the limit switch is already tripped. The ESP now
hard-fails instead of zeroing blindly when the switch stays active
after the preclear move. Default 10 mm; set home_preclear_mm=0 to
disable the preclear and revert to immediate failure.
2026-05-03 15:14:25 +02:00
ad4815d822 Z-A coupling: auto-coordinate A on jogs and MDI
Match the file-preprocessor behaviour for live operator input. When a
Z-down jog or MDI line would push (A-Z) above the safe band, append
the matching A delta to the same line so the planner runs Z and A
together. Same direction-aware refusal: only error when the operator
explicitly asks A to move *up* (delta > 0) past the bound, or when
the required A would violate A's soft minimum.

Implementation:
  * ExternalAxis.coordinate_mdi rewrites a multi-line MDI burst,
    tracking G90/G91 modal across lines (jogs always emit
    M70/G91/G0/M72; standard MDI defaults to G90). Z and A targets
    are computed in machine coords using offset_z and offset_a so
    the work-coord A token we emit is consistent with the operator's
    frame.
  * The 'A0' the jog UI emits for axes that aren't moving is treated
    as 'no A intent' (G91 delta of zero) and freely overridden.
  * Hooked into Mach.mdi after the existing ATC rewrite. On
    ExternalAxisError the burst is dropped with a user message; the
    planner check downstream still fires as defense in depth.
  * Planner.__encode also catches ExternalAxisError now (vs
    bricking on uncaught) - logs to the operator messages list and
    halts the cycle cleanly so subsequent jogs work.
  * check_coupling itself is now improvement-aware: only refuses
    moves that worsen an existing violation. Pure XY jogs and
    Z-up/A-down recovery moves pass even when (A-Z) is currently
    above the bound.

Tested locally with synthetic MDI: small Z jog within band, Z jog
across the boundary (auto-injects A delta), G90 MDI G0 Z-50
(appends A106), explicit A-lift while Z deep (refuses), pure XY
jog (unchanged), G91 A-down (unchanged), G90 G0 A0 with
offset_a=134 (refuses as lift to home).
2026-05-03 15:14:25 +02:00
5150c3e4a8 Z-A coupling interlock: prevent collision between Z and A tools
The auxiliary A axis carries a tool that hangs below the Z spindle.
Beyond a small Z descent the two physically collide unless A drops
with Z. Enforce in machine coords:

    A_machine - Z_machine <= K
    K = (A_home_mm - z_home_mm) + couple_z_clearance_mm

With our setup K = (134 - 0) + 22 = 156. At rest A=134 Z=0, A-Z=134
which is fine. Z can descend 22mm before the rule starts forcing A
down with it.

Two complementary layers:

(1) AuxPreprocessor injection (auto-fix uploaded files)
    Tracks modal Z, A and distance mode (G90/G91) while scanning the
    file. When a line would put A above Z by more than the clearance
    we emit a 'G0 A<safe>' BEFORE the line so A is already at the
    safe position when Z descends. Endpoint check is sufficient
    because Z moves monotonically along a single line.

    Errors are raised (not silently auto-fixed) when:
      - the line lifts A above the safe band while Z stays put
        (would require auto-injecting a Z-up which could swing
        through a fixture)
      - the line endpoint targets an A above the safe band

    G91 disables injection with a one-shot warning; the runtime
    check still applies.

(2) Runtime check (ExternalAxis.check_coupling)
    Single source of truth for live motion. Hooked into:
      * Planner.__encode for every line block (covers MDI and
        running programs - gplan emits machine-coord targets)
      * ExternalAxis.execute_to_mm/enqueue_target_mm/enqueue_line
        for direct A motion (covers UI jog/move and planner-A
        dispatch)
    Raises ExternalAxisError on violation; gplan and the API both
    surface the message. Skipped when coupling is disabled or the
    axis isn't homed (mirrors the soft-limit gate).

    Continuous Z jog from the AVR is not gated - it's an active
    operator action without a pre-known endpoint. Operator-driven
    over-travel during continuous jog will be caught by the next
    MDI/file-load attempt.

Configuration in aux.json:
    couple_z_enabled        bool   default true (per agreed setup)
    couple_z_clearance_mm   float  default 22.0
    z_home_mm               float  default 0.0

Surfaced in the new Z-A Coupling section of the A Axis settings
page with a description of the rule. Existing aux.json files get
the new keys via the merged-defaults path on read.

Tested locally with synthetic gcode covering Z descent, combined
moves, A lift while Z deep, G92 reset, G91 mode, and combined
Z+A target violations.
2026-05-03 15:14:25 +02:00
4109f9f838 docs: A axis architecture (renamed from W) + README section
- Move docs/AUX_W_AXIS.md to docs/AUX_A_AXIS.md and rebadge W -> A
  throughout, with a header note pointing at ExternalAxis as the
  current implementation.
- README: A-axis fork heading, link to AUX_A_AXIS.md, /api/aux/status
  in verify-flash, small comment in scripts/deploy/local.sh.
2026-05-03 15:14:25 +02:00
ad846b6033 Config: idempotent macro file rename W -> A
The auxiliary stepper used to be exposed as a W axis. After the
gplan integration it is exposed as A. Migrate persisted macro
config on every load:
  w_down.nc -> a_down.nc
  w_up.nc   -> a_up.nc
  'W Down'  -> 'A Down'
  'W Up'    -> 'A Up'

Idempotent so a stale in-memory copy can never reintroduce the old
names.
2026-05-03 15:14:25 +02:00
7a3c2bbb0d UI: A axis surface (DRO row, jog, Home A, settings page)
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.
2026-05-03 15:14:25 +02:00
da619bd56c ATC: M100..M103 preprocessor + Mach MDI rewrite + hook handlers
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.
2026-05-03 15:14:25 +02:00
800cb04e3b ExternalAxis: virtual A axis through gplan, mirrored on the ESP
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.
2026-05-03 15:14:25 +02:00
d797f1d4fc AuxAxis: ESP32-driven external stepper (auxcnc)
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}.
2026-05-03 15:14:25 +02:00
80a00978b7 Hooks: ATC IPC layer between gcode preprocessor and runtime
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.
2026-05-03 15:14:25 +02:00
f0a37828a4 docs: rename esp-a-axis branch to private-mods in AGENTS.md 2026-05-03 15:14:21 +02:00
2b949c4f00 docs: AGENTS.md - branch model and where-does-it-go guide 2026-05-03 15:10:25 +02:00
72c69d3000 docs: CHANGELOG entry summarising the community-fork additions 2026-05-03 14:12:18 +02:00
94072253d4 ui: V09 redesign - Control/Program/Console/Settings shell
Replaces the legacy side-menu chrome with a 4-tab top header.

- index.pug: tablet/kiosk fit-to-viewport script, header tab nav,
  estop/state badges in header.
- app.js: route hash to (control|program|console|<settings-family>),
  multi-section settings shell.
- control-view: header DRO, jog grid, MDI/probe/macros panels.
- program-view + program-mixin: file browser + toolpath preview +
  run/pause/stop, replaces the legacy 'macros' tab content.
- console-view: MDI shell, message log, indicators.
- settings-shell-view: rail-driven inner pages (Display & Units,
  Probing, G-code & Motion, Macros, Network, etc.).
- settings-view: filter Svelte SettingsView to one rail section.
- SettingsView.svelte: tag every section with data-sec=… so the
  filter above can hide non-matching ones.
- style.styl: ~2700 lines of V09 layout, DRO, jog grid, status
  strip, and tablet/kiosk variants.

No A-axis / auxiliary-axis content lives on this branch.
2026-05-03 14:11:29 +02:00
c10f5c053a ui: assorted polish - Vue async fix, OrbitControls passive listeners, path-viewer + motor-view + indicators
- main.js: disable Vue async batching so reactive writes from
  hashchange listeners propagate synchronously (matches Vue 1's older
  default; avoids dropped DRO updates).
- orbit.js: pass {passive:false} to wheel/touch listeners so
  OrbitControls.preventDefault() actually suppresses page panning.
- path-viewer: opaque dark canvas (no flash from page background),
  zero-size guard, ResizeObserver cleanup on destroy.
- motor-view: stop clobbering user edits with controller state.
- estop/indicators/tool-view/path-viewer pug: rename FA4 icons to FA6,
  add viewBox to estop SVG, fix tool-view trailing newline.
2026-05-03 14:07:35 +02:00
b9e880448e ui: upgrade to FontAwesome 6, harden burger-menu shim
- 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'.
2026-05-03 14:07:06 +02:00
8224ab8f97 boot: cold-boot optimisations cutting bbctrl listen by ~8s on the Pi
- 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.
2026-05-03 14:06:44 +02:00
0b5ab2ff3b diag: add startup-timing trace and /api/diag/timing endpoint
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.
2026-05-03 14:06:17 +02:00
94270e7725 Planner: lazy-load camotics.gplan so HTTP listener comes up first
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.
2026-05-03 14:04:30 +02:00
7a6e2cd00b Camera: replace deprecated @web.asynchronous with async def
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.
2026-05-03 14:04:03 +02:00
785dafc3bc Log: tolerate missing rotated log files on startup
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.
2026-05-03 14:03:58 +02:00
0d5370a724 deploy: add macOS-friendly deploy scripts (local / hardware / prod)
- deploy.sh dispatcher + thin shims (deploy-local.sh / -hardware.sh / -prod.sh).
- scripts/deploy/local.sh: build UI bundle and serve via tmux session on :8770 for offline iteration.
- scripts/deploy/hardware.sh: rsync-based push to a Pi over SSH and restart bbctrl.service.
- scripts/deploy/prod.sh: bundle release tarball.
- scripts/deploy/patch_font_mime.py: hot-patches Chromium 72's broken WOFF2 mime handling on the kiosk Pi.
2026-05-03 14:03:50 +02:00
f170002c8b tools: SD card backup/restore script
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.
2026-05-03 14:03:24 +02:00
24215a8b36 build: document Pi firmware build/flash + gplan.so cross-build via Stretch Docker
- .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.
2026-05-03 14:03:20 +02:00
3ca19ea875 chore: ignore build/log/scratch artefacts and dev-container helper 2026-05-03 14:03:08 +02:00
sanjayk03-dev
44b85bad5a v1.6.7 2025-09-21 01:57:17 +05:30
sanjayk03-dev
f092c0c5d0 UI change 2025-09-21 01:52:42 +05:30
sanjayk03-dev
fda579d765 making easy-adapter reactive 2025-09-21 01:45:20 +05:30
sanjayk03-dev
9b72d7c5cc debuging with logs 2025-09-21 01:37:52 +05:30
sanjayk03-dev
6eb2739426 Merge branch 'v1.6.0' of https://github.com/sanjayk03-dev/onefinity-firmware into v1.6.0 2025-09-21 01:31:59 +05:30
sanjayk03-dev
31fae30546 made label reactive 2025-09-21 01:31:55 +05:30
bsaravanan783
7fd8d32680 Merge branch 'v1.6.0' of https://github.com/sanjayk03-dev/onefinity-firmware into v1.6.0 2025-09-21 01:26:36 +05:30
bsaravanan783
4fe84412d4 easy- adapter style chagne 2025-09-21 01:26:28 +05:30
sanjayk03-dev
6f881e1eae changed to 90 seconds modal 2025-09-21 01:22:44 +05:30
sanjayk03-dev
363f3a770e UI changes 2025-09-21 01:21:55 +05:30
sanjayk03-dev
4ef4943ce9 fixed modal opening on each refresh 2025-09-21 01:06:42 +05:30
bsaravanan783
104cbbf5da styles 2025-09-21 01:05:41 +05:30
bsaravanan783
a0ebced79a changed easy adapter to true 2025-09-21 00:53:01 +05:30
sanjayk03-dev
763fb3a763 testing with 5 secs 2025-09-21 00:27:47 +05:30
sanjayk03-dev
02c01bcc08 added title for easy adapter in settings 2025-09-21 00:23:53 +05:30
sanjayk03-dev
5c15385d0f consumed easyadapter dialog and added timer 2025-09-21 00:21:48 +05:30
sanjayk03-dev
1b18f2e4ba fixed cond 2025-09-21 00:02:29 +05:30
sanjayk03-dev
9a347e3406 easy adapter dialogs 2025-09-20 23:55:46 +05:30
sanjayk03-dev
6889828e7a easy adapter UI 2025-09-20 23:47:42 +05:30
sanjayk03-dev
668a116de7 added easy adapter in settings 2025-09-20 23:36:33 +05:30
sanjayk03-dev
6192afd532 added metadata 2025-09-20 23:02:36 +05:30