diff --git a/lib/logitech_receiver/listener.py b/lib/logitech_receiver/listener.py index 3f665ba7..c00a81b8 100644 --- a/lib/logitech_receiver/listener.py +++ b/lib/logitech_receiver/listener.py @@ -150,7 +150,7 @@ class EventsListener(_threading.Thread): # replace the handle with a threaded one self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle) - # get the right low-level handle for this thead + # get the right low-level handle for this thread ihandle = int(self.receiver.handle) if _log.isEnabledFor(_INFO): _log.info("started with %s (%d)", self.receiver, ihandle) diff --git a/lib/logitech_receiver/notifications.py b/lib/logitech_receiver/notifications.py index 376e7567..f9b7e4a7 100644 --- a/lib/logitech_receiver/notifications.py +++ b/lib/logitech_receiver/notifications.py @@ -164,14 +164,14 @@ def _process_hidpp10_notification(device, status, n): assert wpid == device.wpid, "%s wpid mismatch, got %s" % (device, wpid) flags = ord(n.data[:1]) & 0xF0 - link_encrypyed = bool(flags & 0x20) + link_encrypted = bool(flags & 0x20) link_established = not (flags & 0x40) if _log.isEnabledFor(_DEBUG): sw_present = bool(flags & 0x10) has_payload = bool(flags & 0x80) _log.debug("%s: %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s", - device, protocol_name, sw_present, link_encrypyed, link_established, has_payload) - status[_K.LINK_ENCRYPTED] = link_encrypyed + device, protocol_name, sw_present, link_encrypted, link_established, has_payload) + status[_K.LINK_ENCRYPTED] = link_encrypted status.changed(active=link_established) else: _log.warn("%s: connection notification with unknown protocol %02X: %s", device.number, n.address, n) diff --git a/lib/logitech_receiver/status.py b/lib/logitech_receiver/status.py index e55381f6..5dbe3614 100644 --- a/lib/logitech_receiver/status.py +++ b/lib/logitech_receiver/status.py @@ -67,10 +67,11 @@ def attach_to(device, changed_callback): assert device assert changed_callback - if device.kind is None: - device.status = ReceiverStatus(device, changed_callback) - else: - device.status = DeviceStatus(device, changed_callback) + if not hasattr(device, 'status') or device.status is None: + if device.kind is None: + device.status = ReceiverStatus(device, changed_callback) + else: + device.status = DeviceStatus(device, changed_callback) # # diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py index 04efd436..88318527 100644 --- a/lib/solaar/listener.py +++ b/lib/solaar/listener.py @@ -18,6 +18,7 @@ ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from __future__ import absolute_import, division, print_function, unicode_literals +import time from logging import getLogger, INFO as _INFO _log = getLogger(__name__) @@ -181,11 +182,20 @@ class ReceiverListener(_listener.EventsListener): return # a device notification - assert n.devnumber > 0 and n.devnumber <= self.receiver.max_devices + assert 0 < n.devnumber <= self.receiver.max_devices already_known = n.devnumber in self.receiver - if n.sub_id == 0x41: - already_known = False + # FIXME: hacky fix for kernel/hardware race condition + # If the device was just turned on or woken up from sleep, it may not + # be ready to receive commands. The "payload" bit of the wireless + # status notification seems to tell us this. If this is the case, we + # must wait a short amount of time to avoid causing a broken pipe + # error. + device_ready = not bool(ord(n.data[0:1]) & 0x80) or n.sub_id != 0x41 + if not device_ready: + time.sleep(0.01) + + if n.sub_id == 0x41 and not already_known: dev = self.receiver.register_new_device(n.devnumber, n) else: dev = self.receiver[n.devnumber] @@ -194,7 +204,8 @@ class ReceiverListener(_listener.EventsListener): _log.warn("%s: received %s for invalid device %d: %r", self.receiver, n, n.devnumber, dev) return - if not already_known: + # Apply settings every time the device connects + if n.sub_id == 0x41: if _log.isEnabledFor(_INFO): _log.info("%s triggered new device %s (%s)", n, dev, dev.kind) # If there are saved configs, bring the device's settings up-to-date. @@ -213,8 +224,7 @@ class ReceiverListener(_listener.EventsListener): if _log.isEnabledFor(_INFO): _log.info("%s: pairing detected new device", self.receiver) self.receiver.status.new_device = dev - elif dev: - if dev.online is None: + elif dev.online is None: dev.ping() def __str__(self): diff --git a/lib/solaar/async.py b/lib/solaar/tasks.py similarity index 100% rename from lib/solaar/async.py rename to lib/solaar/tasks.py diff --git a/lib/solaar/ui/__init__.py b/lib/solaar/ui/__init__.py index 3f64e83f..84285950 100644 --- a/lib/solaar/ui/__init__.py +++ b/lib/solaar/ui/__init__.py @@ -75,7 +75,7 @@ def error_dialog(reason, object): # _task_runner = None -def async(function, *args, **kwargs): +def ui_async(function, *args, **kwargs): if _task_runner: _task_runner(function, *args, **kwargs) @@ -90,7 +90,7 @@ def _startup(app, startup_hook): if _log.isEnabledFor(_DEBUG): _log.debug("startup registered=%s, remote=%s", app.get_is_registered(), app.get_is_remote()) - from solaar.async import TaskRunner as _TaskRunner + from solaar.tasks import TaskRunner as _TaskRunner global _task_runner _task_runner = _TaskRunner('AsyncUI') _task_runner.start() diff --git a/lib/solaar/ui/config_panel.py b/lib/solaar/ui/config_panel.py index 75f9a2c3..151b61c2 100644 --- a/lib/solaar/ui/config_panel.py +++ b/lib/solaar/ui/config_panel.py @@ -23,7 +23,7 @@ from gi.repository import Gtk, GLib from threading import Timer as _Timer from solaar.i18n import _ -from solaar.ui import async as _ui_async +from solaar.ui import ui_async as _ui_async from logitech_receiver.settings import KIND as _SETTING_KIND # diff --git a/lib/solaar/ui/window.py b/lib/solaar/ui/window.py index 6e27e095..8697fc73 100644 --- a/lib/solaar/ui/window.py +++ b/lib/solaar/ui/window.py @@ -31,7 +31,7 @@ from solaar import NAME from solaar.i18n import _ from gettext import ngettext # from solaar import __version__ as VERSION -from solaar.ui import async as _ui_async +from solaar.ui import ui_async as _ui_async from logitech_receiver import hidpp10 as _hidpp10 from logitech_receiver.common import NamedInts as _NamedInts, NamedInt as _NamedInt from logitech_receiver.status import KEYS as _K