From 1d8ac27614f42377419a605ec8a5951983c64713 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Thu, 1 Nov 2012 13:47:11 +0200 Subject: [PATCH] clean-up and simpler monitoring of receiver state --- app/pairing.py | 2 +- app/receiver.py | 4 +-- app/solaar.py | 30 ++++++++++------------ app/ui/__init__.py | 2 ++ app/ui/action.py | 3 +++ app/ui/main_window.py | 25 ++++++++++-------- app/ui/notify.py | 2 +- app/ui/pair_window.py | 8 +++--- lib/hidapi/hidconsole.py | 2 +- lib/logitech/unifying_receiver/api.py | 30 +++++++++++----------- lib/logitech/unifying_receiver/base.py | 30 +++++++++++----------- lib/logitech/unifying_receiver/listener.py | 2 +- 12 files changed, 74 insertions(+), 66 deletions(-) diff --git a/app/pairing.py b/app/pairing.py index 96ff9c12..1fa7c312 100644 --- a/app/pairing.py +++ b/app/pairing.py @@ -10,7 +10,7 @@ from logitech.unifying_receiver import base as _base state = None class State(object): - TICK = 300 + TICK = 400 PAIR_TIMEOUT = 60 * 1000 / TICK def __init__(self, listener): diff --git a/app/receiver.py b/app/receiver.py index 6b794b69..2627bd20 100644 --- a/app/receiver.py +++ b/app/receiver.py @@ -258,7 +258,7 @@ class ReceiverListener(_EventsListener): self.events_filter = None self.events_handler = None - self.status_changed_callback = status_changed_callback or (lambda reason=None, urgent=False: None) + self.status_changed_callback = status_changed_callback or (lambda reason, urgent=False: None) receiver.kind = receiver.name receiver.devices = {} @@ -354,7 +354,7 @@ class ReceiverListener(_EventsListener): return True def __str__(self): - return '' % (self.path, self.receiver.status) + return '' % (self.receiver.path, self.receiver.status) @classmethod def open(self, status_changed_callback=None): diff --git a/app/solaar.py b/app/solaar.py index e9eb3955..b7af4bf1 100644 --- a/app/solaar.py +++ b/app/solaar.py @@ -1,16 +1,14 @@ #!/usr/bin/env python +APPNAME = 'Solaar' __author__ = "Daniel Pavel " -__version__ = '0.5' +__version__ = '0.6' __license__ = "GPL" # # # -APPNAME = 'Solaar' - - def _parse_arguments(): import argparse arg_parser = argparse.ArgumentParser(prog=APPNAME.lower()) @@ -31,7 +29,7 @@ def _parse_arguments(): args = arg_parser.parse_args() import logging - log_level = logging.ERROR - 10 * args.verbose + log_level = logging.WARNING - 10 * args.verbose log_format='%(asctime)s %(levelname)8s [%(threadName)s] %(name)s: %(message)s' logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format) @@ -66,6 +64,7 @@ if __name__ == '__main__': window.present() import pairing + from gi.repository import Gtk, GObject listener = None notify_missing = True @@ -74,8 +73,11 @@ if __name__ == '__main__': global listener receiver = DUMMY if listener is None else listener.receiver ui.update(receiver, icon, window, reason) - if ui.notify.available and reason and urgent: - ui.notify.show(reason or receiver) + if ui.notify.available and urgent: + ui.notify.show(reason) + if not listener: + listener = None + GObject.timeout_add(3000, check_for_listener) def check_for_listener(): global listener, notify_missing @@ -85,18 +87,14 @@ if __name__ == '__main__': pairing.state = None if notify_missing: status_changed(DUMMY, True) - ui.notify.show(DUMMY) notify_missing = False - else: - # print ("opened receiver", listener, listener.receiver) - pairing.state = pairing.State(listener) - notify_missing = True - status_changed(listener.receiver, True) - return True + return True - from gi.repository import Gtk, GObject + # print ("opened receiver", listener, listener.receiver) + pairing.state = pairing.State(listener) + notify_missing = True + status_changed(listener.receiver, True) - GObject.timeout_add(5000, check_for_listener) check_for_listener() Gtk.main() diff --git a/app/ui/__init__.py b/app/ui/__init__.py index cc4308a0..17a53930 100644 --- a/app/ui/__init__.py +++ b/app/ui/__init__.py @@ -27,6 +27,8 @@ def icon_file(name): def find_children(container, *child_names): + assert container is not None + def _iterate_children(widget, names, result, count): wname = widget.get_name() if wname in names: diff --git a/app/ui/action.py b/app/ui/action.py index 6b3d4c31..d8a52002 100644 --- a/app/ui/action.py +++ b/app/ui/action.py @@ -1,3 +1,6 @@ +# +# +# from gi.repository import Gtk diff --git a/app/ui/main_window.py b/app/ui/main_window.py index 9dbd1da0..5853cb2b 100644 --- a/app/ui/main_window.py +++ b/app/ui/main_window.py @@ -183,7 +183,7 @@ def create(title, name, max_devices, systray=False): geometry = Gdk.Geometry() geometry.min_width = 320 - geometry.min_height = 20 + geometry.min_height = 32 window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE) window.set_resizable(False) @@ -206,10 +206,10 @@ def _update_receiver_box(frame, receiver): label.set_text(receiver.status_text or '') if receiver.status < STATUS.CONNECTED: - frame._device = None toolbar.set_sensitive(False) toolbar.get_children()[0].set_active(False) info_label.set_text('') + frame._device = None else: toolbar.set_sensitive(True) frame._device = receiver @@ -274,20 +274,25 @@ def _update_device_box(frame, dev): frame.set_visible(True) -def update(window, receiver, reason): - print ("update", receiver, receiver.status, reason) +def update(window, receiver, device): + print ("update", receiver, receiver.status, device) window.set_icon_name(ui.appicon(receiver.status)) vbox = window.get_child() - controls = list(vbox.get_children()) + frames = list(vbox.get_children()) - if reason == receiver: - _update_receiver_box(controls[0], receiver) + if id(device) == id(receiver): + _update_receiver_box(frames[0], receiver) + if receiver.status < STATUS.CONNECTED: + for frame in frames[1:]: + frame.set_visible(False) + frame.set_name(_PLACEHOLDER) + frame._device = None else: - frame = controls[reason.number] - if reason.status == STATUS.UNPAIRED: + frame = frames[device.number] + if device.status == STATUS.UNPAIRED: frame.set_visible(False) frame.set_name(_PLACEHOLDER) frame._device = None else: - _update_device_box(frame, reason) + _update_device_box(frame, device) diff --git a/app/ui/notify.py b/app/ui/notify.py index 5367e796..b6a479a3 100644 --- a/app/ui/notify.py +++ b/app/ui/notify.py @@ -68,7 +68,7 @@ try: logging.exception("showing %s", n) except ImportError: - logging.warn("Notify not found in gi.repository, desktop notifications are disabled") + logging.warn("desktop notifications disabled") available = False init = lambda app_title: False uninit = lambda: None diff --git a/app/ui/pair_window.py b/app/ui/pair_window.py index 5ec5c1ee..b56bb41a 100644 --- a/app/ui/pair_window.py +++ b/app/ui/pair_window.py @@ -2,7 +2,7 @@ # # -import logging +# import logging from gi.repository import (Gtk, GObject) import ui @@ -31,17 +31,17 @@ def _device_confirmed(entry, _2, trigger, assistant, page): def _finish(assistant): - logging.debug("finish %s", assistant) + # logging.debug("finish %s", assistant) assistant.destroy() def _cancel(assistant, state): - logging.debug("cancel %s", assistant) + # logging.debug("cancel %s", assistant) state.stop_scan() _finish(assistant) def _prepare(assistant, page, state): index = assistant.get_current_page() - logging.debug("prepare %s %d %s", assistant, index, page) + # logging.debug("prepare %s %d %s", assistant, index, page) if index == 0: state.reset() diff --git a/lib/hidapi/hidconsole.py b/lib/hidapi/hidconsole.py index 7356ac90..8aeea3f5 100644 --- a/lib/hidapi/hidconsole.py +++ b/lib/hidapi/hidconsole.py @@ -71,7 +71,7 @@ if __name__ == '__main__': t.start() while t.is_alive(): - line = read_packet ('?? Input: ').strip().replace(' ', '') + line = read_packet('?? Input: ').strip().replace(' ', '') if line: try: data = unhexlify(line.encode('ascii')) diff --git a/lib/logitech/unifying_receiver/api.py b/lib/logitech/unifying_receiver/api.py index 38411496..263996ab 100644 --- a/lib/logitech/unifying_receiver/api.py +++ b/lib/logitech/unifying_receiver/api.py @@ -231,7 +231,7 @@ def get_device(handle, devnumber, features=None): """ if ping(handle, devnumber): devinfo = PairedDevice(handle, devnumber) - # _log.debug("(%d) found device %s", devnumber, devinfo) + # _log.debug("found device %s", devinfo) return devinfo @@ -240,7 +240,7 @@ def get_feature_index(handle, devnumber, feature): :returns: An int, or ``None`` if the feature is not available. """ - # _log.debug("(%d) get feature index <%s:%s>", devnumber, _hex(feature), FEATURE_NAME[feature]) + # _log.debug("device %d get feature index <%s:%s>", devnumber, _hex(feature), FEATURE_NAME[feature]) if len(feature) != 2: raise ValueError("invalid feature <%s>: it must be a two-byte string" % feature) @@ -251,11 +251,11 @@ def get_feature_index(handle, devnumber, feature): if feature_index: # feature_flags = ord(reply[1:2]) & 0xE0 # if feature_flags: - # _log.debug("(%d) feature <%s:%s> has index %d: %s", + # _log.debug("device %d feature <%s:%s> has index %d: %s", # devnumber, _hex(feature), FEATURE_NAME[feature], feature_index, # ','.join([FEATURE_FLAGS[k] for k in FEATURE_FLAGS if feature_flags & k])) # else: - # _log.debug("(%d) feature <%s:%s> has index %d", devnumber, _hex(feature), FEATURE_NAME[feature], feature_index) + # _log.debug("device %d feature <%s:%s> has index %d", devnumber, _hex(feature), FEATURE_NAME[feature], feature_index) # only consider active and supported features? # if feature_flags: @@ -263,7 +263,7 @@ def get_feature_index(handle, devnumber, feature): return feature_index - _log.warn("(%d) feature <%s:%s> not supported by the device", devnumber, _hex(feature), FEATURE_NAME[feature]) + _log.warn("device %d feature <%s:%s> not supported by the device", devnumber, _hex(feature), FEATURE_NAME[feature]) raise _FeatureNotSupported(devnumber, feature) @@ -288,13 +288,13 @@ def get_device_features(handle, devnumber): Their position in the array is the index to be used when requesting that feature on the device. """ - # _log.debug("(%d) get device features", devnumber) + # _log.debug("device %d get device features", devnumber) # get the index of the FEATURE_SET # FEATURE.ROOT should always be available for all devices fs_index = _base.request(handle, devnumber, FEATURE.ROOT, FEATURE.FEATURE_SET) if fs_index is None: - # _l.warn("(%d) FEATURE_SET not available", device) + _log.warn("device %d FEATURE_SET not available", devnumber) return None fs_index = fs_index[:1] @@ -306,11 +306,11 @@ def get_device_features(handle, devnumber): if not features_count: # this can happen if the device disappeard since the fs_index request # otherwise we should get at least a count of 1 (the FEATURE_SET we've just used above) - _log.debug("(%d) no features available?!", devnumber) + _log.debug("device %d no features available?!", devnumber) return None features_count = ord(features_count[:1]) - # _log.debug("(%d) found %d features", devnumber, features_count) + # _log.debug("device %d found %d features", devnumber, features_count) features = [None] * 0x20 for index in range(1, 1 + features_count): @@ -322,11 +322,11 @@ def get_device_features(handle, devnumber): features[index] = feature # if feature_flags: - # _log.debug("(%d) feature <%s:%s> at index %d: %s", + # _log.debug("device %d feature <%s:%s> at index %d: %s", # devnumber, _hex(feature), FEATURE_NAME[feature], index, # ','.join([FEATURE_FLAGS[k] for k in FEATURE_FLAGS if feature_flags & k])) # else: - # _log.debug("(%d) feature <%s:%s> at index %d", devnumber, _hex(feature), FEATURE_NAME[feature], index) + # _log.debug("device %d feature <%s:%s> at index %d", devnumber, _hex(feature), FEATURE_NAME[feature], index) features[0] = FEATURE.ROOT while features[-1] is None: @@ -369,7 +369,7 @@ def get_device_firmware(handle, devnumber, features=None): fw_info = _FirmwareInfo(level, FIRMWARE_KIND[-1], '', '', None) fw.append(fw_info) - # _log.debug("(%d) firmware %s", devnumber, fw_info) + # _log.debug("device %d firmware %s", devnumber, fw_info) return tuple(fw) @@ -387,7 +387,7 @@ def get_device_kind(handle, devnumber, features=None): d_kind = _base.request(handle, devnumber, _pack('!BB', name_fi, 0x20)) if d_kind: d_kind = ord(d_kind[:1]) - # _log.debug("(%d) device type %d = %s", devnumber, d_kind, DEVICE_KIND[d_kind]) + # _log.debug("device %d type %d = %s", devnumber, d_kind, DEVICE_KIND[d_kind]) return DEVICE_KIND[d_kind] @@ -415,7 +415,7 @@ def get_device_name(handle, devnumber, features=None): break d_name = d_name.decode('ascii') - # _log.debug("(%d) device name %s", devnumber, d_name) + # _log.debug("device %d name %s", devnumber, d_name) return d_name @@ -429,7 +429,7 @@ def get_device_battery_level(handle, devnumber, features=None): battery = _base.request(handle, devnumber, _pack('!BB', bat_fi, 0)) if battery: discharge, dischargeNext, status = _unpack('!BBB', battery[:3]) - _log.debug("(%d) battery %d%% charged, next level %d%% charge, status %d = %s", + _log.debug("device %d battery %d%% charged, next level %d%% charge, status %d = %s", devnumber, discharge, dischargeNext, status, BATTERY_STATUS[status]) return (discharge, dischargeNext, BATTERY_STATUS[status]) diff --git a/lib/logitech/unifying_receiver/base.py b/lib/logitech/unifying_receiver/base.py index 82df116f..249ad7d3 100644 --- a/lib/logitech/unifying_receiver/base.py +++ b/lib/logitech/unifying_receiver/base.py @@ -40,7 +40,7 @@ _MAX_REPLY_SIZE = _MAX_CALL_SIZE """Default timeout on read (in ms).""" -DEFAULT_TIMEOUT = 1000 +DEFAULT_TIMEOUT = 1500 # # @@ -166,9 +166,9 @@ def write(handle, devnumber, data): assert _MAX_CALL_SIZE == 20 # the data is padded to either 5 or 18 bytes wdata = _pack('!BB18s' if len(data) > 5 else '!BB5s', 0x10, devnumber, data) - _log.debug("(%d) <= w[10 %02X %s %s]", devnumber, devnumber, _hex(wdata[2:4]), _hex(wdata[4:])) + _log.debug("<= w[10 %02X %s %s]", devnumber, _hex(wdata[2:4]), _hex(wdata[4:])) if not _hid.write(handle, wdata): - _log.warn("(%d) write failed, assuming receiver %X no longer available", devnumber, handle) + _log.warn("write failed, assuming receiver %X no longer available", handle) close(handle) raise _NoReceiver @@ -191,19 +191,19 @@ def read(handle, timeout=DEFAULT_TIMEOUT): """ data = _hid.read(handle, _MAX_REPLY_SIZE, timeout) if data is None: - _log.warn("(-) read failed, assuming receiver %X no longer available", handle) + _log.warn("read failed, assuming receiver %X no longer available", handle) close(handle) raise _NoReceiver if data: if len(data) < _MIN_REPLY_SIZE: - _log.warn("(%d) => r[%s] read packet too short: %d bytes", ord(data[1:2]), _hex(data), len(data)) + _log.warn("=> r[%s] read packet too short: %d bytes", _hex(data), len(data)) data += b'\x00' * (_MIN_REPLY_SIZE - len(data)) if len(data) > _MAX_REPLY_SIZE: - _log.warn("(%d) => r[%s] read packet too long: %d bytes", ord(data[1:2]), _hex(data), len(data)) + _log.warn("=> r[%s] read packet too long: %d bytes", _hex(data), len(data)) code = ord(data[:1]) devnumber = ord(data[1:2]) - _log.debug("(%d) => r[%02X %02X %s %s]", devnumber, code, devnumber, _hex(data[2:4]), _hex(data[4:])) + _log.debug("=> r[%02X %02X %s %s]", code, devnumber, _hex(data[2:4]), _hex(data[4:])) return code, devnumber, data[2:] # _l.log(_LOG_LEVEL, "(-) => r[]") @@ -236,7 +236,7 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None if type(params) == int: params = _pack('!B', params) - # _log.debug("(%d) request {%s} params [%s]", devnumber, _hex(feature_index_function), _hex(params)) + # _log.debug("device %d request {%s} params [%s]", devnumber, _hex(feature_index_function), _hex(params)) if len(feature_index_function) != 2: raise ValueError('invalid feature_index_function {%s}: it must be a two-byte string' % _hex(feature_index_function)) @@ -263,7 +263,7 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None if reply_devnumber != devnumber: # this message not for the device we're interested in - # _l.log(_LOG_LEVEL, "(%d) request got reply for unexpected device %d: [%s]", devnumber, reply_devnumber, _hex(reply_data)) + # _l.log(_LOG_LEVEL, "device %d request got reply for unexpected device %d: [%s]", devnumber, reply_devnumber, _hex(reply_data)) # worst case scenario, this is a reply for a concurrent request # on this receiver if _unhandled: @@ -272,18 +272,18 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None if reply_code == 0x10 and reply_data[:1] == b'\x8F' and reply_data[1:3] == feature_index_function: # device not present - _log.debug("(%d) request ping failed on {%s} call: [%s]", devnumber, _hex(feature_index_function), _hex(reply_data)) + _log.debug("device %d request ping failed on {%s} call: [%s]", devnumber, _hex(feature_index_function), _hex(reply_data)) return None if reply_code == 0x10 and reply_data[:1] == b'\x8F': # device not present - _log.debug("(%d) request ping failed: [%s]", devnumber, _hex(reply_data)) + _log.debug("request ping failed: [%s]", devnumber, _hex(reply_data)) return None if reply_code == 0x11 and reply_data[0] == b'\xFF' and reply_data[1:3] == feature_index_function: # the feature call returned with an error error_code = ord(reply_data[3]) - _log.warn("(%d) request feature call error %d = %s: %s", devnumber, error_code, ERROR_NAME[error_code], _hex(reply_data)) + _log.warn("device %d request feature call error %d = %s: %s", devnumber, error_code, ERROR_NAME[error_code], _hex(reply_data)) feature_index = ord(feature_index_function[:1]) feature_function = feature_index_function[1:2] feature = None if features is None else features[feature_index] if feature_index < len(features) else None @@ -291,14 +291,14 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None if reply_code == 0x11 and reply_data[:2] == feature_index_function: # a matching reply - # _log.debug("(%d) matched reply with feature-index-function [%s]", devnumber, _hex(reply_data[2:])) + # _log.debug("device %d matched reply with feature-index-function [%s]", devnumber, _hex(reply_data[2:])) return reply_data[2:] if reply_code == 0x10 and devnumber == 0xFF and reply_data[:2] == feature_index_function: # direct calls to the receiver (device 0xFF) may also return successfully with reply code 0x10 - # _log.debug("(%d) matched reply with feature-index-function [%s]", devnumber, _hex(reply_data[2:])) + # _log.debug("device %d matched reply with feature-index-function [%s]", devnumber, _hex(reply_data[2:])) return reply_data[2:] - # _log.debug("(%d) unmatched reply {%s} (expected {%s})", devnumber, _hex(reply_data[:2]), _hex(feature_index_function)) + # _log.debug("device %d unmatched reply {%s} (expected {%s})", devnumber, _hex(reply_data[:2]), _hex(feature_index_function)) if _unhandled: _unhandled(reply_code, reply_devnumber, reply_data) diff --git a/lib/logitech/unifying_receiver/listener.py b/lib/logitech/unifying_receiver/listener.py index a3e53264..eaf171c9 100644 --- a/lib/logitech/unifying_receiver/listener.py +++ b/lib/logitech/unifying_receiver/listener.py @@ -21,7 +21,7 @@ _log = getLogger('LUR').getChild('listener') del getLogger -_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT) # ms +_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT / 2) # ms def _event_dispatch(listener, callback): while listener._active: # or not listener._events.empty():