Add debug logging around Centurion device_addr probe

Temporary diagnostics for field-testing the probe fix. Each step of
the probe loop logs attempt number, bytes received, and the first 4
bytes of the RX frame so a `solaar -dd` trace shows exactly what the
device returned (or didn't).

Also adds a WARNING log in Device.battery() when it falls through to
the HID++ 1.0 path on a Centurion device. If that warning ever fires
in the wild, it means the probe silently failed and the next step will
be the register read that returns INVALID_SUB_ID_COMMAND — a direct
breadcrumb from cause to crash.

Revert this commit once we've confirmed the probe works reliably on
reporter hardware.
This commit is contained in:
Ken Sanislo 2026-04-15 18:11:14 -07:00
parent 31a14340d3
commit dbd054c468
2 changed files with 46 additions and 3 deletions

View File

@ -358,24 +358,58 @@ def probe_centurion_device_addr(handle, state: CenturionHandleState) -> bool:
if state.report_id != CENTURION_ADDRESSED_REPORT_ID or state.device_addr is not None:
return False
ihandle = int(handle)
if logger.isEnabledFor(logging.DEBUG):
logger.debug(
"(%s) probing centurion device_addr (report_id=0x%02X, %d iters x %d ms)",
handle,
state.report_id,
_CENTURION_PROBE_READ_ITERATIONS,
_CENTURION_PROBE_READ_TIMEOUT_MS,
)
probe = bytes([state.report_id]) + b"\x00" * (CENTURION_FRAME_SIZE - 1)
try:
hidapi.write(ihandle, probe)
except Exception as reason:
logger.warning("(%s) centurion device_addr probe write failed: %s", handle, reason)
return False
for _ in range(_CENTURION_PROBE_READ_ITERATIONS):
for attempt in range(1, _CENTURION_PROBE_READ_ITERATIONS + 1):
try:
data = hidapi.read(ihandle, CENTURION_FRAME_SIZE, _CENTURION_PROBE_READ_TIMEOUT_MS)
except Exception as reason:
logger.warning("(%s) centurion device_addr probe read failed: %s", handle, reason)
return False
if logger.isEnabledFor(logging.DEBUG):
if data:
logger.debug(
"(%s) centurion probe attempt %d/%d: got %d bytes, head=%s",
handle,
attempt,
_CENTURION_PROBE_READ_ITERATIONS,
len(data),
common.strhex(data[:4]) if len(data) >= 4 else common.strhex(data),
)
else:
logger.debug(
"(%s) centurion probe attempt %d/%d: read timeout (no data)",
handle,
attempt,
_CENTURION_PROBE_READ_ITERATIONS,
)
if data and len(data) >= 2 and ord(data[:1]) == state.report_id:
state.device_addr = ord(data[1:2])
if logger.isEnabledFor(logging.DEBUG):
logger.debug("(%s) probed centurion device addr 0x%02X", handle, state.device_addr)
logger.debug(
"(%s) probed centurion device addr 0x%02X on attempt %d",
handle,
state.device_addr,
attempt,
)
return True
logger.warning("(%s) centurion device_addr probe timed out, subsequent TX will use 0x00", handle)
logger.warning(
"(%s) centurion device_addr probe timed out after %d attempts, subsequent TX will use 0x00",
handle,
_CENTURION_PROBE_READ_ITERATIONS,
)
return False

View File

@ -468,6 +468,15 @@ class Device:
def battery(self): # None or level, next, status, voltage
if self.protocol < 2.0:
if self.centurion:
logger.warning(
"%s: battery() dispatching HID++ 1.0 path for a Centurion device "
"(protocol=%s, _protocol=%s) — device_addr probe likely failed, "
"expect INVALID_SUB_ID_COMMAND",
self,
self.protocol,
self._protocol,
)
return _hidpp10.get_battery(self)
else:
battery_feature = self.persister.get("_battery", None) if self.persister else None