From 27403a08d2d9ae838e6b7215578c986b80e61d95 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Wed, 5 Dec 2012 21:41:02 +0200 Subject: [PATCH] improved hid++ 1.0 support --- app/listener.py | 9 ++++----- app/solaar_cli.py | 6 ++++-- lib/logitech/unifying_receiver/base.py | 3 +++ lib/logitech/unifying_receiver/hidpp10.py | 7 ++++++- lib/logitech/unifying_receiver/hidpp20.py | 1 + lib/logitech/unifying_receiver/receiver.py | 9 +++++++++ lib/logitech/unifying_receiver/status.py | 9 +++++++++ 7 files changed, 36 insertions(+), 8 deletions(-) diff --git a/app/listener.py b/app/listener.py index c552a233..fd57e522 100644 --- a/app/listener.py +++ b/app/listener.py @@ -95,8 +95,8 @@ class ReceiverListener(_listener.EventsListener): return for dev in self.receiver: - assert dev.status is not None - dev.status.poll(timestamp) + if dev.status is not None: + dev.status.poll(timestamp) def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None): if _log.isEnabledFor(_DEBUG): @@ -125,8 +125,7 @@ class ReceiverListener(_listener.EventsListener): assert event.devnumber > 0 and event.devnumber <= self.receiver.max_devices already_known = event.devnumber in self.receiver dev = self.receiver[event.devnumber] - if dev: - assert dev.status is not None + if dev and dev.status is not None: dev.status.process_event(event) if self.receiver.status.lock_open and not already_known: # this should be the first event after a device was paired @@ -134,7 +133,7 @@ class ReceiverListener(_listener.EventsListener): _log.info("pairing detected new device") self.receiver.status.new_device = dev else: - _log.warn("received event %s for invalid device %d", event, event.devnumber) + _log.warn("received event %s for invalid device %d: %s", event, event.devnumber, dev) def __str__(self): return '' % (self.receiver.path, self.receiver.handle) diff --git a/app/solaar_cli.py b/app/solaar_cli.py index 390cdf7a..6839d546 100644 --- a/app/solaar_cli.py +++ b/app/solaar_cli.py @@ -216,9 +216,11 @@ def unpair_device(receiver, args): if dev is receiver: _fail("cannot unpair the receiver") + # query these + number, name, codename, serial = dev.number, dev.name, dev.codename, dev.serial try: - del receiver[dev.number] - print ("Unpaired %d: %s [%s:%s]" % (dev.number, dev.name, dev.codename, dev.serial)) + del receiver[number] + print ("Unpaired %d: %s [%s:%s]" % (number, name, codename, serial)) except Exception as e: _fail("failed to unpair device %s: %s" % (dev.name, e)) diff --git a/lib/logitech/unifying_receiver/base.py b/lib/logitech/unifying_receiver/base.py index d3a6ceb9..78515c04 100644 --- a/lib/logitech/unifying_receiver/base.py +++ b/lib/logitech/unifying_receiver/base.py @@ -318,6 +318,9 @@ def request(handle, devnumber, request_id, *params): # these replies have to match the first parameter as well if reply_data[2:3] == params[:1]: return reply_data[2:] + else: + # hm, not mathing my request, and certainly not an event + continue else: return reply_data[2:] else: diff --git a/lib/logitech/unifying_receiver/hidpp10.py b/lib/logitech/unifying_receiver/hidpp10.py index dfb9b075..e572daa9 100644 --- a/lib/logitech/unifying_receiver/hidpp10.py +++ b/lib/logitech/unifying_receiver/hidpp10.py @@ -71,7 +71,12 @@ def get_battery(device): reply = device.request(0x810D) if reply: charge = ord(reply[:1]) - return charge, None + status = ord(reply[2:3]) & 0xF0 + status = ('discharging' if status == 0x30 + else 'charging' if status == 0x50 + else 'fully charged' if status == 0x90 + else None) + return charge, status def get_serial(device): diff --git a/lib/logitech/unifying_receiver/hidpp20.py b/lib/logitech/unifying_receiver/hidpp20.py index 350cd132..9ec9341c 100644 --- a/lib/logitech/unifying_receiver/hidpp20.py +++ b/lib/logitech/unifying_receiver/hidpp20.py @@ -31,6 +31,7 @@ FEATURE = _NamedInts( BATTERY=0x1000, REPROGRAMMABLE_KEYS=0x1B00, WIRELESS=0x1D4B, + FN_TOGGLE=0x40A0, SOLAR_CHARGE=0x4301, TOUCH_MOUSE=0x6110) FEATURE._fallback = lambda x: 'unknown:%04X' % x diff --git a/lib/logitech/unifying_receiver/receiver.py b/lib/logitech/unifying_receiver/receiver.py index 6ec970e6..84d63e65 100644 --- a/lib/logitech/unifying_receiver/receiver.py +++ b/lib/logitech/unifying_receiver/receiver.py @@ -33,6 +33,7 @@ class PairedDevice(object): self._protocol = None self._wpid = None self._power_switch = None + self._polling_rate = None self._codename = None self._name = None self._kind = None @@ -58,8 +59,16 @@ class PairedDevice(object): if self._kind is None: kind = ord(pair_info[7:8]) & 0x0F self._kind = _hidpp10.DEVICE_KIND[kind] + if self._polling_rate is None: + self._polling_rate = ord(pair_info[2:3]) return self._wpid + @property + def polling_rate(self): + if self._polling_rate is None: + self.wpid, 0 + return self._polling_rate + @property def power_switch_location(self): if self._power_switch is None: diff --git a/lib/logitech/unifying_receiver/status.py b/lib/logitech/unifying_receiver/status.py index 5692e9fd..6ad9f2b3 100644 --- a/lib/logitech/unifying_receiver/status.py +++ b/lib/logitech/unifying_receiver/status.py @@ -180,6 +180,14 @@ class DeviceStatus(dict): return True + if event.sub_id == 0x04B: + if event.address == 0x01: + _log.debug("device came online? %d", event.devnumber) + self._changed(alert=ALERT.LOW, reason='powered on') + else: + _log.warn("unknown event %s", event) + return True + if event.sub_id >= 0x80: # this can't possibly be an event, can it? if _log.isEnabledFor(_DEBUG): @@ -188,6 +196,7 @@ class DeviceStatus(dict): if event.sub_id >= 0x40: _log.warn("don't know how to handle event %s", event) + return False # this must be a feature event, assuming no device has more than 0x40 features if event.sub_id >= len(self._device.features):