Explorar el Código

Explicit wake configuration

Jariullah Safi hace 4 meses
padre
commit
4b3c4848cd
Se han modificado 4 ficheros con 57 adiciones y 0 borrados
  1. 20 0
      ARCHITECTURE.md
  2. 5 0
      OpenPuck/OpenPuck.ino
  3. 15 0
      OpenPuck/wake_hid.cpp
  4. 17 0
      OpenPuck/wake_hid.h

+ 20 - 0
ARCHITECTURE.md

@@ -85,6 +85,7 @@ just points at the `OpenPuck` directory). Modules are layered low → high:
 | `rf_diag.{h,cpp}` | RF reverse-engineering / calibration tooling: raw capture, CRC-validating config sweeps, frame replay, address listen, scan-then-respond, live-session sniffer. Not used in normal operation. |
 | `webusb_config.{h,cpp}` | The WebUSB binary config channel for the browser panel. |
 | `serial_console.{h,cpp}` | The CDC single-letter debug command line. |
+| `wake_hid.{h,cpp}` | A boot-keyboard HID interface added to the clean controller modes so the host honors USB remote-wakeup (see "Wake from sleep"). |
 
 ## The controller abstraction
 
@@ -203,6 +204,25 @@ Because the discovery address is shared, two things prevent one puck from distur
    reconnect. (Before these two fixes, plugging a second puck into another computer would wake a sleeping host
    running the first puck.)
 
+## Wake from sleep
+
+The puck can wake a sleeping host via `USBDevice.remoteWakeup()` — driven from `rf_link.cpp` on a Steam-button
+short-press or a fresh RF reconnect (guarded by `USBDevice.suspended()`). Every mode advertises the
+remote-wakeup capability in its config descriptor, so the device is always *armed*. The catch is that a host
+only *honors* a resume signal from an allow-listed input device class (HID keyboard/mouse) — a bare
+gamepad/vendor/composite presentation gets armed but ignored (notably Windows under Modern Standby). That's
+why Xbox mode (which exposes a boot mouse) woke Windows while the gamepad/puck modes didn't.
+
+The fix: `wake_hid.cpp` registers a do-nothing **boot keyboard** interface so each mode is classified as a
+wake-capable input device. It's added in `setup()` for every **clean** mode. It is **not** added in puck mode,
+which is already at the nRF52840's 7-data-IN-endpoint limit (CDC + 4 puck HID + WebUSB) — adding it there would
+require freeing an endpoint (dropping CDC or WebUSB, or a bond slot). Puck mode already wakes on Linux/Steam
+Deck; making it wake Windows is the one case this doesn't cover without that tradeoff.
+
+Note hosts differ in what they honor: Windows keys on the input device class (this fix targets it); Linux/Steam
+Deck gates wake per-device in `/sys/.../power/wakeup` regardless of class, so a mode that still won't wake the
+Deck may just need that sysfs flag enabled host-side.
+
 ## RF reverse-engineering tooling
 
 `rf_diag.cpp` holds everything used to *discover* the protocol — promiscuous capture, config sweeps, bit-exact

+ 5 - 0
OpenPuck/OpenPuck.ino

@@ -29,6 +29,7 @@ using namespace Adafruit_LittleFS_Namespace;
 #include "rf_diag.h"
 #include "webusb_config.h"
 #include "serial_console.h"
+#include "wake_hid.h"
 
 #if CFG_TUD_HID < 4
 #error "build with -DCFG_TUD_HID=4 (extra_flags): up to 4 HID interfaces per mode"
@@ -65,6 +66,10 @@ void setup() {
 
   g_active->begin();   // register this mode's USB interface(s) + set VID/PID/strings
 
+  // Boot-keyboard wake interface so the host honors USBDevice.remoteWakeup() in this mode (see wake_hid.h).
+  // Skipped in puck mode: its CDC + 4 HID + WebUSB composite already uses all 7 data IN endpoints.
+  if (!puckMode) wakeHidBegin();
+
   // WebUSB config panel -- every mode. Puck: historical CDC+HID+vendor stack (Steam + Chrome can share it).
   // Clean modes: bare gamepad + WebUSB (begin() sets bcdUSB 0x0210 + BOS).
   usb_web.begin();

+ 15 - 0
OpenPuck/wake_hid.cpp

@@ -0,0 +1,15 @@
+#include "wake_hid.h"
+#include <Adafruit_TinyUSB.h>
+
+// A bog-standard boot keyboard descriptor. We never send a report on it; it exists purely so the host
+// enumerates a "HID-compliant keyboard" child and grants the device wake-from-sleep privileges.
+static const uint8_t WAKE_HID_DESC[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
+static Adafruit_USBD_HID g_wakeHid;
+
+void wakeHidBegin(){
+  g_wakeHid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);   // boot keyboard = the canonical wake device class
+  g_wakeHid.setStringDescriptor("OpenPuck Wake");
+  g_wakeHid.setReportDescriptor(WAKE_HID_DESC, sizeof WAKE_HID_DESC);
+  g_wakeHid.setPollInterval(10);
+  g_wakeHid.begin();
+}

+ 17 - 0
OpenPuck/wake_hid.h

@@ -0,0 +1,17 @@
+// wake_hid.h -- a minimal boot-protocol HID interface whose ONLY job is to make the device a host-recognized
+// USB wake source.
+//
+// Every mode already advertises remote-wakeup in its config descriptor (the Adafruit core sets
+// TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP), so the device is *armed* to wake the host. But hosts only *honor* a
+// remote-wakeup resume signal from an allow-listed input device class -- a HID keyboard/mouse. Windows
+// (especially under Modern Standby) ignores the wake from a bare gamepad / vendor / composite presentation
+// even though it's armed. Exposing a boot keyboard interface puts the device in that allow-list. It never
+// sends reports -- the actual wake is the device-level USBDevice.remoteWakeup() resume signal driven from
+// rf_link.cpp; this interface only changes how the host classifies us.
+//
+// NOT used in puck (Steam) mode: that composite (CDC + 4 puck HID + WebUSB) already consumes all 7 of the
+// nRF52840's data IN endpoints, leaving no room for another interface. (Puck mode already wakes on Linux/Deck;
+// giving it a wake interface on Windows would require freeing an endpoint -- see ARCHITECTURE.md.)
+#pragma once
+
+void wakeHidBegin();   // register the boot-keyboard wake interface (call from setup() for clean modes)