diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py index ff3565b7..209affed 100644 --- a/lib/logitech_receiver/device.py +++ b/lib/logitech_receiver/device.py @@ -437,6 +437,11 @@ class Device: if self.online and self.protocol >= 2.0: _hidpp20.config_change(self, configuration_, no_reply=no_reply) + def signal_configuration_complete(self): + """Read the device's config cookie and echo it back via SetComplete to ack end of configuration.""" + if self.online and self.protocol >= 2.0: + _hidpp20.set_configuration_complete(self) + def reset(self, no_reply=False): self.set_configuration(0, no_reply) @@ -541,7 +546,7 @@ class Device: if self.protocol < 2.0: # Make sure to set notification flags on the device self.notification_flags = self.enable_connection_notifications() else: - self.set_configuration(0x11) # signal end of configuration + self.signal_configuration_complete() self.read_battery() # battery information may have changed so try to read it now elif was_active and self.receiver and not isinstance(self.receiver, CenturionReceiver): hidpp10.set_configuration_pending_flags(self.receiver, 0xFF) diff --git a/lib/logitech_receiver/hidpp20.py b/lib/logitech_receiver/hidpp20.py index d000b409..32a7e93f 100644 --- a/lib/logitech_receiver/hidpp20.py +++ b/lib/logitech_receiver/hidpp20.py @@ -2051,7 +2051,26 @@ class Hidpp20: return struct.unpack("!B", result[:1])[0] return None + def get_configuration_cookie(self, device: Device): + """ConfigChange (0x0020) GetCookie — read the device's current configuration cookie.""" + response = device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x00) + return response[:2] if response else None + + def set_configuration_complete(self, device: Device, cookie=None, no_reply=False): + """ConfigChange (0x0020) SetComplete — acknowledge host has synced with device configuration. + + If cookie is None, reads the current cookie and increments it to mark + a new sync point, so future cookie changes indicate device-side drift.""" + if cookie is None: + cookie = self.get_configuration_cookie(device) + if cookie and len(cookie) >= 2: + value = (cookie[0] << 8 | cookie[1]) + 1 & 0xFFFF + cookie = bytes([value >> 8, value & 0xFF]) + if cookie and len(cookie) >= 2: + return device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x10, cookie[0], cookie[1], no_reply=no_reply) + def config_change(self, device: Device, configuration, no_reply=False): + """Deprecated — use set_configuration_complete() instead.""" return device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x10, configuration, no_reply=no_reply) diff --git a/lib/logitech_receiver/notifications.py b/lib/logitech_receiver/notifications.py index 693e3afd..79c7cf5a 100644 --- a/lib/logitech_receiver/notifications.py +++ b/lib/logitech_receiver/notifications.py @@ -34,6 +34,7 @@ from . import diversion from . import hidpp10 from . import hidpp10_constants from . import hidpp20 +from . import settings from . import settings_templates from .common import Alert from .common import BatteryStatus @@ -324,7 +325,9 @@ def _process_feature_notification(device: Device, notification: HIDPPNotificatio reason = "powered on" if notification.data[2] == 1 else None if notification.data[1] == 1: # device is asking for software reconfiguration so need to change status alert = Alert.NONE - device.changed(active=True, alert=alert, reason=reason, push=True) + device.changed(active=True, alert=alert, reason=reason) + settings.apply_all_settings(device) + device.signal_configuration_complete() else: logger.warning("%s: unknown WIRELESS %s", device, notification)