diff --git a/oc-patches/change-mesh-temp/README.md b/oc-patches/change-mesh-temp/README.md new file mode 100644 index 0000000..535dd67 --- /dev/null +++ b/oc-patches/change-mesh-temp/README.md @@ -0,0 +1,14 @@ +# Bed Mesh Temp Change Patch + +## Summary +Binary patching of 0x36d7bc performed to update the bed mesh preheat command from "M109 S60" to "M109 SXX" using the BED_MESH_TEMP value (35–99°C) + +## Summary +Allow user to set default meshing temp between 35C and 99C (hardcoded val is 60C) + +--- + +## Verification +- [x] Confirm patched binary boots normally +- [ ] Confirm mesh happens at XXC +- [ ] Verify mesh saves diff --git a/oc-patches/change-mesh-temp/patch.py b/oc-patches/change-mesh-temp/patch.py new file mode 100755 index 0000000..2f61674 --- /dev/null +++ b/oc-patches/change-mesh-temp/patch.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +# - Only tested on 1.1.40 app binary + +import os +import re +import sys +import shutil +from pathlib import Path + +# ------------------------------------------------------------------- +# Bed-mesh temp patch: +# Replace "M190 S60" -> "M190 SXX" (XX comes from BED_MESH_TEMP in patch_config) +# Only allow 35–99 inclusive to prevent low temps and byte shift. +# +BASE_VA = 0x00010000 # base address +TARGET_VA = 0x036D7BC # address of string "M190 S60" (data_36d7bc) +EXPECTED_BEFORE = bytes.fromhex("4D31393020533630") # "M190 S60" +# ------------------------------------------------------------------- + +# rootcheck +if hasattr(os, "geteuid") and os.geteuid() != 0: + print("[INFO] Skipping: requires root.", file=sys.stderr) + sys.exit(0) + +# env/path +project_root = os.environ.get("REPOSITORY_ROOT") +squashfs_root = os.environ.get("SQUASHFS_ROOT") + +if not project_root or not squashfs_root: + print("Error: REPOSITORY_ROOT and SQUASHFS_ROOT must be set in the environment.", file=sys.stderr) + sys.exit(1) + +project_root = Path(project_root) +squashfs_root = Path(squashfs_root) + +# read BED_MESH_TEMP from patch_config +cfg_file = project_root / "oc-patches" / "patch_config" + +try: + cfg_text = cfg_file.read_text(encoding="utf-8", errors="replace") + m = re.search(r'^BED_MESH_TEMP\s*=\s*([^\r\n#]+)', cfg_text, flags=re.MULTILINE) +except FileNotFoundError: + print("[INFO] Config file not found; skipping patch.") + sys.exit(0) + +if not m: + print("[INFO] BED_MESH_TEMP not found in config; skipping patch.") + sys.exit(0) + +# sanitize +temp_raw = m.group(1).strip() +if not re.fullmatch(r'\d+', temp_raw): + print("[INFO] BED_MESH_TEMP invalid (non-integer); skipping patch.") + sys.exit(0) + +bed_mesh_temp = int(temp_raw, 10) +if not (35 <= bed_mesh_temp <= 99): + print("[INFO] BED_MESH_TEMP invalid (requires integer 35–99); skipping patch.") + sys.exit(0) + +# skip if no change (60 in cfg) +if bed_mesh_temp == 60: + print("[INFO] BED_MESH_TEMP is set to 60 (stock) - no change; skipping patch.") + sys.exit(0) + +# get app +app_dir = squashfs_root / "app" +orig = app_dir / "app" +work = app_dir / "app-patch" + +if not orig.is_file(): + print(f"ERROR: target file not found: {orig}", file=sys.stderr) + sys.exit(1) + +shutil.copyfile(orig, work) + +try: + data = bytearray(work.read_bytes()) +except Exception as e: + print(f"ERROR: failed to read working file: {e}", file=sys.stderr) + sys.exit(1) + +# Check/find +file_off = TARGET_VA - BASE_VA +if file_off < 0 or file_off + 8 > len(data): + print(f"ERROR: invalid offset 0x{file_off:X}", file=sys.stderr) + work.unlink(missing_ok=True) + sys.exit(0) + +before_slice = bytes(data[file_off:file_off+8]) + +# Confirm location +if before_slice != EXPECTED_BEFORE: + print( + f"ERROR: pre-patch bytes mismatch at 0x{file_off:X}\n" + f" found {before_slice.hex().upper()}\n" + f" expected {EXPECTED_BEFORE.hex().upper()}\n" + f" → skipping patch (unsafe)", + file=sys.stderr + ) + work.unlink(missing_ok=True) + sys.exit(0) + +# write change: keep "M190 S", change last two digits +digits_off = file_off + 6 +data[digits_off:digits_off+2] = f"{bed_mesh_temp:02d}".encode("ascii") + +try: + work.write_bytes(data) +except Exception as e: + print(f"ERROR: failed to write working file: {e}", file=sys.stderr) + sys.exit(1) + +bak = orig.with_suffix(".bak") +try: + shutil.copyfile(orig, bak) + shutil.move(str(work), str(orig)) +except Exception as e: + print(f"ERROR: failed to replace original app: {e}", file=sys.stderr) + sys.exit(1) + +after_slice = bytes(data[file_off:file_off+8]) +print( + f"[INFO] Patch successful — bed-mesh temp set: 'M190 S60' -> 'M190 S{bed_mesh_temp:02d}' " + f"- (DEBUG - at 0x{file_off:X}: {before_slice.hex().upper()} → {after_slice.hex().upper()})" +) \ No newline at end of file diff --git a/oc-patches/change-mesh-temp/patch.toml b/oc-patches/change-mesh-temp/patch.toml new file mode 100644 index 0000000..7ae1c83 --- /dev/null +++ b/oc-patches/change-mesh-temp/patch.toml @@ -0,0 +1,6 @@ +id = "bed_mesh_temp" +name = "Customize bed mesh temperature" +compatible_versions = ["1.1.40"] +after = ["base"] +run = ["./patch.py"] +execution_policy = "Always" \ No newline at end of file diff --git a/oc-patches/patch_config b/oc-patches/patch_config index 5af2746..a046942 100644 --- a/oc-patches/patch_config +++ b/oc-patches/patch_config @@ -26,3 +26,4 @@ HOME_POSITION_FRONT_RIGHT=true REPLACE_BOOTLOGO=true SET_FIRMWARE_VERSION=true ALWAYS_ALLOW_Z_OFFSET_ADJUST=true +# BOWDEN_LENGTH_MM=700 \ No newline at end of file