OpenPuck SC2 puck · WebUSB disconnected

First connect uses the Chrome/Edge device picker; reconnects are automatic. If the picker is empty, quit any app holding the device or replug.

Controller Firmware update

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
Polls/s
Delivered
Fails/s (crc·noRx·relay)
Delivered (all)
New reports (all)
Polls/s (all)
Relay/s (all)
RF fails/s (crc·noRx·heal)
Clock LF / HF
µs per ms (ideal 1000)
Loop
usbd stack free (words)
Loop period
Slowest stage
Poll period act/want
Build
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.

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.
Land all 0x87 (experiment). Relay Steam's full haptic/settings config to the controller verbatim (like the real puck) instead of discarding it. Testing whether the connect buzz is caused by the controller's haptic engine being left misconfigured. If the gyro freezes in Steam, turn this back off.
Buzzes the controllers every 10 s (keeps them awake) and times how long the puck stays up. On a reset it records the uptime and shows it by Last reset; it auto-resumes after the puck reconnects. The count is kept in this tab (a page refresh clears it).

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.

Hang log

One row per reset: uptime before it, reason, the stuck loop stage and captured PC (when the watchdog ISR could run), and usbd stack free. Accumulates across resets in this tab — a page refresh clears it. Pair with Test stability above for unattended runs.

no resets logged yet

    

Loop-state trail

Every change of the Loop pill, timestamped — stall episodes, live wedge reports, heartbeat loss (hard wedge, USB silent), recoveries, disconnects and the reset cause on reconnect — so an unattended hang is recorded even if you weren't watching. Saved in this browser (localStorage): it survives page refreshes and device reboots, and clears only with the button.

no events yet

Flight recorder

The trail of events the firmware recorded in the seconds before its most recent watchdog hang — the ring survives the reset in .noinit RAM (like the hang PC), so it's the post-mortem of what wedged the board. Loads automatically after a hang reconnects; click to reload. Same data the console FR command prints.

no trail loaded

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.


    

Panel updates not supported by this firmware

Update from a local file

Drop a .uf2 file here — or click to browse
no file selected
The image is streamed over WebUSB into spare flash, verified on the puck, and applied on an automatic reboot. Nothing is armed until it verifies — a failed or interrupted transfer leaves the running firmware untouched, and even a power cut during the apply only leaves the puck in its UF2 bootloader for drag-and-drop recovery.

Update from a release

Official builds from github.com/safijari/openpuck/releases  ·  installed:
loading…

Factory reset flashes the -factory-reset build of that version: on its first boot it wipes ALL settings and the controller pairing (you must re-pair), then behaves like the standard build. Use it to recover from a bad config or stale bond.

Firmware update