mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-21 21:02:16 -05:00
worktree-timelapse-test-gcode
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
42d876d5eb |
The auto-PA sweep is host code; only the per-line verdict is in the eBoard
firmwareExe runs a real PA calibration at print start, inside the nozzle clean. CommMgr::paTestMgr @0x791640 prints one slow-fast-slow line per candidate at Y = 50 + 5*i for seven fixed PA values, asks the eBoard to score each line, keeps the smallest that scores 9, repeats until three sweeps have produced a winner and averages those three. All of that is host code and is recovered here in full. Only the verdict crosses into the closed toolhead MCU, over two commands that pa_adjust.py already forwards -- and pa_adjust.py is in our tree byte-identical to FlashForge's, with [pa_adjust] already in printer.base.cfg. So PA_ACTION and PA_GET should answer on a Reforge machine today; that is step one of the port. This supersedes "sensor unknown" in 60-background.md and "callable, not reproducible" in 25-app-vs-klipper-ownership.md. What stays unknown is narrower: which sensor the eBoard samples, what ACTION=11 and PC=666 select, and what the non-9 verdicts mean. Two findings that shape the port. PA_GET only respond_info()s its value, so the sweep cannot be a G-code macro -- it needs an extra that queries the eBoard directly. And PA_ACTION is an immediate MCU command, so FlashForge never synchronises the measurement window with motion; the port must copy that timing rather than improve it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw2rehvQJ7LSc28hPikfqk |
||
|
|
a22f3b04ef |
Tool calibration speaks klipper-toolchanger's G-code
STATION_CALIBRATE is TOOL_LOCATE_SENSOR and TOOL_OFFSET_CALIBRATE is
TOOL_CALIBRATE_TOOL_OFFSET, with upstream's call shape as well as its
names: no TOOL= (the mounted tool is the one measured, so SELECT_TOOL
first, as upstream's macro does) and no PLATE_REMOVED=.
The renames are not just conformance. Upstream says "run
TOOL_LOCATE_SENSOR with tool 0" because tool 0's nozzle is the only
thing on their machine that can reach the pin -- their baseline is a
tool, so tool 0's own error rides into every other tool. Here the
carriage's probe element sits above the tool mount and reaches the
station directly with nothing installed, so the command means what it
says: locate the sensor, with no tool. That baseline cannot be spoiled
by a badly seated T0, which is what lets nozzle_x/y/z stay absolute and
per-tool independent.
PLATE_REMOVED=1 goes because the plate check that runs anyway is the
better guard: it parks the carriage and MEASURES whether the plate is
there, where the flag only asked the operator to promise. Dropping it
also removes the last non-upstream required parameter.
Losing TOOL= means losing TOOL=ALL, so CALIBRATE_TOOL_OFFSETS loops over
printer.toolchanger.tool_numbers -- the same shape as upstream's macro.
GRAB=/RELEASE= go with it: they cannot mean anything once the tool has
to be mounted already. The plate check still needs an empty carriage, so
the command parks the selected tool and picks it straight back up.
Probe sampling gets klipper-toolchanger's parameters -- SAMPLES,
SAMPLES_TOLERANCE, SAMPLES_TOLERANCE_RETRIES, SAMPLES_RESULT,
SAMPLE_RETRACT_DIST, PROBE_SPEED -- on both commands and in
[ff_tool_offset]. The fork's e_stop ALREADY samples (sub_cycle_cnt
touches, spread rejected above error_v, retried main_cycle_cnt times,
averaged); what was missing was reaching those numbers from a command
and a median. So _estop runs that loop itself over the fork's
single-touch _probe, every default is read off the [e_stop <axis>]
object, and an unparameterised command probes exactly as it did before.
Spread is judged after each touch, as the fork does, so a round already
known bad is not finished. Two things the fork does not bound are
bounded here: the 9999 move-failure sentinel it spins on forever, and an
e_stop with no _probe, which falls back to run_probe as one sample
rather than cubing the touch count.
Also fixes _plate_check reaching for z_trigger where it had bound
station_z -- a NameError left by the rename sweep in
|
||
|
|
5798606e48 |
The pre-HelixScreen program waits for the boards, and says which one
It only ever ran on a first boot, and only to migrate. Every other boot it exited at its stamp in microseconds and HelixScreen started immediately -- against a klippy that was very often still hunting for its MCUs. What the owner saw then was a UI reporting a disconnected printer, with nothing anywhere naming the board that had not answered. So ff-firstboot-import.py becomes ff-startup.py, with the migration demoted to its second job. Every boot it now waits: first for ff-mcu-bringup.py, which start.sh runs alongside it, to finish handing the toolhead boards over from their bootloaders, then for klipper and moonraker to be ready. Only after that does it look at the stamp and decide whether there is a migration to do. Naming the board needed a source. ff-mcu-bringup.py now publishes what it is still working on to /tmp/ff-mcu-bringup.status -- rewritten only when the outstanding set actually shrinks, renamed into place so a reader never sees half a file, and on a tmpfs so it cannot survive a reboot and be mistaken for this boot's. The panel turns the serial port into something an owner can act on: WAITING FOR THE HEATER BOARD, not /dev/ttyS4. When klippy fails outright its own state_message is the only place the guilty board is named, so that is parsed too and becomes THE HEATER BOARD DID NOT ANSWER. The MCU wait is one we are happy to abandon. A bring-up that never reports -- because it has not started yet, or wrote something malformed, or is simply absent -- times out into the klipper wait rather than holding the boot: klippy is the real authority on whether a board answered, and it has a far better message than we could write. Tests pin that, including a parametrised sweep of malformed status files. The two halves of that file format are checked against each other rather than against a copy of it written down twice. MOD_STARTUP=0 skips the whole thing; MOD_IMPORT=0 keeps the wait and skips only the migration. 20 frames, still byte-identical host to replica. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
97caf27e1c |
The factory-calibration import moves out of klippy
Importing this unit's nozzle/dock/station numbers out of firmwareExe's JSON is a Creator-5 chore that happens once per INSTALL, and it lived inside a general-purpose Klipper extra on a klippy:ready hook -- the one moment klippy cannot know whether the rest of the machine is up. It also had no memory of having run: auto_import re-decided itself on every ready by guessing from "has anything been calibrated yet", so the lifetime was wrong in both directions. It is now bin/ff-firstboot-import.py, its own program with one job, which the firmwareExe wrapper runs ahead of HelixScreen. It exits on a stat() of its stamp (every boot but the first) or when there is no firmwareRes JSON at all; otherwise it waits until klipper, moonraker AND Mainsail are all answering, sends FF_IMPORT_FIRMWARE_CONFIG and SAVE_CONFIG over the moonraker API, rides out the klippy restart that save causes, verifies the values came back saved, and only then stamps. It stands down if a tool is already calibrated or if someone else's SAVE_CONFIG is pending -- neither is ours to overwrite. Nothing short of a verified save writes the stamp. The heater board on this machine routinely needs several klippy restarts before it answers, so "the stack was not up in time" is a normal event to retry on the next boot, not a failure to record forever. It runs in the foreground before the UI because the save restarts klippy, and doing that behind a HelixScreen already showing a printer is worse than making the splash wait; MOD_IMPORT_TIMEOUT bounds it and MOD_IMPORT=0 turns it off. BREAKING: [ff_legacy] auto_import and auto_save are gone, and klipper refuses to start on an unknown option -- anyone who set either one in printer.cfg has to remove it. FF_IMPORT_FIRMWARE_CONFIG itself is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
d05565284d |
Sections E, F, G: wrong values, stale claims, overclaims
E -- values and counts. The START_PRINT prologue has no M400 and an idle timeout of 864000, not 1800000. The nozzle-clean temperature comes from the material table FIRST, so NOZZLE=240 with no per-tool temp cleans at 220 -- documented backwards before. TOOLS is the paired 0:220,2:240 form. The wipe Z is the raw eddy frame, not the homed one. The runout M117 strings are "T<n> clog" / "T<n> out of filament", not E-codes. Grab-verify raises E0051+tool, not E0143. Docks are at X~297; 250/280 are staging waypoints. The grab sequence is documented in the order _grab actually emits it. ff_print exposes seven status fields, not nine, and never emits TOOLS=. Package sizes reconciled against the real artifacts (62MB built, ~93MB stock, ~370MB of CI assets, ~60s not 90s). testing.md's sample output block matched no header the code prints, so it is replaced with the real ones; its pytest row listed two of six suites. F -- stale claims. _FF_PREFLIGHT is not "missing". SDCARD_SET_CHANNEL is not still issued ( |
||
|
|
e5bd171cf8 |
Correct the docs the code had drifted away from
Applies the audit's sections B, C and D, plus two decisions. Behaviour (A1): fm_ex1..3 carried stock's `extruder: extruder`, so a clog on T1..T3 was measured against T0's filament movement. Each motion sensor now watches its own extruder. Gate count (A6): "four gates" was the number of make test-* targets, not of gates run -- run-tests.py emits twelve. The number is dropped rather than restated, in docs/testing.md and the Makefile help. B, install instructions that failed as written: STOCK_TGZ_CREATOR5 missing its .tgz; a pointer to a ./build.sh that does not exist; klippy-extras/ paths that moved to payload/klipper/extras/ in 0ef9d6b; a calibration recipe both commands refuse without PLATE_REMOVED=1; a storage table that put dock_x/dock_y in an include, which SAVE_CONFIG refuses; four files telling the user to add includes printer.base.cfg already ships; ./pack.sh style paths that do not resolve from where the scripts leave you. The MAINSAIL_ZIP / HELIX_TGZ override was documented in three places as "used as-is, never checksummed". It is checksummed, and fetch-assets.sh overwrites the user's file with the pinned release -- SKIP re-downloads too. Corrected, with the way that actually works (match the hash in versions.env). C, files that contradicted themselves: the -5/-3 ESTOP target, the t<n>_offset_* storage names, the chamber heater's model split, the LED premise, the include order comment in test_includes.py, gear_stepper as a "feed hub" when it is the tool lock, an object list ff-toolchange.cfg says does not exist, the eddy probe vs the under-bed cylinder, "installs them without clobbering" against a gate that enforces the clobber, "keeps two versions" when the installer keeps one, "two changes from stock" when there are three, and ff_legacy's "nothing here runs during normal operation" when auto_import runs on every ready. D, dangling references: OKF/* and firmwareExe-decompiled/* repointed at docs/notes/*, plus case-boot.sh, sim-image.sh, printer-exec.sh, the test/printer build context, wait_for_banner, ff_toolchanger_compat and a nonexistent orca snippet. Not touched, pending a decision: sections E-H, and the printer.base.cfg "verbatim" claim (A7), which depends on how the unpack drift check is fixed. 48 passed, 5 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0ef9d6b86b |
Move the imported toolchange files into this repo's layout
Pure renames, no content changes, so `git log --follow` walks straight back into the toolchange history imported by the previous commit. klippy-extras/ff_*.py -> payload/klipper/extras/ config/ff-*.cfg -> payload/klipper/config/ helixscreen/*.json -> payload/helixscreen/printer_database.d/ orca/ -> assets/orca/ docs/notes/ -> docs/notes/ README.md -> docs/toolchange.md payload/ is the right home for the first three: they are files that ship to the printer, which is what everything else under payload/ is. The Orca snippets go to assets/ instead -- they are pasted into a slicer on the desktop and never reach the machine. bin/patch.sh still reads them from $TOOLCHANGE; the next commit points it here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GgNhSa1Qvwvxb2nQXT6b1Y |