Przeglądaj źródła

battery level shows up now

Jari 4 miesięcy temu
rodzic
commit
2ae02ad5c2
4 zmienionych plików z 37 dodań i 4 usunięć
  1. 25 2
      OpenPuck/puck_hid.cpp
  2. 9 2
      OpenPuck/rf_link.cpp
  3. 2 0
      OpenPuck/rf_link.h
  4. 1 0
      docs/index.html

+ 25 - 2
OpenPuck/puck_hid.cpp

@@ -462,8 +462,12 @@ void SteamPuckController::onAuxReport(int slot, uint8_t rid,
 	// Forward the controller's status report VERBATIM (the real puck does this; it's how the host reads
 	// battery). Padding the report to the descriptor-declared length broke battery in both lizard and
 	// Steam, so it's reverted -- send exactly what the controller sent.
-	if (g_slot[slot].used && hid[slot].ready())
+	if (g_slot[slot].used && hid[slot].ready()) {
+		// capture the pushed status report (0x43 battery / 0x44) device->host for the WebUSB panel: this is
+		// the channel Steam actually reads battery from; marker 0xFB = "->host push".
+		hapLogAdd(0xFB, rid, data, n);
 		hid[slot].sendReport(rid, data, n);
+	}
 }
 
 // wake nudge: a bare USB resume signal is NOT enough to wake some hosts (Windows in particular) -- they only
@@ -568,7 +572,7 @@ void SteamPuckController::task()
 	// slot. The real puck's per-slot edge-triggered 0x79 prevents re-triggering Steam's connect-chime loop.
 	static bool usbConn[NSLOT] = { 0 };
 	static unsigned long last79[NSLOT] = { 0 }, last7B[NSLOT] = { 0 },
-			     connEdgeMs[NSLOT] = { 0 };
+			     connEdgeMs[NSLOT] = { 0 }, last43[NSLOT] = { 0 };
 	for (int s = 0; s < NSLOT; s++) {
 		if (!g_slot[s].used || !hid[s].ready())
 			continue;
@@ -586,6 +590,7 @@ void SteamPuckController::task()
 			if (conn && !usbConn[s])
 				connEdgeMs[s] = millis();
 			uint8_t st = conn ? 0x02 : 0x01;
+			hapLogAdd(0xFB, 0x79, &st, 1); // ->host push (capture)
 			hid[s].sendReport(0x79, &st, 1);
 			usbConn[s] = conn;
 			last79[s] = millis();
@@ -609,9 +614,27 @@ void SteamPuckController::task()
 					mag = 95;
 				s7b[8] = (uint8_t)(0u - (uint8_t)mag);
 			}
+			hapLogAdd(0xFB, 0x7B, s7b, 12); // ->host push (capture)
 			hid[s].sendReport(0x7B, s7b, 12);
 			last7B[s] = millis();
 		}
+		// Synthesized 0x43 = ID_TRITON_BATTERY_STATUS for SDL/Steam's gamepad driver. The verbatim forward of
+		// the controller's own 0x43 (onAuxReport) is what the LIZARD/kernel path reads, but SDL's Triton driver
+		// requires the FULL TritonBatteryStatus_t length (r >= 1 + 14) and lapses to the "wired" glyph without a
+		// fresh one -- so we push a clean 14-byte report from g_battery every 2s. Body: [ucChargeState][ucBattery
+		// Level][voltages/current/temp = 0]; SDL only reads the first two. Map unknown/reset state -> discharging
+		// so it shows ON_BATTERY + % rather than UNKNOWN. Skipped until the controller has reported a level.
+		if (conn && g_battery[s] && millis() - last43[s] >= 2000) {
+			uint8_t st = g_batteryState[s];
+			if (st != 1 && st != 2 && st != 4)
+				st = 1; // EChargeState discharging -> SDL_POWERSTATE_ON_BATTERY
+			uint8_t b43[14] = { 0 };
+			b43[0] = st; // ucChargeState
+			b43[1] = g_battery[s]; // ucBatteryLevel (percent)
+			hapLogAdd(0xFB, 0x43, b43, 14); // ->host push (capture)
+			hid[s].sendReport(0x43, b43, sizeof b43);
+			last43[s] = millis();
+		}
 	}
 	// Reset edge state for slots that are no longer used/ready (so a re-bond sees a fresh edge).
 	for (int s = 0; s < NSLOT; s++)

+ 9 - 2
OpenPuck/rf_link.cpp

@@ -68,6 +68,8 @@ volatile uint8_t g_linkRssi[NSLOT] = { 0 };
 // battery % from the controller's report 0x43 (body[1]); 0 = none yet. Per-slot -- the active controller's
 // battery is the most recently seen one (other slots' values stay in their own array slots).
 volatile uint8_t g_battery[NSLOT] = { 0 };
+// charge state from report 0x43 body[0] (EChargeState: 1=discharging 2=charging 4=charging-done; 0=unknown).
+volatile uint8_t g_batteryState[NSLOT] = { 0 };
 
 // Slot the poll loop is currently driving. Set by rfConnStep before each E7/relay/E3, consumed by the
 // decode (g_in[g_curSlot]), the haptic flush (per-slot session address), and the per-second stat dump.
@@ -534,13 +536,18 @@ uint8_t rfConnTx(uint8_t ch, uint8_t s1, const uint8_t *payload, uint8_t plen,
 						// [rid][body...]
 						const uint8_t *rep =
 							&rfrx[idx + 2];
-						// 0x43 body[1] (~0x5e=94) reads as battery % (sniff-derived)
+						// 0x43 body[0] = ucChargeState (EChargeState), body[1] = ucBatteryLevel % (sniff-derived).
+						// rep[0]=rid, rep[1]=body[0], rep[2]=body[1]. Snapshot both for the WebUSB panel and the
+						// synthesized full-length 0x43 the puck pushes for SDL (see puck_hid.cpp task()).
 						if (rep[0] == 0x43 &&
 						    tlen >= 3 &&
 						    g_curSlot >= 0 &&
-						    g_curSlot < NSLOT)
+						    g_curSlot < NSLOT) {
+							g_batteryState[g_curSlot] =
+								rep[1];
 							g_battery[g_curSlot] =
 								rep[2];
+						}
 						if (g_active)
 							g_active->onAuxReport(
 								g_curSlot,

+ 2 - 0
OpenPuck/rf_link.h

@@ -91,6 +91,8 @@ extern volatile uint8_t g_linkRssi[NSLOT];
 // reads g_battery[g_curSlot] (the most recently active one). The raw 0x43 report is also forwarded to
 // Steam verbatim (puck_hid onAuxReport) so Steam reads it itself.
 extern volatile uint8_t g_battery[NSLOT];
+// charge state from report 0x43 body[0] (EChargeState: 1=discharging, 2=charging, 4=charging-done; 0=unknown)
+extern volatile uint8_t g_batteryState[NSLOT];
 
 // TX one connected packet [LEN][S1][payload] on channel ch, then RX the reply into rfrx; decodes 0xF1.
 // rxWinUs overrides the reply-wait window (0 = use g_rxWin). Pass a tiny value for NO-ACK relays that expect

+ 1 - 0
docs/index.html

@@ -510,6 +510,7 @@ function fmtCapEntry(e,maxMs){
   const t = `-${String(maxMs-e.ms).padStart(6," ")}ms  `;
   if(e.slot===0xFD){ const k=e.bytes[0]; return `${t}════════ ${k===2?"RECONNECT (block+reinit armed)":k===1?"RF LINK UP":"RF LINK DOWN"} ════════`; }
   if(e.slot===0xFC){ return `${t}GET←host rid=${e.rid.toString(16).padStart(2,"0")}  n=${e.nb}:  ${hex}`; } // host feature GET (battery poll lives here)
+  if(e.slot===0xFB){ return `${t}→host    rid=${e.rid.toString(16).padStart(2,"0")}  n=${e.nb}:  ${hex}`; } // pushed device→host status (0x43 battery / 0x7B / 0x79)
   const who = (e.slot===0xFE) ? "TX→ctlr " : `if${e.slot}     `;
   return `${t}${who} cmd=${e.rid.toString(16).padStart(2,"0")}  n=${e.nb}:  ${hex}`;
 }