Car Radio — project map
A custom head unit for a Ford Fusion: a Raspberry Pi drives the factory display (FDIM) and button panel (FCIM) over CAN, and an ADAU1467 DSP over I²C. Generated from the folder contents on 2026-10-26.
ACTIVE current, maintained code EXPERIMENT one-off reverse-engineering tools TEST automated tests CLUTTER stale, duplicate or accidental
car-radio/fusion/, plus deploy/ to put it on the Pi. Everything under code/ is the earlier CAN-cracking work. The protocol knowledge lives in notes-and-knowledge/, FDIM/ and the ccode/cmd/* probes. Several files are leftovers (see the cleanup section).Outer folder: projects/car/
| car-radio/ | The git repo. Almost everything lives here. |
| start_can.sh | Finds a CANable USB adapter (candleLight or slcan firmware) and brings it up as a SocketCAN canN at 125 kbit/s (Ford MS-CAN). Re-runs itself with sudo/run0. It sits outside the repo, so it isn't version-controlled. ACTIVE |
| grommet.scad / .stl / .3mf | OpenSCAD source, the exported mesh and the slicer project for a small printed grommet (a 6 mm post on an 8 mm flange), probably for routing wires. Unrelated to the code. HARDWARE |
| .claude/ | Claude Code local permission settings. |
Repo root: car-radio/
| README.md, LICENSE | A one-line README ("Repo for everything involving… my custom car radio") and the license. |
| decode.py | The original Python (python-can) FCIM button decoder, including send_wake_fcim. It's the first working decoder from the initial commit. The Go code later ported it. LEGACY |
| read-can.txt | A cheat sheet: slcand plus candump commands for sniffing the bus. NOTES |
| write-can.txt | Pasted shell history (line numbers included) of cansend/cangen experiments. One line is a bad paste where two commands ran together. CLUTTER |
fusion/: the main application ACTIVE
This is a Go implementation of the "Fusion Audio UI & Software Specification". It has a pure UI core, and every piece of hardware sits behind an interface. Terminal emulators for the display and the buttons let the whole system run on a laptop. README.md documents how to run it.
| cmd/fusiond/ | The daemon that wires the core to drivers (real CAN/I²C or simulated). console.go is a simulated-hardware REPL with commands like connect Pixel, ring Alice and dsp fail. |
| cmd/fdim/ | A terminal emulator of the 2×20 front display. It listens on :7002. |
| cmd/fcim/ | A terminal emulator of the button panel. Each keystroke is sent to fusiond as a button pulse on :7001. |
| core/ | The UI state machine: pages and menus (pages.go), rendering, text, the clock editor and shared types. script.go runs the .test scenario files. |
| app/ | Dependency injection (app.Deps) and the main loop that ties core and drivers together. |
| fdim/ | The display driver. can.go/canproto.go drive the real FDIM over CAN, net.go drives the emulator, and there's an in-memory version for tests. |
| fcim/ | The button source: the real FCIM over CAN, the emulator over the network, and keymap.go. |
| can/ | The low-level SocketCAN wrapper (can_linux.go). |
| dsp/ | The DSP interface, a simulator, and the real ADAU1467 driver over I²C (i2c_linux.go). |
| bt/ | The Bluetooth module interface. It's simulated only so far. |
| platform/ | Clock and persistent settings store. |
| termui/ | Shared terminal-drawing helpers for the emulators. |
| tests/*.test | Seven scenario scripts written as key X / expect … steps: boot/standby, volume, menus/source, now playing, clock editor, Bluetooth, phone/health. Each one cites a spec section. TEST |
| *_test.go | Go unit tests in core, app, fdim, fcim, can, dsp, platform and fusiond/console. TEST |
| run-all.sh | Opens the three programs in separate terminals or in tmux panes. --build compiles them first. |
deploy/: putting it in the car ACTIVE
| bootstrap.sh | One-time, idempotent setup of the Pi, run from the laptop (deploy/bootstrap.sh main@fusion.local). |
| 99-canable.rules | A udev rule that identifies the CANable adapter. |
| slcan.service | A systemd unit that brings up the slcan CAN interface at boot. |
| fusion.service | A systemd unit that auto-starts fusiond (latest commit: "Make fusiond auto-boot"). |
code/: earlier Go prototypes EXPERIMENT
This folder holds the work done before fusion/ existed, and it's the messiest part of the repo. It has three layers, each a newer copy of the previous one. ccode/ and new/ are untracked in git.
| main.go, display.go, inputs.go, go.mod | The first Go radio prototype (May). It's been superseded: an updated copy lives at ccode/cmd/radio/. STALE |
| new/ | An intermediate snapshot: fdimtext, ISO-TP and layout code with tests, plus Ford FDIM text protocol.md, the most complete write-up of how FDIM text is encoded. layout.go and isotp.go are identical to the copies in ccode/. DUPLICATE (keep the .md) |
| ccode/ | The newest prototype library: isotp.go (multi-frame CAN transport), layout.go (fitting text into 2×20), clock.go, fcim.go, each with a _test.go. TEST |
| ccode/cmd/radio | An updated version of the old radio prototype. |
| ccode/cmd/fcimread | Receive-only sniffer that decodes FCIM button presses. |
| ccode/cmd/fdimtext | Prints the cansend frames for a two-line message without touching the bus. Same purpose as new/main.go. |
| ccode/cmd/fdimtest | Cycles test patterns across the whole 2×20 text area. |
| ccode/cmd/fdimprobe | Steps through experiments on the source box, the volume bar and unmapped icons. |
| ccode/cmd/sweep | A fast blind search for the frames that drive the AM/FM/SYNC/AUX source box. |
| ccode/cmd/backlight | Isolates which frame turns on the FCIM backlight. The answer (the 0x3E8 baseline) went into fusion. |
FDIM/: raw display experiments EXPERIMENT
| send.sh | Replays a cansend script onto a given CAN interface. |
| display-text.py | An early Python generator for display text frames. |
| display-matthew.txt | A captured or hand-written frame sequence that shows a name on the display. |
| maybe-text.txt | A near-copy of the above that's slightly different. It was a guess, as the name says. CLUTTER |
notes-and-knowledge/: research REFERENCE
| fdim.txt | A summary of the FDIM protocol (heartbeat, text) based on p1ne's fdim-controller. |
| keep-wake.txt | Notes on the Ford network-management "ring" that keeps modules awake. |
| wiring.txt | Links to ACM pinouts and wiring diagrams. |
| software-design.md, interface-design.md | Early design docs for the menu and UI that came before the formal spec. |
dsp/: ADAU1467 SigmaStudio project
| Design 1.dspproj | The SigmaStudio project (the audio signal chain). |
| Design 1_IC 1/ | SigmaStudio's compiled export: Program.bin/.dat, the memory images, ParamAddress.dat (register addresses the Go driver needs) and the compiler log. It also contains a second copy of the .dspproj and of bass_remapping.txt. |
| generate_bass_remapping.py | Generates a sigmoid lookup curve for remapping bass levels. The output goes to bass_remapping.txt. |
| Settings/Design 1, Design 3 | Empty folders. CLUTTER |
| System Volume Information/, FOUND.000/ | Windows filesystem debris from when this folder was on a USB stick or SD card. FILE0000.CHK is a chkdsk recovery fragment. These are committed to git by mistake. CLUTTER |
Cleanup suggestions
- Remove from git:
dsp/System Volume Information/,dsp/FOUND.000/, and the emptydsp/Settings/. Add them to a.gitignore(the repo doesn't have one). - Collapse
code/: keepccode/and movenew/Ford FDIM text protocol.mdintonotes-and-knowledge/. Then deletenew/and the top-levelcode/*.go, which are older copies ofccode/. Commitccode/; right now it's untracked. - Move
start_can.shinto the repo (for exampledeploy/ortools/) so it's versioned. - Merge
read-can.txtandwrite-can.txtinto one cleaned-up CAN cheat sheet innotes-and-knowledge/, and deleteFDIM/maybe-text.txt. git statusshows every file underdsp/as modified. That's probably just file-mode or line-ending noise from the FAT copy (trygit diff --statto check). Only one.dspprojorbass_remapping.txtcopy needs tracking.- Expand the root README to point at
fusion/README.md.