From b957217ea8c2e34a8d3c68fbc6e2a78daec21aff Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Thu, 6 Oct 2022 01:08:11 -0400 Subject: [PATCH] receiver: delay device sending first messages --- lib/logitech_receiver/device.py | 19 +++++++++++-------- lib/logitech_receiver/hidpp10.py | 11 +++++++++++ lib/logitech_receiver/hidpp10_constants.py | 19 +++++++++---------- lib/logitech_receiver/notifications.py | 2 ++ lib/logitech_receiver/receiver.py | 7 ++----- lib/solaar/cli/show.py | 6 ++++++ 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/logitech_receiver/device.py b/lib/logitech_receiver/device.py index cd5c2796..e4e614c1 100644 --- a/lib/logitech_receiver/device.py +++ b/lib/logitech_receiver/device.py @@ -393,9 +393,8 @@ class Device: if enable: set_flag_bits = ( hidpp10_constants.NOTIFICATION_FLAG.battery_status - | hidpp10_constants.NOTIFICATION_FLAG.keyboard_illumination - | hidpp10_constants.NOTIFICATION_FLAG.wireless - | hidpp10_constants.NOTIFICATION_FLAG.software_present + | hidpp10_constants.NOTIFICATION_FLAG.ui + | hidpp10_constants.NOTIFICATION_FLAG.configuration_complete ) else: set_flag_bits = 0 @@ -404,8 +403,8 @@ class Device: logger.warning("%s: failed to %s device notifications", self, "enable" if enable else "disable") flag_bits = _hidpp10.get_notification_flags(self) - flag_names = None if flag_bits is None else tuple(hidpp10_constants.NOTIFICATION_FLAG.flag_names(flag_bits)) if logger.isEnabledFor(logging.INFO): + flag_names = None if flag_bits is None else tuple(hidpp10_constants.NOTIFICATION_FLAG.flag_names(flag_bits)) logger.info("%s: device notifications %s %s", self, "enabled" if enable else "disabled", flag_names) return flag_bits if ok else None @@ -416,10 +415,6 @@ class Device: self.online = active was_active, self._active = self._active, active if active: - if not was_active: - if self.protocol < 2.0: # Make sure to set notification flags on the device - self.notification_flags = self.enable_connection_notifications() - self.read_battery() # battery information may have changed so try to read it now # Push settings for new devices when devices request software reconfiguration # and when devices become active if they don't have wireless device status feature, if ( @@ -431,6 +426,14 @@ class Device: if logger.isEnabledFor(logging.INFO): logger.info("%s pushing device settings %s", self, self.settings) settings.apply_all_settings(self) + if not was_active: + 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.read_battery() # battery information may have changed so try to read it now + elif was_active and self.receiver: # need to set configuration pending flag in receiver + hidpp10.Hidpp10().set_configuration_pending_flags(self.receiver, 0xFF) if logger.isEnabledFor(logging.DEBUG): logger.debug("device %d changed: active=%s %s", self.number, self._active, self.battery_info) if self.status_callback is not None: diff --git a/lib/logitech_receiver/hidpp10.py b/lib/logitech_receiver/hidpp10.py index 9da59c5d..3c3dd483 100644 --- a/lib/logitech_receiver/hidpp10.py +++ b/lib/logitech_receiver/hidpp10.py @@ -189,6 +189,17 @@ class Hidpp10: assert len(flags) == 3 return _bytes2int(flags) + def get_configuration_pending_flags(self, receiver): + assert not receiver.isDevice + result = read_register(receiver, REGISTERS.devices_configuration) + if result is not None: + return ord(result[:1]) + + def set_configuration_pending_flags(self, receiver, devices): + assert not receiver.isDevice + result = write_register(receiver, REGISTERS.devices_configuration, devices) + return result is not None + def parse_battery_status(register, reply): if register == REGISTERS.battery_charge: diff --git a/lib/logitech_receiver/hidpp10_constants.py b/lib/logitech_receiver/hidpp10_constants.py index 7ab69ee6..7ce607cc 100644 --- a/lib/logitech_receiver/hidpp10_constants.py +++ b/lib/logitech_receiver/hidpp10_constants.py @@ -73,18 +73,16 @@ NOTIFICATION_FLAG = NamedInts( battery_status=0x100000, # send battery charge notifications (0x07 or 0x0D) mouse_extra_buttons=0x080000, roller_V=0x040000, - keyboard_sleep_raw=0x020000, # system control keys such as Sleep + power_keys=0x020000, # system control keys such as Sleep keyboard_multimedia_raw=0x010000, # consumer controls such as Mute and Calculator - # reserved_r1b4= 0x001000, # unknown, seen on a unifying receiver - reserved5=0x008000, - reserved4=0x004000, - reserved3=0x002000, - reserved2=0x001000, - software_present=0x000800, # .. no idea - reserved1=0x000400, - keyboard_illumination=0x000200, # illumination brightness level changes (by pressing keys) + multi_touch=0x001000, # notify on multi-touch changes + software_present=0x000800, # software is controlling part of device behaviour + link_quality=0x000400, # notify on link quality changes + ui=0x000200, # notify on UI changes wireless=0x000100, # notify when the device wireless goes on/off-line - mx_air_3d_gesture=0x000001, + configuration_complete=0x000004, + voip_telephony=0x000002, + threed_gesture=0x000001, ) ERROR = NamedInts( @@ -119,6 +117,7 @@ REGISTERS = NamedInts( # only apply to devices mouse_button_flags=0x01, keyboard_hand_detection=0x01, + devices_configuration=0x03, battery_status=0x07, keyboard_fn_swap=0x09, battery_charge=0x0D, diff --git a/lib/logitech_receiver/notifications.py b/lib/logitech_receiver/notifications.py index 77c091af..fd6626cd 100644 --- a/lib/logitech_receiver/notifications.py +++ b/lib/logitech_receiver/notifications.py @@ -261,6 +261,8 @@ def _process_hidpp10_notification(device, n): bool(flags & 0x80), ) device.link_encrypted = link_encrypted + if not link_established and device.receiver: + _hidpp10.set_configuration_pending_flags(device.receiver, 0xFF) device.changed(active=link_established) return True diff --git a/lib/logitech_receiver/receiver.py b/lib/logitech_receiver/receiver.py index aed45bdf..c3ac47d8 100644 --- a/lib/logitech_receiver/receiver.py +++ b/lib/logitech_receiver/receiver.py @@ -80,6 +80,7 @@ class Receiver: self.notification_flags = None self.pairing = Pairing() self.initialize(product_info) + _hidpp10.set_configuration_pending_flags(self, 0xFF) def initialize(self, product_info: dict): # read the receiver information subregister, so we can find out max_devices @@ -131,11 +132,7 @@ class Receiver: return False if enable: - set_flag_bits = ( - hidpp10_constants.NOTIFICATION_FLAG.battery_status - | hidpp10_constants.NOTIFICATION_FLAG.wireless - | hidpp10_constants.NOTIFICATION_FLAG.software_present - ) + set_flag_bits = hidpp10_constants.NOTIFICATION_FLAG.wireless | hidpp10_constants.NOTIFICATION_FLAG.software_present else: set_flag_bits = 0 ok = _hidpp10.set_notification_flags(self, set_flag_bits) diff --git a/lib/solaar/cli/show.py b/lib/solaar/cli/show.py index ca953457..4f0e64e9 100644 --- a/lib/solaar/cli/show.py +++ b/lib/solaar/cli/show.py @@ -35,6 +35,9 @@ def _print_receiver(receiver): print(" Device path :", receiver.path) print(" USB id : 046d:%s" % receiver.product_id) print(" Serial :", receiver.serial) + pending = _hidpp10.get_configuration_pending_flags(receiver) + if pending: + print(" C Pending : %02x" % pending) if receiver.firmware: for f in receiver.firmware: print(" %-11s: %s" % (f.kind, f.version)) @@ -225,6 +228,9 @@ def _print_device(dev, num=None): or feature == _hidpp20_constants.FEATURE.EXTENDED_ADJUSTABLE_REPORT_RATE ): print(" Report Rate: %s" % _hidpp20.get_polling_rate(dev)) + elif feature == _hidpp20_constants.FEATURE.CONFIG_CHANGE: + response = dev.feature_request(_hidpp20_constants.FEATURE.CONFIG_CHANGE, 0x10) + print(" Configuration: %s" % response.hex()) elif feature == _hidpp20_constants.FEATURE.REMAINING_PAIRING: print(" Remaining Pairings: %d" % _hidpp20.get_remaining_pairing(dev)) elif feature == _hidpp20_constants.FEATURE.ONBOARD_PROFILES: