From 20dfc063ff4875add4fdae09fb032fad8bdc38aa Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Sun, 23 Jun 2013 19:19:32 +0200 Subject: [PATCH] initial support for performance mx leds The leds light up when we get updates about the battery level. Right now they are not (programatically) turned off. --- lib/logitech/unifying_receiver/descriptors.py | 6 +- lib/logitech/unifying_receiver/hidpp10.py | 58 +++++++++++++++++-- lib/logitech/unifying_receiver/status.py | 2 + 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/lib/logitech/unifying_receiver/descriptors.py b/lib/logitech/unifying_receiver/descriptors.py index 84c012d7..b9045cfb 100644 --- a/lib/logitech/unifying_receiver/descriptors.py +++ b/lib/logitech/unifying_receiver/descriptors.py @@ -75,6 +75,10 @@ def _D(name, codename=None, kind=None, product_id=None, protocol=None, registers codename = name.split(' ')[-1] assert codename is not None, "descriptor for %s does not have codename set" % name + if protocol is not None: + # ? 2.0 devices should not have any registers + assert protocol < 2.0 or registers is None + DEVICES[codename] = _DeviceDescriptor( name=name, kind=kind, @@ -183,7 +187,7 @@ _D('Anywhere Mouse MX', codename='Anywhere MX', # ], ) _D('Performance Mouse MX', codename='Performance MX', protocol=1.0, - registers={'battery_charge': -0x0D, 'battery_status': 0x07}, + registers={'battery_charge': -0x0D, 'battery_status': 0x07, 'leds': 0x51}, settings=[ _register_dpi(0x63, _NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))), ], diff --git a/lib/logitech/unifying_receiver/hidpp10.py b/lib/logitech/unifying_receiver/hidpp10.py index 42434937..aea534c5 100644 --- a/lib/logitech/unifying_receiver/hidpp10.py +++ b/lib/logitech/unifying_receiver/hidpp10.py @@ -81,6 +81,13 @@ PAIRING_ERRORS = _NamedInts( too_many_devices=0x03, sequence_timeout=0x06) +BATTERY_APPOX = _NamedInts( + empty = 0, + critical = 5, + low = 20, + good = 50, + full = 90) + # # functions # @@ -151,11 +158,11 @@ def parse_battery_reply_0D(level, battery_status): return charge, status def parse_battery_reply_07(level, battery_status): - charge = (90 if level == 7 # full - else 50 if level == 5 # good - else 20 if level == 3 # low - else 5 if level == 1 # critical - else 0 ) # wtf? + charge = (BATTERY_APPOX.full if level == 7 # full + else BATTERY_APPOX.good if level == 5 # good + else BATTERY_APPOX.low if level == 3 # low + else BATTERY_APPOX.critical if level == 1 # critical + else BATTERY_APPOX.empty ) # wtf? status = ('charging' if battery_status == 0x21 or battery_status == 0x25 else 'fully charged' if battery_status == 0x22 else 'discharging' if battery_status == 0x00 @@ -208,6 +215,47 @@ def get_firmware(device): return tuple(f for f in firmware if f) +def set_3leds(device, battery_level=None, charging=None, warning=None): + assert device + assert device.kind is not None + if not device.online: + return + + leds_register = device.registers.get('leds') + if leds_register is None or leds_register < 0: + return + + if battery_level is not None: + if battery_level < BATTERY_APPOX.critical: + # 1 orange, and force blink + v1, v2 = 0x22, 0x00 + warning = True + elif battery_level < BATTERY_APPOX.low: + # 1 orange + v1, v2 = 0x22, 0x00 + elif battery_level < BATTERY_APPOX.good: + # 1 green + v1, v2 = 0x20, 0x00 + elif battery_level < BATTERY_APPOX.full: + # 2 greens + v1, v2 = 0x20, 0x02 + else: + # all 3 green + v1, v2 = 0x20, 0x22 + if warning: + # set the blinking flag for the leds already set + v1 |= (v1 >> 1) + v2 |= (v2 >> 1) + elif warning: + # 1 red + v1, v2 = 0x02, 0x00 + else: + # turn off all leds + v1, v2 = 0x11, 0x11 + + write_register(device, leds_register, v1, v2) + + def get_notification_flags(device): assert device diff --git a/lib/logitech/unifying_receiver/status.py b/lib/logitech/unifying_receiver/status.py index abde0110..ff8bd150 100644 --- a/lib/logitech/unifying_receiver/status.py +++ b/lib/logitech/unifying_receiver/status.py @@ -187,6 +187,8 @@ class DeviceStatus(dict): reason = 'Battery: %d%% (%s)' % (level, status) if changed or reason: + # update the leds on the device, if any + _hidpp10.set_3leds(self._device, level, charging=charging, warning=bool(alert)) self._changed(alert=alert, reason=reason, timestamp=timestamp) def read_battery(self, timestamp=None):