فهرست منبع

Expose charge shutdown setting in panel and console

Co-authored-by: safijari <5191844+safijari@users.noreply.github.com>
copilot-swe-agent[bot] 1 هفته پیش
والد
کامیت
48edec7fec
3فایلهای تغییر یافته به همراه21 افزوده شده و 2 حذف شده
  1. 6 0
      OpenPuck/serial_console.cpp
  2. 8 2
      OpenPuck/webusb_config.cpp
  3. 7 0
      docs/index.html

+ 6 - 0
OpenPuck/serial_console.cpp

@@ -74,6 +74,12 @@ void serialConsolePoll()
 					"# power off controllers on host sleep (>%ums) %s\n",
 					(unsigned)SUSPEND_OFF_MS,
 					g_suspendOff ? "ON" : "off");
+			} else if (!strcmp(line, "CO")) {
+				g_chargeOff = !g_chargeOff;
+				saveCfg();
+				Serial.printf(
+					"# power off controllers when charging %s\n",
+					g_chargeOff ? "ON" : "off");
 			} else if (!strcmp(line, "HR")) {
 				// A/B: disable the puck->controller haptic relay (Steam 0x80-0x86 rumble/pad feedback)
 				// to isolate whether relaying Steam's trackpad texture haptics degrades drag smoothness.

+ 8 - 2
OpenPuck/webusb_config.cpp

@@ -105,7 +105,8 @@ static bool boardCommand(uint8_t op)
 //                [v21: p[53] rumble strength as PERCENT/2 (field 22, revived); p[195] rumble style
 //                 (field 39, RUMBLE_STYLE_* in haptics.h)]
 //                [v22: p[196] RF recovery status/journal transport capability marker (0x52)]
-#define WB_PAYLEN 195
+//                [v23: p[197] power-off-on-charge option (field 30)]
+#define WB_PAYLEN 196
 // The blob send is drop-on-full (never blocks loop), so the vendor TX FIFO MUST be able to hold a whole blob
 // -- otherwise tud_vendor_write_available() never reaches the frame size and EVERY frame is dropped (blank
 // panel / stale mappings). The Makefile sets -DCFG_TUD_VENDOR_TX_BUFSIZE=256; guard it here so a build without
@@ -134,6 +135,7 @@ static void webusbSendBlob()
 	// protocol version
 	// (21 = +rumble style (field 39, blob p[195]) and the REVIVED rumble-strength field 22 at blob p[53], 
 	// now carrying percent/2; 
+	// 23 = +power-off-on-charge option at p[197];
 	// 22 = +RF recovery capability marker at blob p[196];
 	// 20 = +per-type trackpad->stick mapping (fields 80..87, blob p[187..194]); 
 	// 19 = +Switch Pro legacy-gyro select (field 38, blob p[186]); the Switch report-rate and
@@ -154,7 +156,7 @@ static void webusbSendBlob()
 	// 7 = +raw accel; 
 	// 6 = +swPro120/gyroScale)
 	// clang-format on
-	p[2] = 22;
+	p[2] = 23;
 	p[3] = g_usbMode;
 	p[4] = (uint8_t)g_mDiv;
 	p[5] = (uint8_t)g_mFric;
@@ -340,6 +342,7 @@ static void webusbSendBlob()
 	// v22: append-only RF recovery transport capability. p[181] remains the
 	// upstream Steam Machine toggle; older RF builds used that byte for 0x52.
 	p[196] = 0x52;
+	p[197] = g_chargeOff;
 	// CRITICAL: usb_web.write() SPINS (`while (remain && _connected) yield();`) until the IN FIFO drains or the
 	// panel disconnects. If the panel holds the WebUSB interface open but stops reading its IN endpoint -- a
 	// backgrounded tab, or the host briefly not servicing transferIn under load -- the FIFO never empties and
@@ -1326,6 +1329,9 @@ void webusbPoll()
 				case 29:
 					g_isMachineInternal = v ? 0xEE : 0;
 					break;
+				case 30:
+					g_chargeOff = v ? 1 : 0;
+					break;
 				}
 				if (persist)
 					saveCfg();

+ 7 - 0
docs/index.html

@@ -263,6 +263,9 @@
       <div class="row" style="margin:10px 0 0"><button id="ctlrOff">Turn off controller</button>
         <span class="note" style="flex:1">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.</span>
       </div>
+      <div class="row hide" id="chargeOffRow" style="margin:10px 0 0"><button id="chargeOff">off</button>
+        <span class="note" style="flex:1">Automatically power off each controller when its battery reports charging or fully charged. This is disabled by default.</span>
+      </div>
       <div class="row" style="margin:10px 0 0"><button id="isMachineInternal">off</button>
         <span class="note" style="flex:1"><strong>Emulate Steam Machine.</strong> If this setting is enabled, OpenPuck will emulate a Steam Machine's internal receiver instead of a Steam Controller Puck.</span>
       </div>
@@ -1553,6 +1556,9 @@ function applyBlob(p){
   setSlider("mDiv",mDiv); setSlider("mFric",mFric);
   $("#persistMode").textContent = persistMode? "on":"off"; $("#persistMode").classList.toggle("active",!!persistMode);
   { const la=(p.length>179?p[179] === 0xEE:false); $("#isMachineInternal").textContent = la?"on":"off"; $("#isMachineInternal").classList.toggle("active",!!la); }
+  const chargeOffCap=(p[0]>=23 && p.length>195);
+  $("#chargeOffRow").classList.toggle("hide", !chargeOffCap);
+  if(chargeOffCap){ const chargeOff=!!p[195]; $("#chargeOff").textContent=chargeOff?"on":"off"; $("#chargeOff").classList.toggle("active",chargeOff); }
   // per-type button config (blob v10/v17): 4 types x 9 bytes. readBlob() strips the 2-byte [0xA5][len] header, so
   // the firmware's buffer index 75 lands at JS index 73 here.
   if(p.length>=73+TYPE_DEFS.length*9){
@@ -2873,6 +2879,7 @@ $("#wipeBoard").onclick=async()=>{
 };
 $("#persistMode").onclick=()=>{ const on=$("#persistMode").classList.contains("active"); setField(16, on?0:1); };
 $("#isMachineInternal").onclick=async()=>{ const on=$("#isMachineInternal").classList.contains("active"); await setField(29, on?0:1); };
+$("#chargeOff").onclick=async()=>{ const on=$("#chargeOff").classList.contains("active"); await setField(30, on?0:1); };
 // Connection tuning: post-connect haptic block on (field 27) + seconds (field 28). (poll RX window is fixed.)
 for(const id of ["mDiv","mFric"]){
   const field={mDiv:1,mFric:2}[id];