OpenPuck Config

nRF52840 Steam Controller 2 puck reimplementation — WebUSB. Chrome/Edge only.

disconnected

If nothing appears in the device picker, the copycat may be busy (quit any app holding it) or needs a replug.

USB mode

Switching reboots the copycat and re-enumerates USB (~2 s). WebUSB works in every mode, including Steam/Lizard with Steam running (Chrome claims the vendor interface; Steam keeps the HID slots). Switch HORIPAD + WebUSB is PC-only.

Off (default): every restart / fresh reconnect boots into Steam mode. On: remembers the last mode you selected.

Back4 + face button chords

Hold all four back paddles (L4+R4+L5+R5) plus a face button to switch mode without the WebUI. A is always Steam. B / X / Y are configurable below (defaults: B=Lizard, X=Xbox, Y=Switch HORIPAD).

Link status

RF link
Battery
—
Signal
—
Delivered
—
New reports
—
Polls/s
—
RF fails/s (crc·noRx·heal)
—
Loop period
—
Slowest stage
—
Poll period act/want
—
Build (git)
—
Last reset
—

Reset detail: —
watchdog (hang)/CPU lockup/HARDFAULT = a fault worth reporting (issue #72); reboot = an intentional reset (mode change / config); power-on & pin/replug = normal plug-in.

IMU (raw): —
Raw SC2 accel (before scaling). This controller is a ±2 g sensor (~16384 = 1 g); the Switch report divides it by 4 to present the genuine ±8 g (4096 = 1 g) scale so the console's gravity-correction engages and the gyro stops drifting.

Polls/s ≈ 250 expected; it's capped by Loop period (≈4000 µs needed). "Slowest stage" is the loop section eating the most time per iteration.

Connection tuning (persists across reboot)
Drops all Steam haptics for a short window right after a controller (re)connects, so its haptic engine settles before the first real haptic.
How long to drop haptics after connect (seconds). Default 10 s.
If the controller's haptics get stuck/buzzing, this re-inits them (same as pressing Steam).
Fires the controller power-off (0x9F "off!", x3) — the same path Steam's "turn off controller" and host-suspend use. Watch the link status to see it disconnect.
Reboots the puck into serial DFU mode (adafruit-nrfutil). The device drops off USB — flash with adafruit-nrfutil dfu serial … then replug.
Reboots the puck into the UF2 mass-storage bootloader. It mounts as a USB drive — drag the .uf2 file onto it to flash, then it reboots automatically.
Danger: wipes all persistent storage on the copycat — the paired controller bond and every saved setting (mode, chords, back-paddle map, sensitivity). The copycat reboots to factory defaults and you must re-pair the controller. This cannot be undone.

Trackpad mouse (lizard + Xbox)

Right-pad cursor in Steam-mode lizard (Steam closed) and in Xbox mode. Sensitivity is a divisor — lower = faster pointer. Glide = how long the cursor coasts after a flick.

Rumble

Scales rumble amplitude across all modes (100% = native, 200% = double, 0% = off).

Switch Pro motion

Full rate (~250 Hz, default) is lowest-latency. 120 Hz is low-latency and drift-free. 66 Hz is a genuine-cadence compatibility fallback — drop to it only if your console rejects the faster rates.

Gyro sensitivity multiplier for Switch Pro mode (1.0× = unchanged).

Button mapping

Separate mappings per emulated controller type — each only offers targets that exist on that controller. The type matching the current mode is highlighted. Steam & Lizard are native puck modes (Steam does its own remapping) and aren't configured here.

Backup & clone

Save this puck's controller pairings and every setting to a file, then restore them onto another puck. The other puck becomes a clone — any controller paired to this one connects to it with no re-pairing. (Also a plain backup: re-import after a factory erase to get everything back.)

Import overwrites all pairings and settings on the connected puck, then reboots it (~2 s — reconnect after). Tip: pair every controller to one puck, export once, then import onto each spare.

Capture — host → controller commands

The firmware logs everything from boot into a big RAM ring: Steam's writes (ifN), the frames we transmit to the controller (TX→ctlr), and RF LINK UP/DOWN edges. For the reconnect buzz: trigger it (it appears moments after the puck boots / the controller reconnects), then connect here and click Dump from boot — the trigger is still in the ring. (Only present in a logging build, -DOPK_LOG=1.)

Dump streams the whole ring (oldest→newest) and then keeps live-updating until you press Stop. cmd is the command/report byte, then the raw bytes.