small clean-ups in device status handling
This commit is contained in:
parent
c22fe6320d
commit
b39016df7c
|
@ -16,24 +16,23 @@ from logitech.unifying_receiver import (Receiver,
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
class _DUMMY_RECEIVER(object):
|
|
||||||
__slots__ = []
|
|
||||||
name = Receiver.name
|
|
||||||
kind = None
|
|
||||||
max_devices = Receiver.max_devices
|
|
||||||
status = 'Receiver not found.'
|
|
||||||
__bool__ = __nonzero__ = lambda self: False
|
|
||||||
__unicode__ = __str__ = __repr__ = lambda self: 'DUMMY'
|
|
||||||
DUMMY = _DUMMY_RECEIVER()
|
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ['number', 'name', 'kind', 'status'])
|
_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ['number', 'name', 'kind', 'status', 'max_devices'])
|
||||||
|
_GHOST_DEVICE.__bool__ = lambda self: False
|
||||||
|
_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__
|
||||||
del namedtuple
|
del namedtuple
|
||||||
|
|
||||||
|
def _ghost(device):
|
||||||
|
return _GHOST_DEVICE(number=device.number, name=device.name, kind=device.kind, status=None, max_devices=None)
|
||||||
|
|
||||||
|
DUMMY = _GHOST_DEVICE(Receiver.number, Receiver.name, None, 'Receiver not found.', Receiver.max_devices)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# how often to poll devices that haven't updated their statuses on their own
|
||||||
|
# (through notifications)
|
||||||
_POLL_TICK = 60 # seconds
|
_POLL_TICK = 60 # seconds
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +45,11 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
self._last_tick = 0
|
self._last_tick = 0
|
||||||
|
|
||||||
self.status_changed_callback = status_changed_callback
|
self.status_changed_callback = status_changed_callback
|
||||||
|
|
||||||
|
# make it a bit similar with the regular devices
|
||||||
|
receiver.kind = None
|
||||||
|
# replace the
|
||||||
|
receiver.handle = _listener.ThreadedHandle(receiver.handle, receiver.path)
|
||||||
receiver.status = _status.ReceiverStatus(receiver, self._status_changed)
|
receiver.status = _status.ReceiverStatus(receiver, self._status_changed)
|
||||||
|
|
||||||
def has_started(self):
|
def has_started(self):
|
||||||
|
@ -100,9 +104,12 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
if device.status is None:
|
if device.status is None:
|
||||||
# device was unpaired, and since the object is weakref'ed
|
# device was unpaired, and since the object is weakref'ed
|
||||||
# it won't be valid for much longer
|
# it won't be valid for much longer
|
||||||
device = _GHOST_DEVICE(number=device.number, name=device.name, kind=device.kind, status=None)
|
device = _ghost(device)
|
||||||
|
|
||||||
self.status_changed_callback(r, device, alert, reason)
|
self.status_changed_callback(r, device, alert, reason)
|
||||||
|
|
||||||
if device.status is None:
|
if device.status is None:
|
||||||
|
# the receiver changed status as well
|
||||||
self.status_changed_callback(r)
|
self.status_changed_callback(r)
|
||||||
|
|
||||||
def _notifications_handler(self, n):
|
def _notifications_handler(self, n):
|
||||||
|
@ -117,21 +124,25 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
already_known = n.devnumber in self.receiver
|
already_known = n.devnumber in self.receiver
|
||||||
dev = self.receiver[n.devnumber]
|
dev = self.receiver[n.devnumber]
|
||||||
|
|
||||||
if dev and not already_known:
|
if not dev:
|
||||||
|
_log.warn("received %s for invalid device %d: %s", n, n.devnumber, repr(dev))
|
||||||
|
return
|
||||||
|
|
||||||
|
if not already_known:
|
||||||
# read these as soon as possible, they will be used everywhere
|
# read these as soon as possible, they will be used everywhere
|
||||||
dev.protocol, dev.codename
|
dev.protocol, dev.codename
|
||||||
dev.status = _status.DeviceStatus(dev, self._status_changed)
|
dev.status = _status.DeviceStatus(dev, self._status_changed)
|
||||||
|
# the receiver changed status as well
|
||||||
self._status_changed(self.receiver)
|
self._status_changed(self.receiver)
|
||||||
|
|
||||||
if dev and dev.status is not None:
|
# status may be None if the device has just been unpaired
|
||||||
|
if dev.status is not None:
|
||||||
dev.status.process_notification(n)
|
dev.status.process_notification(n)
|
||||||
if self.receiver.status.lock_open and not already_known:
|
if self.receiver.status.lock_open and not already_known:
|
||||||
# this should be the first notification after a device was paired
|
# this should be the first notification after a device was paired
|
||||||
assert n.sub_id == 0x41 and n.address == 0x04
|
assert n.sub_id == 0x41 and n.address == 0x04
|
||||||
_log.info("pairing detected new device")
|
_log.info("pairing detected new device")
|
||||||
self.receiver.status.new_device = dev
|
self.receiver.status.new_device = dev
|
||||||
else:
|
|
||||||
_log.warn("received notification %s for invalid device %d: %s", n, n.devnumber, dev)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '<ReceiverListener(%s,%s)>' % (self.receiver.path, self.receiver.handle)
|
return '<ReceiverListener(%s,%s)>' % (self.receiver.path, self.receiver.handle)
|
||||||
|
@ -141,8 +152,6 @@ class ReceiverListener(_listener.EventsListener):
|
||||||
def open(self, status_changed_callback=None):
|
def open(self, status_changed_callback=None):
|
||||||
receiver = Receiver.open()
|
receiver = Receiver.open()
|
||||||
if receiver:
|
if receiver:
|
||||||
receiver.handle = _listener.ThreadedHandle(receiver.handle, receiver.path)
|
|
||||||
receiver.kind = None
|
|
||||||
rl = ReceiverListener(receiver, status_changed_callback)
|
rl = ReceiverListener(receiver, status_changed_callback)
|
||||||
rl.start()
|
rl.start()
|
||||||
return rl
|
return rl
|
||||||
|
|
|
@ -183,6 +183,7 @@ def update(frame):
|
||||||
return
|
return
|
||||||
|
|
||||||
device_active = bool(device.status)
|
device_active = bool(device.status)
|
||||||
|
# if the device just became active, re-read the settings
|
||||||
force_read |= device_active and not box.get_sensitive()
|
force_read |= device_active and not box.get_sensitive()
|
||||||
box.set_sensitive(device_active)
|
box.set_sensitive(device_active)
|
||||||
if device_active:
|
if device_active:
|
||||||
|
|
|
@ -424,10 +424,10 @@ def update(window, receiver, device=None):
|
||||||
frames = list(vbox.get_children())
|
frames = list(vbox.get_children())
|
||||||
assert len(frames) == 1 + receiver.max_devices, frames
|
assert len(frames) == 1 + receiver.max_devices, frames
|
||||||
|
|
||||||
if device:
|
if device is None:
|
||||||
_update_device_box(frames[device.number], None if device.status is None else device)
|
|
||||||
else:
|
|
||||||
_update_receiver_box(frames[0], receiver)
|
_update_receiver_box(frames[0], receiver)
|
||||||
if not receiver:
|
if not receiver:
|
||||||
for frame in frames[1:]:
|
for frame in frames[1:]:
|
||||||
_update_device_box(frame, None)
|
_update_device_box(frame, None)
|
||||||
|
else:
|
||||||
|
_update_device_box(frames[device.number], None if device.status is None else device)
|
||||||
|
|
|
@ -78,7 +78,7 @@ def _icon_with_battery(level, active):
|
||||||
|
|
||||||
def update(icon, receiver, device=None):
|
def update(icon, receiver, device=None):
|
||||||
# print ("icon update", receiver, receiver.status, len(receiver), device)
|
# print ("icon update", receiver, receiver.status, len(receiver), device)
|
||||||
if device:
|
if device is not None:
|
||||||
icon._devices[device.number] = None if device.status is None else device
|
icon._devices[device.number] = None if device.status is None else device
|
||||||
if not receiver:
|
if not receiver:
|
||||||
icon._devices[:] = _NO_DEVICES
|
icon._devices[:] = _NO_DEVICES
|
||||||
|
|
|
@ -148,11 +148,11 @@ class EventsListener(_threading.Thread):
|
||||||
|
|
||||||
if n:
|
if n:
|
||||||
# if _log.isEnabledFor(_DEBUG):
|
# if _log.isEnabledFor(_DEBUG):
|
||||||
# _log.debug("processing notification %s", n)
|
# _log.debug("processing %s", n)
|
||||||
try:
|
try:
|
||||||
self._notifications_callback(n)
|
self._notifications_callback(n)
|
||||||
except:
|
except:
|
||||||
_log.exception("processing notification %s", n)
|
_log.exception("processing %s", n)
|
||||||
elif self.tick_period:
|
elif self.tick_period:
|
||||||
idle_reads += 1
|
idle_reads += 1
|
||||||
if idle_reads % _IDLE_READS == 0:
|
if idle_reads % _IDLE_READS == 0:
|
||||||
|
@ -189,7 +189,7 @@ class EventsListener(_threading.Thread):
|
||||||
# i.e. triggered by a callback handling a previous notification.
|
# i.e. triggered by a callback handling a previous notification.
|
||||||
if self._active and _threading.current_thread() == self:
|
if self._active and _threading.current_thread() == self:
|
||||||
if _log.isEnabledFor(_DEBUG):
|
if _log.isEnabledFor(_DEBUG):
|
||||||
_log.debug("queueing unhandled notification %s", n)
|
_log.debug("queueing unhandled %s", n)
|
||||||
self._queued_notifications.put(n)
|
self._queued_notifications.put(n)
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
|
|
|
@ -176,26 +176,14 @@ class PairedDevice(object):
|
||||||
return self.number
|
return self.number
|
||||||
__int__ = __index__
|
__int__ = __index__
|
||||||
|
|
||||||
def __lt__(self, other):
|
|
||||||
return self.number < other.number
|
|
||||||
|
|
||||||
def __le__(self, other):
|
|
||||||
return self.number <= other.number
|
|
||||||
|
|
||||||
def __gt__(self, other):
|
|
||||||
return self.number > other.number
|
|
||||||
|
|
||||||
def __ge__(self, other):
|
|
||||||
return self.number >= other.number
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.receiver == other.receiver and self.number == other.number
|
return self.serial == other.serial
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return self.receiver != other.receiver or self.number != other.number
|
return self.serial != other.serial
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return self.number
|
return self.serial.__hash__()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '<PairedDevice(%d,%s)>' % (self.number, self.codename or '?')
|
return '<PairedDevice(%d,%s)>' % (self.number, self.codename or '?')
|
||||||
|
@ -210,6 +198,7 @@ class Receiver(object):
|
||||||
|
|
||||||
The paired devices are available through the sequence interface.
|
The paired devices are available through the sequence interface.
|
||||||
"""
|
"""
|
||||||
|
number = 0xFF
|
||||||
name = 'Unifying Receiver'
|
name = 'Unifying Receiver'
|
||||||
kind = None
|
kind = None
|
||||||
max_devices = MAX_PAIRED_DEVICES
|
max_devices = MAX_PAIRED_DEVICES
|
||||||
|
@ -220,7 +209,6 @@ class Receiver(object):
|
||||||
assert path
|
assert path
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
self.number = 0xFF
|
|
||||||
self._serial = None
|
self._serial = None
|
||||||
self._firmware = None
|
self._firmware = None
|
||||||
self._devices = {}
|
self._devices = {}
|
||||||
|
|
|
@ -186,11 +186,7 @@ class DeviceStatus(dict):
|
||||||
if n.sub_id >= 0x40:
|
if n.sub_id >= 0x40:
|
||||||
return self._process_hidpp10_notification(n)
|
return self._process_hidpp10_notification(n)
|
||||||
|
|
||||||
# if n.sub_id >= len(self._device.features):
|
# assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications
|
||||||
# _log.warn("%s: notification from invalid feature index %02X", self._device, n.sub_id)
|
|
||||||
# return False
|
|
||||||
|
|
||||||
# assuming 0x00 to 0x3F are device feature (HID++ 2.0) notifications
|
|
||||||
try:
|
try:
|
||||||
feature = self._device.features[n.sub_id]
|
feature = self._device.features[n.sub_id]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|
Loading…
Reference in New Issue