A browser-based toolkit (TypeScript, WebUSB, no OpenOCD, no native driver, no backend) for working with the RF Unit's Nuvoton ISD9160 audio codec on Xbox One and Xbox Series consoles. Everything runs from a Raspberry Pi Pico (or Pico 2) adapter, driven directly from Chrome or Edge.
It covers the full workflow:
- Guided, console-specific wiring and soldering instructions.
- Initial flashing of a blank ISD9160 over SWD.
- Flashing the RF Unit's ISD9160 over I2C, for boards where the chip is already fitted (Special Edition consoles, or after a DIY solder mod).
- Switching the Pico adapter's own firmware between its two roles (SWD probe and I2C adapter) without unplugging or reflashing by hand.
- Editing the custom sound firmware: extract, preview, and replace individual audio segments, then build a patched image ready to flash back.
Live version: https://xboxoneresearch.github.io/xbox-one-sonus/
The app is a step-by-step wizard:
- Choose console - pick your Xbox model. If your chip isn't already fitted from the factory, you'll be asked whether it's a Special Edition (chip pre-installed) or a regular console (needs the DIY solder mod).
- Console guide - wiring diagrams, pin mappings, and (for the DIY path) a parts list and soldering photos, specific to your console.
- Initial SWD flash - for a blank, never-programmed chip. Connects to the Pico over WebUSB while it runs CMSIS-DAP probe firmware, halts the chip over SWD, and erases/programs/verifies it directly.
- Switch Pico firmware - flips the Pico between its two roles (SWD probe or I2C adapter) by putting it in bootloader mode and reflashing it over WebUSB, no manual drag-and-drop required.
- I2C flash - for a chip that already has firmware (Special Edition, or after step 3). Talks to the RF Unit's own I2C bootloader through the Pico running the I2C-adapter firmware: play test sounds, dump the current firmware, or write a new one.
- Custom sound editor - load a firmware dump, browse and preview its audio segments in the browser, swap one out for your own WAV file, and download a patched firmware image to flash back in step 5.
Only one physical Pico is needed. It plays two different roles at different points in the wizard (SWD probe or I2C adapter), and the tool identifies which role it's currently in by its USB VID/PID.
- A Raspberry Pi Pico or Pico 2, used as the SWD probe / I2C adapter. Prebuilt firmware for both roles and both boards is bundled with the app.
- Chrome or Edge (WebUSB support is required; Firefox and Safari will not work).
- Wiring per the console-specific guide shown in the app. Consoles that need a direct motherboard (FACET) connection have extra safety requirements called out in that guide.
- Linux only: a udev rule granting your user access to the Pico's USB
identities, otherwise connecting fails with "Failed to execute 'open' on
'USBDevice': Access denied." See
firmware/i2c-adapter/udev/README.md.
pnpm install
pnpm devOpen the printed http://localhost:5173 URL and follow the wizard.
A production build is also deployed automatically to GitHub Pages from
main; most users can just use the live version above instead of running
this locally.
pnpm typecheck # tsc --noEmit
pnpm test # vitest
pnpm build # typecheck + production buildsrc/ui/- the wizard shell and its steps (src/ui/steps/*.ts), one file per step described above.src/app/session.ts- the SWD debug session (WebUSB CMSIS-DAP transport viadapjs, ADIv5, halting the Cortex-M0 core).src/numicro/- the NuMicro ISP register sequencing used to erase/program/read the ISD9160 over SWD.src/i2c/- the I2C session and the RF Unit's I2C bootloader protocol, ported from thevendor/DuRFUnitI2Csubmodule and cross-checked against its Python test vectors.src/picoboot/- the PICOBOOT protocol used to reflash the Pico's own firmware (its two roles) while it's in USB bootloader mode. This never touches the ISD9160, only the Pico's own flash.src/vpe/- the TS side of the sound editor's Pyodide integration (loading Pyodide, marshaling calls/files across the JS/Python boundary).python/-vpe_pyodide_bridge.py, the Python side of that integration: thin glue this repo owns, calling the vendoredvpe.pycodec library's classes directly rather than re-deriving codec logic in TypeScript. Tested withpytest(python/tests/) againstvpe.py's own synthetic-firmware fixture from the submodule.firmware/i2c-adapter/- source for the custom Pico firmware that bridges USB to the RF Unit's I2C bus. Seefirmware/i2c-adapter/BUILD.mdto rebuild it.public/firmware/- prebuilt firmware binaries for both Pico roles and both board revisions (RP2040 / RP2350), catalogued with hashes inmanifest.json. Seepublic/firmware/README.mdto update them.vendor/DuRFUnitI2C- git submodule with the underlying hardware research, wiring documentation, and the originalvpe.pysound tooling this project is built on.
Unit tests sit next to the code they cover (*.test.ts) and run entirely
against in-memory fakes, no hardware required: NuMicro ISP register
sequencing, I2C protocol golden vectors, SWD session error paths, PICOBOOT
connection/target/uf2 handling, and the VPE bridge.
The WebUSB transport itself (SWD and I2C alike) can only be exercised
against real hardware. scripts/hw-debug-*.mjs are standalone harnesses
that reuse the same session code as the app but run under Node (via the
usb package's WebUSB polyfill) against a real Pico, useful for
reproducing hardware issues outside the browser. Run one with:
pnpm exec vite-node scripts/hw-debug-<name>.mjsThis repo has a git submodule (vendor/DuRFUnitI2C) that must be checked
out (git submodule update --init) before pnpm install/pnpm dev for
the sound editor to work — it supplies vpe.py, the shared Siren/DPCM codec
library (also used by DuRFUnitI2C's own CLI/GUI tools, which is why it stays
vendored rather than copied in here). pnpm dev and pnpm build both run
scripts/sync-vpe-python.mjs first, which copies vpe.py from the
submodule and this repo's own python/vpe_pyodide_bridge.py into
public/py/ (gitignored, regenerated on every run) so Vite can serve them
as static assets for the browser to fetch into Pyodide.
To run python/'s own test suite, use any Python environment with
vendor/DuRFUnitI2C/pyproject.toml's dependencies installed (numpy, scipy,
fastcrc, pytest — the submodule's own uv sync sets one up at
vendor/DuRFUnitI2C/.venv), then from this repo's root:
vendor/DuRFUnitI2C/.venv/bin/python -m pytestThis repo's root pyproject.toml points pytest at python/tests/ with
vpe.py/test_vpe.py on the path via the submodule, so no dependency
duplication or code copying is needed to test the bridge against the real
codec library.
Full attribution for the hardware research, firmware, and third-party libraries this project builds on is in the in-app credits page, also linked from the app itself. Base hardware/firmware research: xboxoneresearch/DuRFUnitI2C.
🤖 Large parts of this toolkit (code, tests, and docs) were generated with Claude Code (Anthropic's Claude), with human review and testing against real hardware.