Files
MonstrofilandClaude Opus 5 5718603f1c Document how a spool's material reaches OrcaSlicer (#25)
OrcaSlicer 2.4.0's Moonraker agent offers to map a project's filaments onto
the printer's slots, and it learns those slots from the `lane_data` namespace
in Moonraker's database. Nothing in the tree said where that data comes from,
so the question "what does this need to work?" had to be answered by reading
three codebases: ff_toolchange's status surface, HelixScreen's AMS backend
and override store, and MoonrakerPrinterAgent.cpp.

The note is that answer as one diagram plus the reasoning around it. Klipper
supplies the slot count and nothing else -- it cannot sense what filament is
in a tool; the operator supplies the identity through HelixScreen; Moonraker's
database is the only durable record; OrcaSlicer reads it once at connect and
never writes back.

It also records the two things that surprised us. The mapping is not applied
at print time -- start_local_print() ignores ams_mapping, so it selects
presets and temperatures at slice time and does not rewrite tool numbers. And
the reason this does not work on our build yet is not a missing feature but a
missing merge: AmsBackendToolChanger was the last AMS backend without a
FilamentSlotOverrideStore, upstream gave it one on 2026-08-24, and our last
catch-up from upstream is four days older than that.


Claude-Session: https://claude.ai/code/session_01PU5nCo85xuFQuub4kJzWt9

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 13:15:19 +03:00

4.9 KiB
Raw Permalink Blame History

firmwareExe analysis — overview

Analyzed binary: firmwareExe (20.9 MB, ELF 32-bit MIPS32r2, Ingenic XBurst2 SoC, Linux 3.10.14, not stripped — full C++ symbols). Machine identifies itself as "Creator 5 Pro", cloud backend api.voxelshare.com.

The single most important finding

The printer already runs Klipper. firmwareExe is NOT the motion firmware — it is the LVGL touchscreen UI + orchestration daemon. It:

  • starts Klipper with /usr/prog/klipper/start.sh &
  • talks to Klipper's native API socket at /tmp/uds (stock webhooks JSON: gcode/script, objects/query, objects/subscribe, …)
  • implements everything "smart" (toolchange orchestration, print lifecycle, filament runout auto-swap, calibration wizards, cloud/camera/LAN APIs) app-side, by sending G-code strings.

The Klipper fork itself ships no START/END/PAUSE/RESUME/CANCEL macros and no toolchange motion code — a print started from Mainsail/Moonraker gets none of that behaviour unless something re-provides it. That something is this repo: ff_toolchange.py + the config/macros.

System architecture

firmwareExe (touchscreen app)
 ├─ LVGL UI on /dev/fb0 + touch /dev/input/event2
 ├─ KlipperAPI ──/tmp/uds──► Klipper fork (/usr/prog/klipper)
 │                            ├─ mcu           main board: X/Y/Z, bed
 │                            ├─ eboard        /dev/ttyS5 carriage extruder driver
 │                            ├─ eheaterboard  /dev/ttyS4 4 hotend heaters + 24V
 │                            └─ levelboard    /dev/ttyS7 fixed under-bed cylinder
 ├─ DryingService ──/dev/ttyS3──► filament drying box (own MCU, not Klipper)
 ├─ OrcaServer / MQTT cloud / camera
 └─ /usr/data/firmwareRes/config/*.json — per-unit calibration + state

Printer facts

  • 4-tool toolchanger: docked heads T0–T3 at X≈297 (250/280 are the staging and approach waypoints, not the docks), picked up by the X carriage with a lock motor. temperature_sensor motor_value exists (printer.motor.cfg) but the app only ever logged it -- no grab/release decision reads it; see 25-app-vs-klipper-ownership.md.
  • Bed ~250×250, 10×10 bed mesh from the carriage eddy ([probe], eboard:PG0). Nozzle XY/Z offset calibration uses a different sensor: the fixed inductive cylinder under the bed ([e_stop X/Y/Z] on levelboard:PD0).
  • 4 filament channels, each a direct-drive extruder on its own head — there is no feed hub; manual_stepper gear_stepper is the tool LOCK motor (see 47-filament-load-recovered.md). Presence sensors fd_ex0..3, motion sensors fm_ex0..3.
  • Chamber heater + 4 fans + LED, front/top door switches.

Method

The binary is not stripped, so targeted questions are answered by reading symbols and disassembling straight from the file (capstone), rather than a full Ghidra project — Ghidra's auto-analysis wrongly marked the logging helpers noreturn and truncated ~916 functions (29k bogus CALL_RETURN overrides), so its decompile of exactly the interesting CommMgr methods was misleading until repaired. Addresses cited in these notes are verified against the live binary.

Notes map

Files ending -recovered are reconstructions of the stock app's behaviour; the matching -port note says what this repo actually shipped.

  • 10-hardware.md — MCUs, serial ports, Klipper objects the UI expects
  • 20-klipper-fork.md — fork delta: custom commands, the Tn interception
  • 25-app-vs-klipper-ownership.md — which side owns which behaviour, and what is ported
  • 30-toolchange.md — dock/grab/release sequences, sensors, mounted-tool state
  • 40-offsets.md — where per-unit numbers live; per-tool offsets; the absolute print Z offset
  • 44-vfa-calibration.md — VFA (motor torque-ripple) compensation: the stock chain, what applies it, and the numpy gap that stopped klippy booting
  • 45-tool-offset-calibration.md — the Klipper port: storage layout, commands, guards
  • 46-offset-calibration-recovered.md — the app's calibration sequence it was ported from
  • 47-filament-load-recovered.md / 48-filament-load-port.md — load/unload/purge
  • 49-runout-recovered.md — runout and clog handling (ported: ff-runout.cfg)
  • 50-print-lifecycle.md — start/pause/resume/cancel/complete, address-verified
  • 50a-nozzle-clean-recovered.md / 50b-nozzle-clean-port.md — the pre-print nozzle clean
  • 51-pa-calibration-recovered.md — automatic pressure advance: the sweep, and how to port it
  • 53-filament-slot-metadata.md — how a spool's material and colour reach OrcaSlicer, through Moonraker's lane_data
  • 60-background.md — filament system, calibration flows, config keys (background context)
  • 70-error-codes.md — full E-code table (behavioral spec)
  • 80-s6-migration.md — the prefix root and s6 supervision plan
  • 85-packaging.md — apk vs opkg, why the first answer was opkg, and the migration to apk that reversed it