Repository navigation
Add experimental on-printer HID erase-fix installer (review of #19) #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
phryneas
wants to merge
4
commits into
main
Choose a base branch
from
feat/on-printer-hid-fix-review
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
58eb6c9
Restore on-printer HID installer for review
phryneas c6c5932
Rewrite on-printer guide around installation and correct reboot advice
phryneas 9652053
Clarify version availability, result reporting and 30D detection
phryneas faf9343
Warn before identification can lead to an extra camera boot
phryneas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| name: On-printer HID tool | ||
| on: | ||
| push: | ||
| pull_request: | ||
| workflow_call: | ||
| permissions: | ||
| contents: read | ||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 20 | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| ref: ${{ github.sha }} | ||
| persist-credentials: false | ||
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | ||
| with: | ||
| python-version: '3.12' | ||
| - name: Check embedded canonical payload and shell contracts | ||
| run: | | ||
| python on-printer/generate_payload.py --check | ||
| python -m unittest discover -s tests -p test_on_printer.py -v | ||
| sh -n on-printer/payload/installer.sh | ||
| - name: Install native build tools | ||
| run: | | ||
| rustup toolchain install 1.85.1 --profile minimal --component clippy --target armv7-unknown-linux-musleabihf | ||
| sudo apt-get update | ||
| sudo apt-get install -y gcc-arm-linux-gnueabihf qemu-user | ||
| - name: Test native protocol and compile static ARMv7 binary | ||
| env: | ||
| CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER: arm-linux-gnueabihf-gcc | ||
| CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_RUNNER: qemu-arm | ||
| run: | | ||
| cargo +1.85.1 test --locked --manifest-path on-printer/Cargo.toml | ||
| cargo +1.85.1 clippy --locked --manifest-path on-printer/Cargo.toml --all-targets -- -D warnings | ||
| cargo +1.85.1 test --locked --manifest-path on-printer/Cargo.toml --target armv7-unknown-linux-musleabihf | ||
| cargo +1.85.1 build --locked --manifest-path on-printer/Cargo.toml --release --target armv7-unknown-linux-musleabihf | ||
| - name: Check static linking and smoke-test executable | ||
| run: | | ||
| mkdir -p dist | ||
| cp on-printer/target/armv7-unknown-linux-musleabihf/release/cc2camera-hid dist/cc2camera-hid-armv7-linux | ||
| file dist/cc2camera-hid-armv7-linux | ||
| if readelf -l dist/cc2camera-hid-armv7-linux | grep -q INTERP; then exit 1; fi | ||
| if readelf -d dist/cc2camera-hid-armv7-linux | grep -q NEEDED; then exit 1; fi | ||
| qemu-arm dist/cc2camera-hid-armv7-linux --help | ||
| if qemu-arm dist/cc2camera-hid-armv7-linux install; then exit 1; fi | ||
| cd dist | ||
| sha256sum cc2camera-hid-armv7-linux > cc2camera-hid-armv7-linux.sha256 | ||
| wc -c cc2camera-hid-armv7-linux | ||
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: cc2camera-hid-armv7-linux | ||
| path: | | ||
| dist/cc2camera-hid-armv7-linux | ||
| dist/cc2camera-hid-armv7-linux.sha256 | ||
| if-no-files-found: error |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,3 +23,6 @@ Thumbs.db | |
| *.swp | ||
| *~ | ||
| *.spec | ||
|
|
||
| # Native on-printer builds | ||
| on-printer/target/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| [package] | ||
| name = "cc2camera-hid" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| publish = false | ||
|
|
||
| [profile.release] | ||
| opt-level = "s" | ||
| lto = true | ||
| codegen-units = 1 | ||
| panic = "abort" | ||
| strip = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # Install the camera fix from a CC2 shell | ||
|
|
||
| This tool installs the startup fix on a working, affected camera without | ||
| disconnecting it from the printer. You need root shell access to an idle CC2 | ||
| and a USB drive to transfer the executable. Obtaining shell access is outside | ||
| this guide. | ||
|
|
||
| **Keep an already-running camera powered; do not reboot to prepare for this | ||
| procedure.** Another boot can exhaust a nearly full configuration partition | ||
| and leave an affected camera unable to boot. | ||
|
|
||
| Start with the [read-only stream identification](../README.md#first-identify-your-camera). | ||
| If the stream is unavailable or the result is unknown, stop and | ||
| [ask for help](https://github.com/OpenCentauri/cc2_camera_fix/issues/new) while | ||
| leaving the camera powered. Do not proceed to that guide's physical-inspection | ||
| fallback without first considering the risk of the extra boot it requires. | ||
|
|
||
| This route supports the affected 8 MiB 30B family, not the early 16 MiB 30B or the | ||
| 30D. A camera that no longer boots needs [hardware recovery](../README.md#failed-camera-hardware-recovery). | ||
|
|
||
| **Experimental:** installation and verification have succeeded on a previously | ||
| modified 30B. First installation on an unmodified, supported camera still needs | ||
| volunteers. If you try it, please [open an issue](https://github.com/OpenCentauri/cc2_camera_fix/issues/new) | ||
| to share results and get help with problems or tool adjustments. | ||
|
|
||
| ## Before installing | ||
|
|
||
| The installer writes two startup scripts to the camera. It does **not** make a | ||
| backup or check how much safely writable configuration space remains. If that | ||
| space is nearly exhausted, installing the scripts can leave the camera unable | ||
| to boot, requiring an external SPI programmer for recovery. Power loss during | ||
| installation can also cause failure. | ||
|
|
||
| Leaving an affected camera unchanged also consumes configuration space on each | ||
| boot. A camera close enough to exhaustion for these writes to cause failure | ||
| may have only a few normal boots left. Moving it to a computer for the | ||
| [USB procedure](../README.md#working-camera-usb-prevention) adds a boot that can | ||
| itself trigger failure. That procedure offers a backup and space check once | ||
| connected; this route avoids the extra boot and cable work, but is less tested. | ||
| The number of remaining boots cannot be determined by this tool. | ||
|
|
||
| If you have already attempted `install` or `verify` during this camera boot, | ||
| see [If a command fails](#if-a-command-fails) before doing more. | ||
|
|
||
| ## Download and inspect | ||
|
|
||
| Download `cc2camera-hid-armv7-linux` and `cc2camera-hid-armv7-linux.sha256` from | ||
| [Releases](https://github.com/OpenCentauri/cc2_camera_fix/releases) and put both | ||
| files at the root of a USB drive. Insert it into the printer. | ||
|
|
||
| In the printer's root shell, with the drive mounted at `/mnt/exUDISK`: | ||
|
|
||
| ```sh | ||
| cd /mnt/exUDISK | ||
| sha256sum -c cc2camera-hid-armv7-linux.sha256 | ||
| ``` | ||
|
|
||
| Continue only if the checksum reports `OK`. Adjust the drive path if needed. | ||
|
|
||
| ```sh | ||
| cp cc2camera-hid-armv7-linux /tmp/cc2camera-hid | ||
| chmod 755 /tmp/cc2camera-hid | ||
| /tmp/cc2camera-hid inspect | ||
| ``` | ||
|
|
||
| `inspect` reads the camera identification and queries its version. It does not | ||
| upload anything or change camera files. **You can proceed directly to install | ||
| without rebooting.** Some cameras have no version file, so inspection may report | ||
| "Camera version unavailable". This does not prevent installing the fix; the | ||
| installer checks firmware compatibility separately. Stop if inspection reports | ||
| an error or an unsupported camera. | ||
|
|
||
| ## Install | ||
|
|
||
| If you accept the installation risk above, run: | ||
|
|
||
| ```sh | ||
| /tmp/cc2camera-hid install --accept-no-backup-space-risk --verbose > /tmp/cc2camera-install.log 2>&1 | ||
| cat /tmp/cc2camera-install.log | ||
| ``` | ||
|
|
||
| Keep power on until the command finishes. Success begins with: | ||
|
|
||
| ```text | ||
| Camera reports exact installed hook contents and permissions verified. | ||
| ``` | ||
|
|
||
| This means the startup scripts were written and checked. They take effect on | ||
| the next camera boot. Any error instead requires the steps below, not a retry. | ||
|
|
||
| If you know your camera already has custom startup scripts, adding | ||
| `--overwrite-managed-scripts` permits replacing `/etc/conf.d/system.sh` and | ||
| `/etc/conf.d/enabled/10-erase-fix.sh`. Custom behavior in those two files will be | ||
| replaced; other enabled scripts remain. Without the flag, different contents | ||
| are refused. A stock camera does not need this flag. If you encounter that | ||
| refusal unexpectedly, keep the log and ask for help before another attempt. | ||
|
|
||
| ## Verify after installation | ||
|
|
||
| After the success message, wait at least two minutes, then turn the idle printer | ||
| fully off and back on. A shell `reboot` may leave the camera powered and will | ||
| not reliably activate the fix. Copy the executable back from the USB drive: | ||
|
|
||
| ```sh | ||
| cp /mnt/exUDISK/cc2camera-hid-armv7-linux /tmp/cc2camera-hid | ||
| chmod 755 /tmp/cc2camera-hid | ||
| /tmp/cc2camera-hid verify --verbose > /tmp/cc2camera-verify.log 2>&1 | ||
| cat /tmp/cc2camera-verify.log | ||
| ``` | ||
|
|
||
| Verification runs a temporary probe on the camera, without changing its | ||
| persistent files or applying the fix itself. Success is: | ||
|
|
||
| ```text | ||
| Camera reports canonical hooks and the live erase correction verified for this boot. | ||
| ``` | ||
|
|
||
| Check that the camera feed works too. Please consider | ||
| [opening a GitHub issue](https://github.com/OpenCentauri/cc2_camera_fix/issues/new) | ||
| to report a successful installation and the result of that check. | ||
|
|
||
| ## If a command fails | ||
|
|
||
| Keep the camera powered and save the log to the USB drive before it is lost | ||
| on a printer restart, for example: | ||
|
|
||
| ```sh | ||
| cp /tmp/cc2camera-install.log /mnt/exUDISK/ | ||
| sync | ||
| ``` | ||
|
|
||
| Use `cc2camera-verify.log` instead for a verification failure. Open an issue with | ||
| the log and command you ran. `--verbose` captures the HID communication; it can | ||
| also be added to `inspect` when diagnosing a connection problem. | ||
|
|
||
| Do not repeat an upload or restart simply because a command failed. A preflight | ||
| refusal means installation writes did not start; a partial-installation error | ||
| means they did. A timeout or USB error leaves the outcome unknown, and a camera | ||
| worker may still be running. The uploader also cannot accept another attempt | ||
| after launching a worker during the same camera boot. Resolve the failure with | ||
| help before deciding whether a power cycle is appropriate. | ||
|
|
||
| For protocol details, build instructions and validation evidence, see the | ||
| [technical report](report.md). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| 01 chmod | ||
| 02 config-changing | ||
| 03 config-mount | ||
| 04 config-path | ||
| 05 config-read | ||
| 06 copy | ||
| 07 destination-appeared | ||
| 08 enabled-path | ||
| 09 final-missing | ||
| 10 fix-inactive | ||
| 11 hid-fingerprint | ||
| 12 identity-file | ||
| 13 incomplete-install | ||
| 14 instructions | ||
| 15 kernel-fingerprint | ||
| 16 managed-link | ||
| 17 missing-hooks | ||
| 18 mkdir | ||
| 19 mode | ||
| 20 mount-topology | ||
| 21 partition-map | ||
| 22 pointer | ||
| 23 pointer-changed | ||
| 24 pointer-format | ||
| 25 pointer-range | ||
| 26 rename | ||
| 27 root | ||
| 28 staged-fix | ||
| 29 staged-runner | ||
| 30 symbols | ||
| 31 sync | ||
| 32 temporary-readback | ||
| 33 unknown-managed-file | ||
| 34 unrelated-hook-type | ||
| 35 starter-type | ||
| 36 starter-stat | ||
| 37 starter-mode | ||
| 38 starter-content | ||
| 39 starter-compare | ||
| 40 erase-hook-type | ||
| 41 erase-hook-stat | ||
| 42 erase-hook-mode | ||
| 43 erase-hook-content | ||
| 44 erase-hook-compare |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| #!/usr/bin/env python3 | ||
| """Build the native tool's embedded installer from canonical hook bytes. | ||
|
|
||
| Python is required only on the development/build machine, never on the printer. | ||
| """ | ||
| import hashlib | ||
| import re | ||
| from pathlib import Path | ||
| import sys | ||
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | ||
| from cc2camera.startup_payloads import RUNNER, erase_hook, KERNEL_MD5 | ||
| from cc2camera.adb_backup import EXPECTED_PARTITIONS | ||
| from cc2camera.restore_prepare import INSTRUCTIONS, SYMBOLS | ||
|
|
||
| ROOT = Path(__file__).resolve().parent | ||
|
|
||
| def generate(): | ||
| fix = erase_hook() | ||
| files = {'fix': fix, 'runner': RUNNER} | ||
| payloads = '\n'.join( | ||
| ' cat > "$STAGE/' + name + '" <<\'CC2_PAYLOAD_END\' || fail payload\n' | ||
| + data.decode('ascii') + 'CC2_PAYLOAD_END' | ||
| for name, data in files.items() | ||
| ) | ||
| checks = '\n'.join( | ||
| f'[ "$(busybox devmem {a:#x} 32)" = "0x{v:08X}" ] || fail instructions' | ||
| for a, v in INSTRUCTIONS.items() | ||
| ) + '\n' + '\n'.join( | ||
| f'[ "$(busybox awk \'$3=="{n}" {{print $1}}\' /proc/kallsyms)" = "{a:08x}" ] || fail symbols' | ||
| for n, a in SYMBOLS.items() | ||
| ) | ||
| reasons = [line.split() for line in (ROOT/'failure-reasons.txt').read_text().splitlines()] | ||
| replacements = { | ||
| '@FAIL_CASES@': '\n'.join(f' {name}) code={code};;' for code,name in reasons), | ||
| '@KERNEL_MD5@': KERNEL_MD5, | ||
| '@HID_MD5@': '8091751fdd4d0d50ea31901663797a86', | ||
| '@MTD@': '\n'.join(f'mtd{i}: {size:08x} 00004000 "{name}"' for i, (name,size) in enumerate(EXPECTED_PARTITIONS)), | ||
| '@PAYLOADS@': payloads, | ||
| '@FIX_MD5@': hashlib.md5(fix).hexdigest(), | ||
| '@RUNNER_MD5@': hashlib.md5(RUNNER).hexdigest(), | ||
| '@LIVE_CHECKS@': checks, | ||
| } | ||
| script = (ROOT/'installer.sh.in').read_text() | ||
| for key,value in replacements.items(): script=script.replace(key,value) | ||
| # Check only this worker and generated live checks, not the embedded hooks. | ||
| worker = (ROOT/'installer.sh.in').read_text() + checks | ||
| used = set(re.findall(r'\bfail ([a-z][a-z-]*)', worker)) | ||
| if used != {name for _,name in reasons}: | ||
| raise ValueError('Worker failure-reasons.txt does not match fail sites') | ||
| if len({code for code,_ in reasons}) != len(reasons) or any(not re.fullmatch(r'[0-9]{2}', code) or code == '00' for code,_ in reasons): | ||
| raise ValueError('Failure codes must be unique two-digit values other than 00') | ||
| return script | ||
|
|
||
| if __name__ == '__main__': | ||
| path = ROOT/'payload/installer.sh' | ||
| data = generate() | ||
| if sys.argv[1:] == ['--check']: | ||
| if path.read_text() != data: raise SystemExit('Embedded installer is stale; run on-printer/generate_payload.py') | ||
| elif not sys.argv[1:]: | ||
| path.write_text(data) | ||
| else: raise SystemExit('Usage: generate_payload.py [--check]') |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Put the power-cycle warning before this identification link. In the linked section, the fallback for an unavailable or unknown stream tells readers to switch the printer off and remove the camera for visual inspection. To use this installer afterward, they must power the camera on again. That is the extra boot which this guide warns can exhaust a nearly full configuration partition and brick the camera. Explain that risk before sending a user with an already-running camera to the physical-inspection fallback, and make the safe stop/decision point explicit.