16-entry source→target table in its own flash sector (-3, magic DS5\x03),
identity default, 0xFF = disabled. Applied to the OUTGOING host report copy
only — raw interrupt_in_data (OLED screens + PS+Mute reboot combo) stays
physical. Edited via the existing 0xF6/0xF7 vendor reports with a hardened
RM+version frame (no HID-descriptor change, so Windows enumeration is
unaffected) plus a revision counter the host polls to confirm a write.
Apply logic + button set ported from SundayMoments/DS5_Bridge (credit).
scripts/remap_test.py exercises the path over /dev/hidraw without the web
tool. Verified on hardware: swap applied, read back, survived reboot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends the firmware's 0xFD vendor feature report from 32 to 44 bytes
to carry the three host -> dongle -> BT trigger counters added in
5da1be4 (host_out02_total / host_out02_trig_allow / host_out02_to_bt).
mic_diag.sh's bt-trace decoder reads them and prints a one-line
verdict so the user can triage issue #3 in one terminal command
instead of switching to the OLED Diagnostics screen mid-game.
Verdicts encoded:
host02 > 0, trig == 0 -> host driver never sets the trigger
Allow bits; not a firmware problem.
trig > 0, tx < trig -> trigger Allow bits arrive but the
speaker-active gate in main.cpp
swallowed them.
full chain populated -> dongle delivered, controller didn't
actuate; Sony BT-side limit.
The 0xFD report ID stays undeclared in the HID descriptor — Linux
hidraw ioctls don't enforce that and WebHID never sees these reports
(config goes through 0xF6). bt-trace's IOCTL_SIZE bumped to 45
(1 byte for the kernel-prepended report ID + 44 bytes payload).
Docs:
README.md - new "Diagnostics & debug tooling" section walks
through the four mic_diag.sh subcommands; previously
the script was only mentioned inside
BLUETOOTH_AUDIO_NOTES.md.
README.md - Diagnostics-screen description updated for the
scrolling row-list + cross-link to bt-trace.
CLAUDE.md - "Where features live" gets a host-side-diagnostics
entry explaining how to extend the 0xFD payload and
wire it into bt-trace's decoder.
CHANGELOG - records both the firmware extension and the README
discoverability fix.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bt-trace was reading kernel-prepended 0xFD as the low byte of bt_31
counter (and shifting all subsequent fields by 1), producing
nonsensical rates like 200000/s and frame lengths of 20224 bytes.
Slicing buf[1:] before decoding gives the firmware-supplied payload
bytes aligned to the documented 0xFD layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In-progress work on DualSense microphone capture over BT. Mic-add tap
itself is disabled (was decoding standard input bytes as Opus and
producing INT16_MIN garbage on the USB IN endpoint) but everything
around it is wired and ready to re-enable once we identify the actual
mic transport.
Firmware:
- src/audio.cpp: Opus decoder on core0, mic_fifo queue, audio_loop
mic-in path with decode + mono->stereo + tud_audio_write. Decoder
init in audio_init() (creates 48kHz mono OpusDecoder).
- src/audio.h: exports mic_add_queue() + per-frame diagnostic
accessors (audio_mic_frames, last_decoded, last_want, last_wrote,
last_toc).
- src/main.cpp on_bt_data(): BT-side instrumentation — counts every
INTERRUPT input report, tracks min/max length, OR mask of byte[2],
most recent non-0x31 report ID, hex prefix of last 0x31/other/any
frame, full content of the longest 0x31 frame seen. Mic-tap call
itself stubbed behind `if (false)` pending the real detector.
- src/state_mgr.cpp: state_init_data byte 6 (VolumeMic) 0xFF→0x40
(was out of range), byte 9 (MuteControl) 0x0F→0x00 (clear all
PowerSave bits — AudioPowerSave was muting DSP).
- src/cmd.cpp: two new vendor feature reports — 0xFD returns 32-byte
diagnostic state (counters + prefixes), 0xFE returns the longest
0x31 frame in full (up to 80 bytes). Both queryable via
/dev/hidraw on Linux from the host script.
- src/oled.cpp: Diagnostics screen shows TOC + decode result + USB
wrote/want bytes for live BT-side visibility.
Host-side:
- scripts/mic_diag.sh: subcommands `status`, `capture [secs]`,
`watch`, `bt-trace`. The bt-trace subcommand reads the 0xFD
feature report via hidraw ioctl, decodes counters + recent
prefixes, computes per-second rates. Drastically cuts iteration
time — no OLED relay or per-test flash cycle needed.
Findings to date:
- Upstream/mic's mic-flag bit ((data[2] >> 1) & 1) does NOT match
this DS5 firmware; bit 1 of byte[2] is NEVER set. Bit 0 is the
standard input report type indicator, not a mic tag — confirmed
by stick-bytes appearing as our supposed "Opus prefix".
- DS5 sends both report ID 0x01 and 0x31 over BT; the longest frame
is a standard 79-byte 0x31 input report with sticks/IMU/touchpad
but no audio bytes appended.
- Conclusion in progress: the DS5 firmware on this controller is
not currently streaming mic over BT at all, even with
AllowAudioControl=1, VolumeMic=0x40, AudioPowerSave=0,
MicMute=0. Next investigation step: compare against a USB-mode
DS5 to see what a real mic stream looks like at the UAC1 layer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build-system, config, usb, and CI wiring on top of upstream's
v0.6.0-hotfix tree. Build will still fail until Phase C+D land bt.h
accessors that oled.cpp references; that's expected mid-rebase.
CMakeLists.txt: add src/oled.cpp + src/slots.cpp to add_executable,
link hardware_spi, restore OUTPUT_NAME ds5-bridge-oled.
src/config.h: append the 4 OLED Edition Config_body fields
(current_slot + auto_haptics_enable/gain/lowpass). Preserves
upstream's field order for the first 8 fields.
src/config.cpp:
- speaker_volume validity default -100 dB → 0 dB (footgun fix)
- 4 new validity guards for the appended fields with sensible
defaults (Fallback / 100 % / 160 Hz / slot 0)
- config_default() impl (was declared in upstream's config.h since
v0.5.4 but never defined; the OLED Edition's "Reset to defaults"
Settings item calls it)
src/usb.cpp: drop the UAC1 SET_CUR Volume → flash-config sync that
let PipeWire/Pulse silently override the user's saved Spk Vol on
every device reconnect. Borrowed from loteran/DS5Dongle commit
03fa1e4.
src/usb_descriptors.cpp: restore iSerialNumber = STRID_SERIAL.
Upstream's commit e79c762 zeroed it to work around SpecialK (#32),
but that broke Windows device identity (#100) — users lost
per-device volume / app preferences when moving USB ports. The
OLED Edition prioritizes Windows device-identity stability for
the broader user base over SpecialK compat for a narrower one.
.github/workflows/{build,release}.yml: artifact filenames use
ds5-bridge-oled.uf2 (and -debug / -picow variants) per the
OUTPUT_NAME rebrand.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>