Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

ToneX librarian: decode the capture-upload path (undecoded by anyone, invariant 0 gated)

Open
#27 10 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
20/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Quiet
Tech stack
python
Domain
embedded-iot

Research direction

Start with tools/tonex_decode.py and the 128 captured frames: implement unstuffing and CRC-CCITT validation, then verify every frame before considering transmission. Next, read the cited community project's protocol.md and implement the documented state request, checking the pedal's reply. Observe uploads passively with Wireshark and document the frame grammar, recovery path, and verified allowlist; done means all listed checks pass before any guarded replay.

Written by the indexing model from the issue text.

Description

Decode the ToneX librarian protocol, the operation that moves a capture onto the pedal. Split from #23, which covers what we can already read.

Why this is not a port

Unlike the planner backends, there is no working implementation to bring across. The community RE (vit3k/tonex_controller, built on by Builty/TonexOneController) covers the read and control surface well, and its protocol.md states plainly that preset writing/uploading and capture functionality "was not yet analyzed". So this is original work on the one operation nobody has cracked.

Worth reading that project's own warning first: a version of it "has an issue with USB that can overwrite the pedal's global settings". That is the failure mode this issue exists to avoid, on hardware that costs real money and that its owner gigs.

What is already known

From prior art, and independently confirmed against our own 128 captured frames:

  • HDLC async framing, 0x7e flags opening and closing.
  • Byte stuffing: 0x7d escapes, next byte XOR 0x20. Present in 36 of our 128 captures.
  • CRC-CCITT over the payload, and the CRC is itself stuffed.
  • Tagged objects: 0xb9/0xba/0xbc collections, 0x80/0x81/0x82 two-byte little-endian numerics, 0x88 float32 little-endian.
  • Decoded operations: hello/handshake with firmware version, state request, state-change notification, active slot switching, preset reassignment, individual preset retrieval.

Undecoded, and the point of this issue: writing a preset or a capture to the pedal.

Method, in order, and the order is the safety property

1. Fix our reader first (offline, no hardware). tools/tonex_decode.py ignores byte stuffing entirely and treats 0x80/0x81/0x82 as single structural bytes. Both are wrong. Implement unstuffing and CRC-CCITT validation, then re-run against the 128 captures: a frame whose CRC validates is a frame we have genuinely parsed, which is the check we have been missing. Nothing else in this issue should start before the reader is trustworthy.

2. Implement the state request (small, bounded write). This is documented prior art, not a guess, and it is the first thing we would ever transmit on that port. It also settles the pollability question honestly, which we have now been wrong about in both directions. Treat it as the pilot for the write path: one documented frame, verified by the reply, with the pedal's own state as the check.

3. Passive capture of a real upload (read-only from our side). Wireshark USB capture while the TONEX Editor loads a capture into a slot the owner nominates. We send nothing. This is the technique the community project documents and it is where the actual decode happens. Expect to repeat it: same capture into different slots, different captures into the same slot, so slot addressing and payload separate out.

4. Only then, replay. And not before there is a written recovery path.

Invariant 0 applies without exception

Nothing reaches that serial port until the operation is decoded and a documented recovery path exists. That is the same bar SENDABLE_FNS holds the FM9 to, and fm9/safety.py now carries a deny-by-default SendGuard precisely so a second device inherits it rather than reimplementing it. A ToneX writer gets a message_type_guard-style allowlist covering only frames we have decoded and verified.

Two things that make this device harder than the FM9 and should be stated rather than discovered:

  • The serial channel is the one firmware travels over. On the FM9 we could separate function ids by scope; here we cannot yet tell a librarian frame from a firmware frame by inspection, and until we can, that is an argument for keeping the allowlist empty.
  • The TONEX Editor holds the port exclusively (Errno 16, lsof names it). Any capture session has to run alongside the editor at the USB layer rather than the serial layer, because we cannot open the port while it works.

Definition of done

  • Reader unstuffs and validates CRC-CCITT; all 128 existing captures verify.
  • State request implemented and answered by the pedal.
  • A capture upload observed end to end, with slot addressing and payload distinguished across repeated runs.
  • Frame grammar for the write path documented in the ledger, with undecoded regions named rather than glossed.
  • Recovery path written down and, ideally, exercised.
  • Only then: a guarded writer, allowlisted to decoded frames.

Refs #17, #23. Hardware-gated, and gated further on the owner's explicit go-ahead before any frame is transmitted.

Dominant language
Python
Stars
7
Forks
3
Avg merge
2h 17m
Merged PRs (30d)
49

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from monzta1/ToneCommand

All issues in monzta1/ToneCommand

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.