Jari 27fcf9096e non steam controllers working 3 miesięcy temu
..
src 27fcf9096e non steam controllers working 3 miesięcy temu
CMakeLists.txt 27fcf9096e non steam controllers working 3 miesięcy temu
NOTICE d3f7268600 First time working 3 miesięcy temu
README.md d3f7268600 First time working 3 miesięcy temu
pico_sdk_import.cmake d3f7268600 First time working 3 miesięcy temu

README.md

PicoPuck

A Steam Controller 2 puck emulator for the Raspberry Pi Pico W and Pico 2 W.

Where the original OpenPuck is an nRF52840 dongle that talks to the controller over Valve's proprietary 2.4 GHz ESB link, PicoPuck uses the Pico W's CYW43 radio to reach controllers over Bluetooth — both BLE and Classic — while presenting the host with the exact same Valve puck USB device (28DE:1304). Steam therefore sees a normal puck, and:

  • A Steam Controller 2 paired over its native Bluetooth mode is forwarded transparently — input reports go through verbatim and Steam's haptics / settings writes are relayed back to the controller, so it behaves just like a controller on a real puck.
  • Other Bluetooth controllers (Xbox, DualShock/DualSense, Switch Pro, 8BitDo, Stadia, …) are canonicalised into the puck's input model and, in Steam mode, presented as a controller with neutral trackpads/gyro.

Pairing, unpairing and scanning are driven from the same WebUSB panel (docs/index.html) as the other OpenPuck devices.

Status: under construction. See the phase checklist below.

Building

You need the Arm GNU toolchain, CMake ≥ 3.13, and the Pico SDK 2.x with its btstack, cyw43-driver, lwip, mbedtls, and tinyusb submodules initialised. Point PICO_SDK_PATH at it.

# Pico W (RP2040)
cmake -S PicoPuck -B PicoPuck/build-pico_w -DPICO_BOARD=pico_w
cmake --build PicoPuck/build-pico_w -j

# Pico 2 W (RP2350)
cmake -S PicoPuck -B PicoPuck/build-pico2_w -DPICO_BOARD=pico2_w
cmake --build PicoPuck/build-pico2_w -j

Outputs: picopuck_pico_w.uf2 / picopuck_pico2_w.uf2. Flash by holding BOOTSEL while plugging in, or from the panel's "reboot to bootloader" button.

There is also a make picopuck / make picopuck-pico2w convenience target in the repo root Makefile.

Phase checklist

  • Phase 0 — scaffold: builds for both boards, heartbeat LED.
  • Phase 1 — USB puck identity (4 HID slots + WebUSB) enumerates; panel connects.
  • Phase 2 — generic BLE pad (Xbox) presented in Steam mode via a synthesized report.
  • Phase 3 — Classic HID host + DualShock 4. (DS5 / Switch Pro are drivers-in-waiting, see below.)
  • Phase 4 — Steam Controller 2 transparent forwarding over the Valve GATT service.
  • Phase 5 — 4-slot model, flash bond persistence + auto-reconnect, scan-duty policy, firmware/bootloader button.

Implemented in code (needs on-hardware validation)

The full architecture is in place and compiling for both boards, but has not been run on real hardware yet. Everything below is correct-by-construction (ported from OpenPuck / joypad-os byte layouts and the reversed SC2 protocol); expect to iterate once flashed.

Follow-on drivers / features (same interfaces, deferred)

  • DualSense (DS5) — Classic, needs the CRC32-sealed output report and adaptive-trigger/touchpad handling; add a drv_ds5 implementing input_driver_t.
  • Switch Pro — Classic, needs the subcommand init handshake before it reports.
  • Battery — read the BLE Battery Service (and the SC2's battery channel) into g_battery[slot] so Steam shows a level instead of the wired glyph.
  • Concurrency/bandwidth and soak testing (see risks).

Known risks / open questions

  • Concurrent-link ceiling. BTstack pools are sized for four slots, but the CYW43 firmware's real concurrent Classic+BLE limit and ACL bandwidth under load are unverified; running inquiry+scan while controllers are connected is known to hurt throughput. The four USB slots are always enumerated regardless.
  • Latency. A BLE connection interval floor (~7.5 ms) delivers input slower than the nRF puck's RF poll; verbatim on-air timestamps keep gyro integration correct but feel is to be compared against a real puck.
  • Windows descriptor cache. Same VID/PID as the nRF puck with a different interface layout — bcdDevice is bumped to 0x03xx to force a fresh cache entry; test both plug orders.
  • BTstack licensing. Covered by the SDK's LICENSE.RP grant only on Raspberry Pi silicon; see NOTICE.