From 89c6904d6929064ee07f21918751abdd4bdaf585 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Fri, 30 Nov 2012 20:28:22 +0200 Subject: [PATCH] fixed pairing (again), this time also tested it --- app/listener.py | 31 +++++++++++++++++----- app/ui/main_window.py | 7 ++--- app/ui/pair_window.py | 8 ++++-- lib/logitech/unifying_receiver/listener.py | 3 ++- lib/logitech/unifying_receiver/receiver.py | 3 ++- lib/logitech/unifying_receiver/status.py | 7 +++++ 6 files changed, 45 insertions(+), 14 deletions(-) diff --git a/app/listener.py b/app/listener.py index d24ba9b1..ea74b2ff 100644 --- a/app/listener.py +++ b/app/listener.py @@ -21,6 +21,7 @@ class _DUMMY_RECEIVER(object): # __slots__ = ['name', 'max_devices', 'status'] __slots__ = [] name = Receiver.name + kind = None max_devices = Receiver.max_devices status = 'Receiver not found.' __bool__ = __nonzero__ = lambda self: False @@ -31,8 +32,8 @@ DUMMY = _DUMMY_RECEIVER() # # -_DEVICE_TIMEOUT = 3 * 60 # seconds -_DEVICE_STATUS_POLL = 60 # seconds +_DEVICE_STATUS_POLL = 30 # seconds +_DEVICE_TIMEOUT = 2 * _DEVICE_STATUS_POLL # seconds # def _fake_device(listener): # dev = _lur.PairedDevice(listener.receiver, 6) @@ -51,6 +52,7 @@ class ReceiverListener(_listener.EventsListener): def __init__(self, receiver, status_changed_callback=None): super(ReceiverListener, self).__init__(receiver, self._events_handler) self.tick_period = _DEVICE_STATUS_POLL + self._last_tick = 0 self.status_changed_callback = status_changed_callback @@ -58,11 +60,15 @@ class ReceiverListener(_listener.EventsListener): Receiver.create_device = self.create_device def create_device(self, receiver, number): - dev = PairedDevice(receiver, number) - dev.status = _status.DeviceStatus(dev, self._status_changed) - return dev + if bool(self): + dev = PairedDevice(receiver, number) + if dev.wpid: + dev.status = _status.DeviceStatus(dev, self._status_changed) + _log.info("new device %s", dev) + return dev def has_started(self): + _log.info("events listener has started") # self._status_changed(self.receiver) self.receiver.enable_notifications() @@ -78,6 +84,7 @@ class ReceiverListener(_listener.EventsListener): self._status_changed(self.receiver, _status.ALERT.LOW) def has_stopped(self): + _log.info("events listener has stopped") if self.receiver: self.receiver.enable_notifications(False) self.receiver.close() @@ -89,6 +96,14 @@ class ReceiverListener(_listener.EventsListener): if _log.isEnabledFor(_DEBUG): _log.debug("tick: polling status: %s %s", self.receiver, self.receiver._devices) + if self._last_tick > 0 and timestamp - self._last_tick > _DEVICE_STATUS_POLL * 2: + # if we missed a couple of polls, most likely the computer went into + # sleep, and we have to reinitialize the receiver again + _log.warn("possible sleep detected, closing this listener") + self.stop() + return + self._last_tick = timestamp + # read these in case they haven't been read already self.receiver.serial, self.receiver.firmware @@ -137,8 +152,10 @@ class ReceiverListener(_listener.EventsListener): dev.status.process_event(event) else: if self.receiver.status.lock_open: - assert event.sub_id == 0x41 - self.receiver.status.new_device = dev + assert event.sub_id == 0x41 and event.address == 0x04 + _log.info("pairing detected new device") + dev = self.receiver.status.device_paired(event.devnumber) + dev.status.process_event(event) else: _log.warn("received event %s for invalid device %d", event, event.devnumber) diff --git a/app/ui/main_window.py b/app/ui/main_window.py index 79dc14d8..22007624 100644 --- a/app/ui/main_window.py +++ b/app/ui/main_window.py @@ -268,7 +268,7 @@ def _update_receiver_info_label(label, dev): def _toggle_info_box(action, label_widget, box_widget, frame, update_function): if action.get_active(): box_widget.set_visible(True) - GObject.timeout_add(50, update_function, label_widget, frame._device) + GObject.timeout_add(60, update_function, label_widget, frame._device) else: box_widget.set_visible(False) @@ -309,7 +309,7 @@ def _update_receiver_box(frame, receiver): def _update_device_box(frame, dev): # print (dev.name, dev.kind) - icon, label, info_label = ui.find_children(frame, 'icon', 'label', 'info-label') + icon, label, toolbar, info_label = ui.find_children(frame, 'icon', 'label', 'toolbar', 'info-label') first_run = frame.get_name() != dev.name if first_run: @@ -318,6 +318,7 @@ def _update_device_box(frame, dev): icon_set = ui.device_icon_set(dev.name, dev.kind) icon.set_from_icon_set(icon_set, _DEVICE_ICON_SIZE) label.set_markup('' + dev.name + '') + toolbar.get_children()[0].set_active(False) status_icons = ui.find_children(frame, 'status').get_children() battery_icon, battery_label, light_icon, light_label, not_encrypted_icon = status_icons[0:5] @@ -384,7 +385,7 @@ def update(window, receiver, device=None): if device is None: _update_receiver_box(frames[0], receiver) - if not receiver.status: + if not receiver: for frame in frames[1:]: frame.set_visible(False) frame.set_name(_PLACEHOLDER) diff --git a/app/ui/pair_window.py b/app/ui/pair_window.py index 81683192..3b4e1713 100644 --- a/app/ui/pair_window.py +++ b/app/ui/pair_window.py @@ -75,7 +75,11 @@ def _check_lock_state(assistant, receiver): _pairing_succeeded(assistant, receiver) return False - return receiver.status.lock_open + if not receiver.status.lock_open: + _pairing_failed(assistant, receiver, 'failed to open pairing lock') + return False + + return True def _prepare(assistant, page, receiver): @@ -89,7 +93,7 @@ def _prepare(assistant, page, receiver): assert receiver.status.get(_status.ERROR) is None spinner = page.get_children()[-1] spinner.start() - GObject.timeout_add(300, _check_lock_state, assistant, receiver) + GObject.timeout_add(500, _check_lock_state, assistant, receiver) assistant.set_page_complete(page, True) else: GObject.idle_add(_pairing_failed, assistant, receiver, 'the pairing lock did not open') diff --git a/lib/logitech/unifying_receiver/listener.py b/lib/logitech/unifying_receiver/listener.py index e7089d4c..ed219e2c 100644 --- a/lib/logitech/unifying_receiver/listener.py +++ b/lib/logitech/unifying_receiver/listener.py @@ -166,7 +166,8 @@ class EventsListener(_threading.Thread): # only consider unhandled events that were sent from this thread, # i.e. triggered during a callback of a previous event if self._active and _threading.current_thread() == self: - _log.info("queueing unhandled event %s", event) + if _log.isEnabledFor(_DEBUG): + _log.debug("queueing unhandled event %s", event) self._queued_events.put(event) def __bool__(self): diff --git a/lib/logitech/unifying_receiver/receiver.py b/lib/logitech/unifying_receiver/receiver.py index d1b77f2a..18bda89d 100644 --- a/lib/logitech/unifying_receiver/receiver.py +++ b/lib/logitech/unifying_receiver/receiver.py @@ -166,6 +166,7 @@ class Receiver(object): The paired devices are available through the sequence interface. """ name = 'Unifying Receiver' + kind = None max_devices = MAX_PAIRED_DEVICES create_device = PairedDevice @@ -271,7 +272,7 @@ class Receiver(object): raise IndexError(key) dev = Receiver.create_device(self, key) - if dev.wpid: + if dev is not None and dev.wpid: self._devices[key] = dev return dev diff --git a/lib/logitech/unifying_receiver/status.py b/lib/logitech/unifying_receiver/status.py index 67dca961..d3dd1579 100644 --- a/lib/logitech/unifying_receiver/status.py +++ b/lib/logitech/unifying_receiver/status.py @@ -50,6 +50,13 @@ class ReceiverStatus(dict): '1 device found.' if count == 1 else '%d devices found.' % count) + def device_paired(self, number): + _log.info("new device paired") + dev = self._receiver.create_device(self._receiver, number) + self._receiver._devices[number] = dev + self.new_device = dev + return dev + def _changed(self, alert=ALERT.LOW, reason=None): # self.updated = _timestamp() self._changed_callback(self._receiver, alert=alert, reason=reason)