diff --git a/lib/logitech/unifying_receiver/common.py b/lib/logitech/unifying_receiver/common.py index 419733c3..df729e6a 100644 --- a/lib/logitech/unifying_receiver/common.py +++ b/lib/logitech/unifying_receiver/common.py @@ -8,11 +8,10 @@ from struct import pack as _pack class NamedInt(int): """An integer with an attached name.""" - # __slots__ = ['name'] def __new__(cls, value, name): obj = int.__new__(cls, value) - obj.name = name + obj.name = str(name) return obj def bytes(self, count=2): @@ -22,6 +21,17 @@ class NamedInt(int): return _pack('!L', value)[-count:] + def __eq__(self, other): + try: + if int(self) == int(other): + return True + except: + pass + return self.name.lower() == str(other).lower() + + def __cmp__(self, other): + return int(self) - int(other) + def __str__(self): return self.name @@ -30,30 +40,50 @@ class NamedInt(int): class NamedInts(object): + __slots__ = ['__dict__', '_values', '_indexed', '_fallback'] + def __init__(self, **kwargs): - values = dict((k, NamedInt(v, k if k == k.upper() else k.replace('__', '/').replace('_', ' '))) for (k, v) in kwargs.items()) - self.__dict__.update(values) - self._indexed = dict((int(v), v) for v in values.values()) + values = dict((k, NamedInt(v, k.lstrip('_') if k == k.upper() else + k.replace('__', '/').replace('_', ' '))) for (k, v) in kwargs.items()) + self.__dict__ = values + self._values = sorted(list(values.values())) + self._indexed = dict((int(v), v) for v in self._values) self._fallback = None - def __getitem__(self, index): - if index in self._indexed: - return self._indexed[index] - - if self._fallback: - value = NamedInt(index, self._fallback(index)) - self._indexed[index] = value - return value - - def __contains__(self, value): - return int(value) in self._indexed - - def __len__(self): - return len(self.values) - def flag_names(self, value): return ', '.join(str(self._indexed[k]) for k in self._indexed if k & value == k) + def __getitem__(self, index): + if type(index) == int: + if index in self._indexed: + return self._indexed[index] + + if self._fallback: + value = NamedInt(index, self._fallback(index)) + self._indexed[index] = value + self._values = sorted(self._values + [value]) + return value + + elif type(index) == slice: + return self._values[index] + + else: + if index in self._values: + index = self._values.index(index) + return self._values[index] + + def __contains__(self, value): + return value in self._values + + def __iter__(self): + return iter(sorted(self._values)) + + def __len__(self): + return len(self._values) + + def __repr__(self): + return 'NamedInts(%s)' % ', '.join(repr(v) for v in self._values) + def strhex(x): return _hexlify(x).decode('ascii').upper() diff --git a/lib/logitech/unifying_receiver/hidpp10.py b/lib/logitech/unifying_receiver/hidpp10.py index e572daa9..ffd3478f 100644 --- a/lib/logitech/unifying_receiver/hidpp10.py +++ b/lib/logitech/unifying_receiver/hidpp10.py @@ -57,10 +57,6 @@ PAIRING_ERRORS = _NamedInts( too_many_devices=0x03, sequence_timeout=0x06) -REGISTERS = _NamedInts( - battery=0x0D, - dpi=0x63, - leds=0x51) # # functions diff --git a/lib/logitech/unifying_receiver/hidpp20.py b/lib/logitech/unifying_receiver/hidpp20.py index 9ec9341c..0b99eb7b 100644 --- a/lib/logitech/unifying_receiver/hidpp20.py +++ b/lib/logitech/unifying_receiver/hidpp20.py @@ -31,7 +31,7 @@ FEATURE = _NamedInts( BATTERY=0x1000, REPROGRAMMABLE_KEYS=0x1B00, WIRELESS=0x1D4B, - FN_TOGGLE=0x40A0, + FN_STATUS=0x40A0, SOLAR_CHARGE=0x4301, TOUCH_MOUSE=0x6110) FEATURE._fallback = lambda x: 'unknown:%04X' % x @@ -80,7 +80,7 @@ KEY = _NamedInts( Calculator=0x000A, Mail=0x000E, Home=0x001A, - Tools=0x001D, + Music=0x001D, Search=0x0029, Sleep=0x002F) KEY._fallback = lambda x: 'unknown:%04X' % x diff --git a/lib/logitech/unifying_receiver/receiver.py b/lib/logitech/unifying_receiver/receiver.py index ee0bf13c..9651bec2 100644 --- a/lib/logitech/unifying_receiver/receiver.py +++ b/lib/logitech/unifying_receiver/receiver.py @@ -118,7 +118,7 @@ class PairedDevice(object): p = self.protocol if p >= 2.0: self._firmware = _hidpp20.get_firmware(self) - elif p >= 1.0: + if self._firmware is None and p == 1.0: self._firmware = _hidpp10.get_firmware(self) return self._firmware or () diff --git a/lib/logitech/unifying_receiver/status.py b/lib/logitech/unifying_receiver/status.py index 6ad9f2b3..901ad637 100644 --- a/lib/logitech/unifying_receiver/status.py +++ b/lib/logitech/unifying_receiver/status.py @@ -106,7 +106,7 @@ class DeviceStatus(dict): return ', '.join(t) def __bool__(self): - return self.updated and self._active + return bool(self._active) __nonzero__ = __bool__ def _changed(self, active=True, alert=ALERT.NONE, reason=None, timestamp=None): @@ -131,13 +131,20 @@ class DeviceStatus(dict): d.protocol, d.serial, d.firmware if BATTERY_LEVEL not in self: - if d.protocol >= 2.0: + battery = _hidpp10.get_battery(d) + if battery is None and d.protocol >= 2.0: battery = _hidpp20.get_battery(d) - else: - battery = _hidpp10.get_battery(d) + + # if battery is None and _hidpp20.FEATURE.SOLAR_CHARGE in d.features: + # d.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE, 0x00, 1, 1) + # return + if battery: self[BATTERY_LEVEL], self[BATTERY_STATUS] = battery self._changed(timestamp=timestamp) + elif BATTERY_STATUS in self: + self[BATTERY_STATUS] = None + self._changed(timestamp=timestamp) elif len(self) > 0 and timestamp - self.updated > _STATUS_TIMEOUT: # if the device has been inactive for too long, clear out any known @@ -191,7 +198,7 @@ class DeviceStatus(dict): if event.sub_id >= 0x80: # this can't possibly be an event, can it? if _log.isEnabledFor(_DEBUG): - _log.debug("ignoring non-event %s", event) + _log.debug("ignoring %s (not an event)", event) return False if event.sub_id >= 0x40: