Fix Centurion protocol version display (1.16 not 2.6)

The HID++ ping math (major + minor/10.0) produced a bogus "2.6" for
Centurion devices whose ProtocolCapabilities returns major=1, minor=0x10.
Store the raw (major, minor) bytes from the ping response and display
them correctly as "Centurion 1.16" in both CLI and GUI.
This commit is contained in:
Ken Sanislo 2026-03-03 18:24:38 -07:00
parent bdc66d0b20
commit 0cc3b01aec
4 changed files with 24 additions and 3 deletions

View File

@ -107,6 +107,8 @@ _CENTURION_MSG_SIZE = 63 # max reconstructed message size after unwrapping (2 +
# Set of handles that use Centurion framing
_centurion_handles: set[int] = set()
# Raw Centurion protocol version (major, minor) by handle, from ping response
_centurion_protocol_versions: dict[int, tuple[int, int]] = {}
"""Default timeout on read (in seconds)."""
@ -300,6 +302,7 @@ def close(handle):
try:
if isinstance(handle, int):
_centurion_handles.discard(handle)
_centurion_protocol_versions.pop(handle, None)
hidapi.close(handle)
else:
handle.close()
@ -715,7 +718,11 @@ def ping(handle, devnumber, long_message: bool = False):
mark_ok = is_centurion or reply_data[4:5] == request_data[-1:]
if reply_data[:2] == request_data[:2] and mark_ok:
# HID++ 2.0+ device, currently connected
return ord(reply_data[2:3]) + ord(reply_data[3:4]) / 10.0
major = ord(reply_data[2:3])
minor = ord(reply_data[3:4])
if is_centurion:
_centurion_protocol_versions[int(handle)] = (major, minor)
return major + minor / 10.0
if (
report_id == HIDPP_SHORT_MESSAGE_ID

View File

@ -1089,6 +1089,10 @@ class Device:
return False
if protocol:
self._protocol = protocol
# Pick up raw Centurion protocol version from ping response
cent_ver = base._centurion_protocol_versions.get(int(handle))
if cent_ver:
self._centurion_protocol = cent_ver
# Dongle responded — now check if headset is actually on by probing through bridge.
# Send ROOT.GetFeature(0x0001) to the sub-device via CentPPBridge.
bridge_idx = getattr(self, "_centurion_bridge_index", None)

View File

@ -164,7 +164,11 @@ def _print_device(dev, num=None):
print(" Kind :", dev.kind)
if dev.protocol:
proto_name = "Centurion" if is_centurion else "HID++"
print(f" Protocol : {proto_name} {dev.protocol:1.1f}")
cent_proto = getattr(dev, "_centurion_protocol", None)
if cent_proto:
print(f" Protocol : {proto_name} {cent_proto[0]}.{cent_proto[1]}")
else:
print(f" Protocol : {proto_name} {dev.protocol:1.1f}")
else:
print(" Protocol : unknown (device is offline)")
if not is_centurion and dev.polling_rate:

View File

@ -536,7 +536,13 @@ def _update_details(button):
if device.product_id:
yield _("Product ID"), f"{LOGITECH_VENDOR_ID:04x}:" + device.product_id
hid_version = device.protocol
yield _("Protocol"), f"HID++ {hid_version:1.1f}" if hid_version else _("Unknown")
cent_proto = getattr(device, "_centurion_protocol", None)
if cent_proto:
yield _("Protocol"), f"Centurion {cent_proto[0]}.{cent_proto[1]}"
elif hid_version:
yield _("Protocol"), f"HID++ {hid_version:1.1f}"
else:
yield _("Protocol"), _("Unknown")
if read_all and device.polling_rate:
yield _("Polling rate"), device.polling_rate