From 546ccb7ac20c18a4186f18ea2d2638f7420f6672 Mon Sep 17 00:00:00 2001 From: "Peter F. Patel-Schneider" Date: Sat, 8 Feb 2020 14:08:13 -0500 Subject: [PATCH] receiver: determine remaining pairings (if receiver has this) and display in solaar show and main window --- lib/logitech_receiver/base_usb.py | 18 ++++++++++++- lib/logitech_receiver/receiver.py | 43 +++++++++++++++++++------------ lib/solaar/cli/show.py | 2 ++ lib/solaar/ui/window.py | 3 +++ 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/logitech_receiver/base_usb.py b/lib/logitech_receiver/base_usb.py index 06c753bb..4c36e9f0 100644 --- a/lib/logitech_receiver/base_usb.py +++ b/lib/logitech_receiver/base_usb.py @@ -25,6 +25,11 @@ from __future__ import absolute_import, division, print_function, unicode_litera _DRIVER = ('hid-generic', 'generic-usb', 'logitech-djreceiver') +# max_devices is only used for receivers that do not support reading from _R.receiver_info offset 0x03, default to 1 +# may_unpair is only used for receivers that do not support reading from _R.receiver_info offset 0x03, default to False +## should this last be changed so that may_unpair is used for all receivers? writing to _R.receiver_pairing doesn't seem right +# re_pairs determines whether a receiver pairs by replacing existing pairings, default to False +## currently only one receiver is so marked - should there be more? _unifying_receiver = lambda product_id: { 'vendor_id':0x046d, @@ -42,6 +47,17 @@ _nano_receiver = lambda product_id: { 'name':'Nano Receiver' } +_nano_receiver_max2 = lambda product_id: { + 'vendor_id':0x046d, + 'product_id':product_id, + 'usb_interface':1, + 'hid_driver':_DRIVER, + 'name':'Nano Receiver', + 'max_devices': 2, + 'may_unpair': False, + 're_pairs': True +} + _lenovo_receiver = lambda product_id: { 'vendor_id':0x17ef, 'product_id':product_id, @@ -75,7 +91,7 @@ NANO_RECEIVER_C525 = _nano_receiver(0xc525) NANO_RECEIVER_C526 = _nano_receiver(0xc526) NANO_RECEIVER_C52e = _nano_receiver(0xc52e) NANO_RECEIVER_C531 = _nano_receiver(0xc531) -NANO_RECEIVER_C534 = _nano_receiver(0xc534) +NANO_RECEIVER_C534 = _nano_receiver_max2(0xc534) NANO_RECEIVER_6042 = _lenovo_receiver(0x6042) # Lightspeed receivers diff --git a/lib/logitech_receiver/receiver.py b/lib/logitech_receiver/receiver.py index 0ca5688a..9637a861 100644 --- a/lib/logitech_receiver/receiver.py +++ b/lib/logitech_receiver/receiver.py @@ -334,29 +334,31 @@ class Receiver(object): self.path = device_info.path # USB product id, used for some Nano receivers self.product_id = device_info.product_id - - # read the serial immediately, so we can find out max_devices - # this will tell us if it's a Unifying or Nano receiver - if self.product_id != 'c534': - serial_reply = self.read_register(_R.receiver_info, 0x03) - assert serial_reply - self.serial = _strhex(serial_reply[1:5]) - self.max_devices = ord(serial_reply[6:7]) - else: - self.serial = None - self.max_devices = 6 - product_info = _product_information(self.product_id) if not product_info: raise Exception("unknown receiver type", self.product_id) - self.name = product_info.get('name','') - self._str = '<%s(%s,%s%s)>' % (self.name.replace(' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle) - # TODO _properly_ figure out which receivers do and which don't support unpairing - self.may_unpair = self.write_register(_R.receiver_pairing) is None + # read the serial immediately, so we can find out max_devices + # this will tell us if it's a Unifying or Nano receiver + serial_reply = self.read_register(_R.receiver_info, 0x03) + if serial_reply : + self.serial = _strhex(serial_reply[1:5]) + self.max_devices = ord(serial_reply[6:7]) + # TODO _properly_ figure out which receivers do and which don't support unpairing + # This code supposes that receivers that don't unpair support a pairing request for device index 0 + self.may_unpair = self.write_register(_R.receiver_pairing) is None + else: # handle receivers that don't have a serial number specially (i.e., c534) + self.serial = None + self.max_devices = product_info.get('max_devices',1) + self.may_unpair = product_info.get('may_unpair',False) + + self.name = product_info.get('name','') + self.re_pairs = product_info.get('re_pairs',False) + self._str = '<%s(%s,%s%s)>' % (self.name.replace(' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle) self._firmware = None self._devices = {} + self._remaining_pairings = None def close(self): handle, self.handle = self.handle, None @@ -372,6 +374,15 @@ class Receiver(object): self._firmware = _hidpp10.get_firmware(self) return self._firmware + # how many pairings remain (None for unknown, -1 for unlimited) + def remaining_pairings(self,cache=True): + if self._remaining_pairings is None or not cache : + ps = self.read_register(_R.receiver_connection) + if ps is not None: + ps = ord(ps[2:3]) + self._remaining_pairings = ps-5 if ps >= 5 else -1 + return self._remaining_pairings + def enable_notifications(self, enable=True): """Enable or disable device (dis)connection notifications on this receiver.""" diff --git a/lib/solaar/cli/show.py b/lib/solaar/cli/show.py index a277b084..ebd91231 100644 --- a/lib/solaar/cli/show.py +++ b/lib/solaar/cli/show.py @@ -38,6 +38,8 @@ def _print_receiver(receiver): print (' %-11s: %s' % (f.kind, f.version)) print (' Has', paired_count, 'paired device(s) out of a maximum of %d.' % receiver.max_devices) + if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0 : + print (' Has %d successful pairing(s) remaining.' % receiver.remaining_pairings() ) notification_flags = _hidpp10.get_notification_flags(receiver) if notification_flags is not None: diff --git a/lib/solaar/ui/window.py b/lib/solaar/ui/window.py index edf097a4..954d0714 100644 --- a/lib/solaar/ui/window.py +++ b/lib/solaar/ui/window.py @@ -572,6 +572,9 @@ def _update_receiver_panel(receiver, panel, buttons, full=False): paired_text += '\n\n%s' % ngettext('Up to %(max_count)s device can be paired to this receiver.', 'Up to %(max_count)s devices can be paired to this receiver.', receiver.max_devices) % { 'max_count': receiver.max_devices } elif(devices_count > 0): paired_text += '\n\n%s' % _('Only one device can be paired to this receiver.') + pairings = receiver.remaining_pairings(False) + if ( pairings is not None and pairings >= 0 ) : + paired_text += '\n%s' % _('This receiver has %d pairing(s) remaining.') % pairings panel._count.set_markup(paired_text)