feat: pair controllers and show them in the app
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
This commit is contained in:
@@ -35,6 +35,24 @@ User-space macOS app that speaks to the Xbox Wireless Dongle (MT76xx chip) and e
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Current Status
|
||||
|
||||
- Phase 1 (GIP + auth): ported and unit-tested.
|
||||
- Phase 2 (USB transport): probe/open, async read pump, vendor requests,
|
||||
bulk write. Verified on hardware.
|
||||
- Phase 3 (MT76 chip): register/EFUSE access, firmware load (per-PID images),
|
||||
radio init (registers, crystal, MAC/BSSID, channel eval, beacon). Verified
|
||||
end-to-end: `radio-init` completes, beacon TX enabled, FCE shows firmware
|
||||
running.
|
||||
- C API + Swift app: async session (fast probe; firmware + radio on a worker
|
||||
thread), state display (idle/starting/ready/error).
|
||||
|
||||
Remaining for Phase 3: controller association and the data path (design below).
|
||||
Then Phase 4 (HID) and Phase 5 (app polish).
|
||||
|
||||
**Immediate goal:** pair a controller and show it in the GUI. Exposing it as
|
||||
a macOS HID device is deferred.
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
@@ -156,6 +174,82 @@ Extract the protocol logic from Linux kernel code into standalone C.
|
||||
- Menubar icon for status
|
||||
- Firmware download helper (script or in-app)
|
||||
|
||||
## Controller Association Design
|
||||
|
||||
Ported from `transport/dongle.c` and `transport/mt76.c`. Goal: pair a
|
||||
controller and show it in the GUI. Exposing it as a macOS HID device is
|
||||
deferred.
|
||||
|
||||
### RX Path
|
||||
|
||||
Both EP IN endpoints (0x04 WLAN, 0x05 CMD) feed one handler:
|
||||
|
||||
1. `process_buffer`: take the raw IN buffer.
|
||||
2. `process_message`: parse the u32 info header; read D_PORT. Ignore command
|
||||
responses (CMD_SEQ == 0x01). Strip header + 4-byte trailer.
|
||||
- D_PORT == WLAN: go to step 3.
|
||||
- D_PORT == CPU_RX: dispatch by EVT_TYPE:
|
||||
- BUTTON (0x04): enter pairing mode.
|
||||
- PACKET_RX (0x0c): go to step 3 (payload is a WLAN frame).
|
||||
- CLIENT_LOST (0x0e): payload[0] = wcid; remove that client.
|
||||
3. `process_wlan`: parse rxwi (16 bytes); if RXINFO_L2PAD set, skip the
|
||||
2-byte pad after the 802.11 header; trim to MPDU_LEN from rxwi.ctl.
|
||||
4. `process_frame`: dispatch by frame_control:
|
||||
- DATA|QOS_DATA: feed the client's GIP adapter (`gip_process_buffer`).
|
||||
- MGMT|ASSOC_REQ: add a client (addr2 = controller MAC).
|
||||
- MGMT|DISASSOC: remove client (wcid from rxwi.ctl).
|
||||
- MGMT|0x70 (WLAN_RESERVED): client command; payload[1] is PAIR_REQ (0x01)
|
||||
or ENABLE_ENCRYPTION (0x10).
|
||||
|
||||
### Client Lifecycle
|
||||
|
||||
- create_client: find a free WCID (1..16); create a GIP adapter for it.
|
||||
- associate_client(wcid, mac): `write_burst(WCID_ADDR, mac)`; ms_command(
|
||||
ADD_CLIENT, {wcid-1,0,0,0,0x40,0x1f,0,0}); send an ASSOC_RESP mgmt frame via
|
||||
`send_wlan` (fc = MGMT|ASSOC_RESP, da/sa/bssid, status_code = 0x0110,
|
||||
aid = 0x0f00).
|
||||
- pair_client(mac): send a PAIR_RESP mgmt frame via `send_wlan`
|
||||
(fc = MGMT|0x70, reserved + PAIR_RESP byte + 9-byte payload).
|
||||
- remove_client(wcid): ms_command(REMOVE_CLIENT, {wcid-1,0,0,0}); zero the
|
||||
WCID ADDR/IV/ATTR regions.
|
||||
- LED: on when a client is added outside pairing mode; off when the last
|
||||
client leaves.
|
||||
|
||||
### Architecture
|
||||
|
||||
One GIP adapter per controller, keyed by the chip's WCID (matches upstream).
|
||||
The rxwi.wcid identifies which controller a frame belongs to; within each
|
||||
adapter the GIP client ID is 0. Our ported `get_client` auto-creates a client
|
||||
on first packet, so a fresh adapter yields its single client on demand.
|
||||
(Verify the GIP header client ID on hardware.)
|
||||
|
||||
### Constants To Add (mt76_defs.hpp)
|
||||
|
||||
- WCID regions: ADDR base 0x1800 (+n*8), KEY base 0x8000 (+n*32, len 16),
|
||||
IV base 0xa000 (+n*8), ATTR base 0xa800 (+n*4); ATTR pairwise bit 0,
|
||||
pkey mode genmask(3,1) = AES_CCMP (4).
|
||||
- TXD info: DPORT genmask(29,27), QSEL genmask(26,25) EDCA=2, WIV bit 24,
|
||||
80211 bit 19.
|
||||
- RX FCE info: CMD_SEQ genmask(19,16), EVT_TYPE genmask(23,20), D_PORT
|
||||
genmask(29,27).
|
||||
- rxwi: RXINFO_L2PAD bit 14; CTL_WCID genmask(7,0); CTL_MPDU_LEN genmask(29,16).
|
||||
- Events: BUTTON 0x04, PACKET_RX 0x0c, CLIENT_LOST 0x0e.
|
||||
- Client commands: WLAN_RESERVED fc 0x70; PAIR_REQ 0x01, PAIR_RESP 0x02,
|
||||
ENABLE_ENCRYPTION 0x10.
|
||||
- 802.11 FCTL: MGMT 0x00, DATA 0x08; ASSOC_REQ 0x00, ASSOC_RESP 0x10,
|
||||
DISASSOC 0xa0, QOS_DATA 0x70.
|
||||
|
||||
### chip Functions To Port (mt76.c)
|
||||
|
||||
`send_wlan`, `associate_client`, `pair_client`, `send_client_command`,
|
||||
`set_client_key`, `remove_client`.
|
||||
|
||||
### GUI
|
||||
|
||||
- C API: expose connected controllers (count + per-client info: MAC, product
|
||||
name from GIP identify, battery).
|
||||
- Swift app: list controllers in the Controllers section of the Debug view.
|
||||
|
||||
## Dongle Initialization Sequence
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user