clean-up and simpler monitoring of receiver state
This commit is contained in:
parent
a8a72f7ae5
commit
1d8ac27614
|
@ -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):
|
||||
|
|
|
@ -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 '<ReceiverListener(%s,%d)>' % (self.path, self.receiver.status)
|
||||
return '<ReceiverListener(%s,%d)>' % (self.receiver.path, self.receiver.status)
|
||||
|
||||
@classmethod
|
||||
def open(self, status_changed_callback=None):
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
APPNAME = 'Solaar'
|
||||
__author__ = "Daniel Pavel <daniel.pavel@gmail.com>"
|
||||
__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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#
|
||||
#
|
||||
#
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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():
|
||||
|
|
Loading…
Reference in New Issue