Update PLAN.md and README.md current status: host to controller TX
(rumble) is implemented and pending hardware confirmation; the dongle
LED is driven at chip level, so no data path LED work remains.
Co-Authored-By: qwen3.8-27b@q3_k_xl: updated status docs
Port the rumble packet from upstream driver/gamepad.c: a 9-byte
GIP_CMD_RUMBLE payload (motors R|L|RT|LT, intensities scaled to the
0..100 GIP range, duration/repeat constants). xone_controller_rumble
now sends it via client::send_rumble; the app button pulses both
motors for 0.6s then stops them. Completes the host to controller
TX remainder of Phase 3 (the dongle LED is already driven at chip
level for pairing and client lifecycle).
Co-Authored-By: qwen3.8-27b@q3_k_xl: implemented rumble TX
Plumb controller battery type/level from the GIP status packets
through the C API into the card header (SF Symbol battery icon).
Add a per-controller Rumble button wired to a new
xone_controller_rumble() entry point; it validates its arguments
and returns -ENOSYS until host to controller TX is implemented.
Co-Authored-By: qwen3.8-27b@q3_k_xl: battery + rumble button UI
Render a clear gap instead of the plain center cell so the D-pad
reads as an open cross.
Co-Authored-By: qwen3.8-27b@q3_k_xl: removed the D-pad center cell
Give both clusters a shared 100x100 footprint so they align on the
same grid: D-pad cells are now square (30x30 with 5pt gaps) and the
ABXY diamond is positioned on its diagonals instead of stacked rows.
Drops the height-matching frame hack from the card layout.
Co-Authored-By: qwen3.8-27b@q3_k_xl: squared and aligned the clusters
Group each stick above its cluster (L over D-pad, R over face
buttons) in equal-height columns so the rows line up, cap the face
at a natural controller proportion so wide cards do not stretch it,
and replace the Select/Start chips with small round icon buttons
flanking the centered Guide button.
Co-Authored-By: qwen3.8-27b@q3_k_xl: compacted and aligned the face
Realign the card to the physical controller face: trigger bars and
bumper chips in the top corners, sticks side by side in the upper
center (stick clicks light up their rings instead of separate chips),
D-pad lower left, face buttons lower right, and the Guide button
centered between the clusters flanked by Select and Start.
Co-Authored-By: qwen3.8-27b@q3_k_xl: realigned card to Xbox layout
Split the single-file Swift app into model, store, and view files
and rework the layout. The dongle card shows a status pill with an
adaptive info grid; controllers render as cards in an adaptive grid
that fills wider windows; each card uses a gamepad-style
visualization (D-pad, face buttons, stick pads, triggers) instead of
flat indicator rows. The window is now resizable and content reflows
instead of staying a fixed 420pt column.
Co-Authored-By: qwen3.8-27b@q3_k_xl: redesigned app UI and structure
Rename all trailing-underscore private data members to the m_ prefix
required by AGENTS.md, across the auth, crypto, gip, mt76, and usb
transport classes plus the app session classes. Pure rename; no
behavior change. Full build and test suite pass.
Co-Authored-By: qwen3.8-27b@q3_k_xl: renamed members to m_ prefix
Convert the remaining west-const declarations in xone_api.h to east
const so the whole file matches the controller functions added later.
Update the AGENTS.md C bridge section: east const applies to the C
header too; only trailing returns are exempt.
Co-Authored-By: qwen3.8-27b@q3_k_xl: converted C API header to east const
Replace em dashes with colons throughout, wrap prose and list lines at
80 columns (Goal, Phase 4 options, Known Challenges), refresh the
current status section now that pairing and the RX data path are done,
and add src/cli to the directory layout. Table alignment was also
normalized as a side effect of the file rewrite.
Co-Authored-By: qwen3.8-27b@q3_k_xl: reformatted PLAN.md per style guide
Check off investigation items resolved on hardware (firmware load,
EFUSE, radio init, beacon, pairing, reconnect), align build commands
with AGENTS.md, add xone_cli and scripts to the layout, replace the
completed first-steps list with a current status section, and drop
em dashes per the documentation conventions.
Co-Authored-By: qwen3.8-27b@q3_k_xl: updated README with current status
Display the standard GIP Menu and View bits in the controller input monitor
alongside the existing Guide and face-button indicators.
Co-Authored-By: openai/gpt-5.6-luna: added menu button indicators
Use direct-width SwiftUI shape bars instead of native ProgressView controls
so increasing stick and trigger values update without delayed fill motion.
Co-Authored-By: openai/gpt-5.6-luna: replaced animated analog indicators
Render stick and trigger progress values without implicit SwiftUI animation
so rapid controller reports are not displayed as delayed movement.
Co-Authored-By: openai/gpt-5.6-luna: removed analog display smoothing
Poll the controller snapshot every 20 ms instead of every 100 ms so stick
and trigger movement reaches the monitor UI with less visible latency.
Co-Authored-By: openai/gpt-5.6-luna: reduced input monitor polling latency
Send GIP_PWR_ON when a controller is identified, matching the upstream
gamepad probe before authentication and input initialization.
Co-Authored-By: openai/gpt-5.6-luna: matched controller power-up flow
Defer RSA, ECDH, and handshake completion until after each received packet
has been added to the authentication transcript, matching the upstream
workqueue ordering and preventing the controller from rejecting host secret.
Co-Authored-By: openai/gpt-5.6-luna: fixed GIP authentication ordering
Log incoming and outgoing authentication context, command, option, and
length fields to isolate the handshake failure before input reports begin.
Co-Authored-By: openai/gpt-5.6-luna: added authentication diagnostics
Route paired controller QoS data through the existing GIP protocol layer and
expose the latest gamepad report through the C API. Add a SwiftUI monitor for
buttons, d-pad, triggers, and stick positions without registering a native HID
device.
Co-Authored-By: openai/gpt-5.6-luna: GIP bridge and live input monitor
Match the upstream 802.11 management layouts for association responses,
pair responses, and reserved client commands by including the sequence
control and association capability fields. Reuse existing WCIDs for repeated
association requests and end pairing mode after a successful pair response.
Also restore the upstream radio calibration sequence needed for reliable
WLAN associations.
Co-Authored-By: openai/gpt-5.6-luna: fixed pairing frame layouts and lifecycle
Use the common xow_dongle.bin image from the upstream driver for the
GUI session instead of selecting the older 02E6-specific image. Update
the firmware download script and plan to document the same upstream flow.
Keep the extended RX diagnostics used to inspect controller discovery.
Co-Authored-By: openai/gpt-5.6-luna: traced firmware and pairing behavior
The dongle beacon carries a pairing flag in the Microsoft OUI IE; with
it clear, controllers ignore the beacon. Port xone_dongle_toggle_pairing:
xone_set_pairing() rewrites the beacon with the flag set and blinks the
LED, the GUI button triggers it, EVT_BUTTON (dongle button) does too, and
the LED follows upstream state (blink while pairing, on when a controller
is connected, off otherwise). The CLI gains a pair command.
Log every inbound frame (info word + first 16 bytes) so the RX path can
be traced against hardware.
Co-Authored-By: qwen3.8-27b@q2_k_xl: pairing mode and RX logging
Port the MT76 client functions (send_wlan, associate_client,
pair_client, set_client_key, remove_client) and wire the RX dispatch
into the session: EP IN frames are parsed, ASSOC_REQ associates a
controller (WCID plus chip programming), PAIR_REQ replies with
PAIR_RESP, and DISASSOC or client-lost removes it. The C API exposes
connected controllers and the app lists them by MAC. Bumps
xone_cli/xone_app to C++23: they were falling back to the default
standard once mt76.hpp started using std::span. Adds a unit test pinning
the WCID regions, the 32-byte rxwi, and the new frame control values.
Co-Authored-By: qwen3.8-27b@q2_k_xl: client functions, RX dispatch, GUI list
Split the dongle session into a fast probe (xone_open) and a background
start (xone_start) that loads the firmware and initializes the radio on
a worker thread, so the app UI never blocks. Add xone_state/xone_error
for progress display, and select the firmware image per product ID when
no path is given. The Swift app polls the state each second and shows
idle/starting/ready/error plus the firmware build or error string.
The session destructor joins the worker so quitting the app does not
terminate on a joinable thread. Note in the CLI and transport that the
recover/re-enumerate path should not be used yet: a crashed SIE drops
off the bus, while the MCU watchdog recovers it after ~90s of quiet.
Co-Authored-By: qwen3.8-27b@q2_k_xl: async C API, Swift state display, and exit-time worker join
Complete the radio bring-up sequence: init_registers now writes the
upstream register values (PBF out of reset, beacon TX off), crystal
calibration, MAC/BSSID programming, channel evaluation, and beacon
programming through an MCU burst into PBF shared memory. The beacon
txwi is the full 20-byte struct and the RF patch is applied on the
cold firmware path.
Download firmware per product (xone_dongle_02e6.bin / 02fe.bin) and
add the xone_cli debug tool (info, firmware, radio-init/deinit, burst,
reg-read/write, led, recover). Recover uses USBDeviceReEnumerate for a
host-side port reset.
Co-Authored-By: grok4.6: internet search (firmware split, beacon SRAM, upstream issues)
Co-Authored-By: qwen3.8-27b@q2_k_xl: initial radio init and CLI implementation
Co-Authored-By: deepseek/deepseek-v4-pro-0813: final radio init fixes and verification
Add an opaque xone_dongle session handle to the C ABI bridge:
xone_open() probes, resets, and loads the firmware (path optional),
and xone_pid/xone_chip_id/xone_mac_address/xone_firmware_build return
debug info for the open session. chip captures the firmware build
string from the image header during load.
The Swift app opens a session when the dongle appears and shows PID,
chip ID, MAC address, and firmware build string in a debug section.
Co-Authored-By: qwen3.8-27b@q2_k_xl: added C API session handle and debug UI
Add chip::load_firmware(): validates the xow_dongle.bin header, DMAs
the ILM and DLM images in 0x3800-byte chunks over EP 0x04 OUT with
FCE completion polling, then loads the IVB and waits for the firmware
to start. Probe now issues a USB reset first (port of
usb_reset_device), matching xone_dongle_probe.
The chip keeps its firmware across a USB reset on macOS and does not
set the upstream reset-complete bit, so load_firmware falls back to
the running firmware when the chip is still alive. Verified on
hardware: fresh load and re-plug both return success.
Add scripts/download-firmware.sh (port of install/firmware.sh), which
fetches the driver CAB from Windows Update and extracts
firmware/xow_dongle.bin, hash-verified.
Co-Authored-By: qwen3.8-27b@q2_k_xl: ported firmware load and download script
Add the mt76::chip class on top of the USB transport: 32-bit register
read/write via vendor requests, register polling, and EFUSE reads with
the kick/control sequence from transport/mt76.c. Expose chip_id() and
mac_address() (with the 62:45:bd fallback).
Verified on hardware: chip ID 0x7612 (MT7612) and MAC address read
from EFUSE.
Co-Authored-By: qwen3.8-27b@q2_k_xl: ported register and EFUSE layer
Discovery, interface claiming, and vendor control requests are confirmed
working on a physical dongle (PID 0x02E6, MT7612 chip). Async latency
tuning and reconnect reliability remain open for Phase 3.
Co-Authored-By: qwen3.8-27b@q2_k_xl: verified transport on hardware
IOServiceMatching on idVendor/idProduct numbers is unreliable (single-key
matches fail), so match the IOUSBDevice class and filter VID/PID in user
space via the idVendor/idProduct properties.
QI'd interfaces are double-pointer references: *ref is the interface
struct and methods are called as (*ref)->Method(ref, ...). The old code
treated the slot as the struct and crashed on the first method call.
Verified on a physical dongle (PID 0x02E6): probe opens the device,
enumerates EP 0x04 IN/OUT and EP 0x05 IN, and register reads via
DeviceRequest return valid values (MT7612 ASIC version).
Co-Authored-By: qwen3.8-27b@q2_k_xl: fixed USB transport for hardware
Replace the stub probe with a real IOKit/IOUSBFamily transport:
discovery by VID/PID, device and interface connections, vendor
control requests on EP0, bulk writes to EP 0x04 OUT, and an async
read pump (EP 0x05 IN / EP 0x04 IN) on a dedicated CFRunLoop
thread with disconnect notification.
Add the test_usb suite, link IOKit/CoreFoundation into xone_usb,
and update the README investigation checklist.
Co-Authored-By: qwen3.8-27b@q2_k_xl: implemented USB transport layer
Replace the command-line entry point with a windowed SwiftUI app
showing live dongle status, a controller placeholder, and a pair button.
The app runs as a regular foreground app even when launched directly
from the build directory.
Co-Authored-By: deepseek (deepseek/deepseek-v4-pro-0813): built SwiftUI app shell
Port the GIP protocol and authentication layers from medusalix/xone
into the C++ stack:
- crypto: SHA-256/HMAC (CommonCrypto), RSA PKCS#1 (Security.framework),
and a self-contained P-256 ECDH validated against OpenSSL vectors
- auth: v1 (RSA) and v2 (ECDH) handshake state machine
- gip: header/varint/chunk handling and packet dispatch, with the kernel
device model replaced by transport + client_listener interfaces
Adds test_crypto, test_auth, and test_gip suites.
Co-Authored-By: deepseek (deepseek/deepseek-v4-pro-0813): ported crypto, auth, and GIP
Adapt the refix AGENTS.md to this project: build commands, module
layout, C++/Swift/C-bridge style rules, and commit guidelines. C++
headers use .hpp and C headers use .h; the PLAN.md port table is
updated to match.
Co-Authored-By: qwen (qwen/qwen3.8-27b@q2_k_xl): wrote coding conventions
Add the CMake build for the Swift + C++ macOS port, mirroring the
refix layout: deps/ modules (Platform, Flags, Sanitizers, FindUnity),
per-module static libraries (usb, auth, mt76, gip, hid, api), a Swift
app entry point with a pure C bridge header, and a Unity test suite
behind BUILD_TESTING.
Swift requires the Ninja or Xcode generator; a guard in
CMakeLists.txt rejects anything else.
Co-Authored-By: qwen (qwen/qwen3.8-27b@q2_k_xl): scaffolded CMake build + tests