pairing fixes
This commit is contained in:
parent
932a015e49
commit
ab5e09db93
|
|
@ -28,7 +28,7 @@ DUMMY = _DUMMY_RECEIVER()
|
|||
_DEVICE_TIMEOUT = 3 * 60 # seconds
|
||||
_DEVICE_STATUS_POLL = 60 # seconds
|
||||
|
||||
# def fake_device(listener):
|
||||
# def _fake_device(listener):
|
||||
# dev = _lur.PairedDevice(listener.receiver, 6)
|
||||
# dev._wpid = '1234'
|
||||
# dev._kind = 'touchpad'
|
||||
|
|
@ -64,7 +64,7 @@ class ReceiverListener(_lur.listener.EventsListener):
|
|||
dev.codename, dev.kind, dev.name
|
||||
# dev.status._changed(dev.protocol > 0)
|
||||
|
||||
# fake = fake_device(self)
|
||||
# fake = _fake_device(self)
|
||||
# self.receiver._devices[fake.number] = fake
|
||||
# self._status_changed(fake, _lur.status.ALERT.LOW)
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class ReceiverListener(_lur.listener.EventsListener):
|
|||
|
||||
def tick(self, timestamp):
|
||||
if _log.isEnabledFor(_DEBUG):
|
||||
_log.debug("tick: polling status")
|
||||
_log.debug("tick: polling status: %s %s", self.receiver, self.receiver._devices)
|
||||
|
||||
# read these in case they haven't been read already
|
||||
self.receiver.serial, self.receiver.firmware
|
||||
|
|
@ -130,8 +130,7 @@ class ReceiverListener(_lur.listener.EventsListener):
|
|||
if dev.status is not None and dev.status.process_event(event):
|
||||
if self.receiver.status.lock_open and not known_device:
|
||||
assert event.sub_id == 0x41
|
||||
self.receiver.pairing_result = dev
|
||||
return
|
||||
self.receiver.status.new_device = dev
|
||||
else:
|
||||
_log.warn("received event %s for invalid device %d", event, event.devnumber)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ def _make_receiver_box(name):
|
|||
|
||||
icon_name = ui.get_icon(name, 'preferences-desktop-peripherals')
|
||||
icon = Gtk.Image.new_from_icon_name(icon_name, _RECEIVER_ICON_SIZE)
|
||||
icon.set_name('icon')
|
||||
icon.set_padding(2, 2)
|
||||
|
||||
label = Gtk.Label('Scanning...')
|
||||
|
|
@ -272,20 +273,21 @@ def _toggle_info_box(action, label_widget, box_widget, frame, update_function):
|
|||
|
||||
|
||||
def _update_receiver_box(frame, receiver):
|
||||
label, pairing_icon, toolbar, info_label = ui.find_children(frame, 'label', 'pairing-icon', 'toolbar', 'info-label')
|
||||
icon, label, pairing_icon, toolbar, info_label = ui.find_children(frame, 'icon', 'label', 'pairing-icon', 'toolbar', 'info-label')
|
||||
|
||||
if receiver.status is None:
|
||||
label.set_text(str(receiver.status))
|
||||
if receiver:
|
||||
frame._device = receiver
|
||||
icon.set_sensitive(True)
|
||||
pairing_icon.set_visible(receiver.status.lock_open)
|
||||
toolbar.set_visible(True)
|
||||
else:
|
||||
frame._device = None
|
||||
label.set_text('No receiver found.')
|
||||
icon.set_sensitive(False)
|
||||
pairing_icon.set_visible(False)
|
||||
toolbar.set_visible(False)
|
||||
toolbar.get_children()[0].set_active(False)
|
||||
info_label.set_text('')
|
||||
else:
|
||||
frame._device = receiver
|
||||
label.set_text(str(receiver.status))
|
||||
pairing_icon.set_visible(receiver.status.lock_open)
|
||||
toolbar.set_visible(True)
|
||||
|
||||
|
||||
def _update_device_box(frame, dev):
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import logging
|
|||
from gi.repository import (Gtk, GObject)
|
||||
|
||||
import ui
|
||||
from logitech.unifying_receiver import status as _status
|
||||
|
||||
|
||||
_PAIRING_TIMEOUT = 30
|
||||
_PAIRING_TIMEOUT = 15
|
||||
|
||||
|
||||
def _create_page(assistant, kind, header=None, icon_name=None, text=None):
|
||||
|
|
@ -40,29 +40,31 @@ def _create_page(assistant, kind, header=None, icon_name=None, text=None):
|
|||
return p
|
||||
|
||||
|
||||
def _fake_device(receiver):
|
||||
from logitech.unifying_receiver import PairedDevice
|
||||
dev = PairedDevice(receiver, 6)
|
||||
dev._kind = 'touchpad'
|
||||
dev._codename = 'T650'
|
||||
dev._name = 'Wireless Rechargeable Touchpad T650'
|
||||
dev._serial = '0123456789'
|
||||
dev._protocol = 2.0
|
||||
dev.status = {'encrypted': False}
|
||||
return dev
|
||||
|
||||
# def _fake_device(receiver):
|
||||
# from logitech.unifying_receiver import PairedDevice
|
||||
# dev = PairedDevice(receiver, 6)
|
||||
# dev._kind = 'touchpad'
|
||||
# dev._codename = 'T650'
|
||||
# dev._name = 'Wireless Rechargeable Touchpad T650'
|
||||
# dev._serial = '0123456789'
|
||||
# dev._protocol = 2.0
|
||||
# dev.status = _status.DeviceStatus(dev, lambda *foo: None)
|
||||
# return dev
|
||||
|
||||
def _check_lock_state(assistant, receiver):
|
||||
if not assistant.is_drawable():
|
||||
return False
|
||||
|
||||
if receiver.pairing_result:
|
||||
receiver.pairing_result = _fake_device(receiver)
|
||||
if type(receiver.pairing_result) == str:
|
||||
_pairing_failed(assistant, receiver, receiver.pairing_result)
|
||||
else:
|
||||
assert hasattr(receiver.pairing_result, 'number')
|
||||
_pairing_succeeded(assistant, receiver, receiver.pairing_result)
|
||||
if receiver.status.get(_status.ERROR):
|
||||
# fake = _fake_device(receiver)
|
||||
# receiver._devices[fake.number] = fake
|
||||
# receiver.status.new_device = fake
|
||||
# fake.status._changed()
|
||||
_pairing_failed(assistant, receiver, receiver.status.pop(_status.ERROR))
|
||||
return False
|
||||
|
||||
if receiver.status.new_device:
|
||||
_pairing_succeeded(assistant, receiver)
|
||||
return False
|
||||
|
||||
return receiver.status.lock_open
|
||||
|
|
@ -73,11 +75,12 @@ def _prepare(assistant, page, receiver):
|
|||
# logging.debug("prepare %s %d %s", assistant, index, page)
|
||||
|
||||
if index == 0:
|
||||
receiver.pairing_result = None
|
||||
if receiver.set_lock(False, timeout=_PAIRING_TIMEOUT):
|
||||
assert receiver.status.new_device is None
|
||||
assert receiver.status.get(_status.ERROR) is None
|
||||
spinner = page.get_children()[-1]
|
||||
spinner.start()
|
||||
GObject.timeout_add(200, _check_lock_state, assistant, receiver)
|
||||
GObject.timeout_add(300, _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')
|
||||
|
|
@ -88,6 +91,7 @@ def _prepare(assistant, page, receiver):
|
|||
def _finish(assistant, receiver):
|
||||
logging.debug("finish %s", assistant)
|
||||
assistant.destroy()
|
||||
receiver.status.new_device = None
|
||||
if receiver.status.lock_open:
|
||||
receiver.set_lock()
|
||||
|
||||
|
|
@ -95,9 +99,8 @@ def _finish(assistant, receiver):
|
|||
def _cancel(assistant, receiver):
|
||||
logging.debug("cancel %s", assistant)
|
||||
assistant.destroy()
|
||||
device, receiver.pairing_result = receiver.pairing_result, None
|
||||
device, receiver.status.new_device = receiver.status.new_device, None
|
||||
if device:
|
||||
assert type(device) != str
|
||||
try:
|
||||
del receiver[device.number]
|
||||
except:
|
||||
|
|
@ -107,11 +110,10 @@ def _cancel(assistant, receiver):
|
|||
|
||||
|
||||
def _pairing_failed(assistant, receiver, error):
|
||||
receiver.pairing_result = None
|
||||
assistant.commit()
|
||||
|
||||
header = 'Pairing failed: %s.' % error
|
||||
if 'timeout' in error:
|
||||
if 'timeout' in str(error):
|
||||
text = 'Make sure your device is within range,\nand it has a decent battery charge.'
|
||||
else:
|
||||
text = None
|
||||
|
|
@ -121,7 +123,9 @@ def _pairing_failed(assistant, receiver, error):
|
|||
assistant.commit()
|
||||
|
||||
|
||||
def _pairing_succeeded(assistant, receiver, device):
|
||||
def _pairing_succeeded(assistant, receiver):
|
||||
device = receiver.status.new_device
|
||||
assert device
|
||||
page = _create_page(assistant, Gtk.AssistantPageType.CONFIRM)
|
||||
|
||||
device_icon = Gtk.Image()
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class ReceiverStatus(dict):
|
|||
# self.updated = 0
|
||||
|
||||
self.lock_open = False
|
||||
self.new_device = None
|
||||
self[ERROR] = None
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -58,13 +59,20 @@ class ReceiverStatus(dict):
|
|||
self.lock_open = bool(event.address & 0x01)
|
||||
reason = 'pairing lock is ' + ('open' if self.lock_open else 'closed')
|
||||
_log.info("%s: %s", self._receiver, reason)
|
||||
if self.lock_open:
|
||||
self[ERROR] = None
|
||||
self.new_device = None
|
||||
|
||||
pair_error = ord(event.data[:1])
|
||||
if pair_error:
|
||||
self[ERROR] = _hidpp10.PAIRING_ERRORS[pair_error]
|
||||
self.new_device = None
|
||||
_log.warn("pairing error %d: %s", pair_error, self[ERROR])
|
||||
else:
|
||||
self[ERROR] = None
|
||||
|
||||
self._changed(reason=reason)
|
||||
return True
|
||||
|
||||
#
|
||||
#
|
||||
|
|
@ -128,8 +136,9 @@ class DeviceStatus(dict):
|
|||
self._device = None
|
||||
else:
|
||||
_log.warn("device %d disconnection notification %s with unknown type %02X", self._device.number, event, event.address)
|
||||
return True
|
||||
|
||||
elif event.sub_id == 0x41:
|
||||
if event.sub_id == 0x41:
|
||||
if event.address == 0x04: # unifying protocol
|
||||
# wpid = _strhex(event.data[4:5] + event.data[3:4])
|
||||
# assert wpid == device.wpid
|
||||
|
|
@ -151,81 +160,91 @@ class DeviceStatus(dict):
|
|||
else:
|
||||
_log.warn("device %d connection notification %s with unknown protocol %02X", self._device.number, event, event.address)
|
||||
|
||||
elif event.sub_id < 0x40:
|
||||
# a feature event, assuming no device has more than 0x40 features
|
||||
if event.sub_id >= len(self._device.features):
|
||||
_log.warn("device %d got event from unknown feature index %02X", self._device.number, event.sub_id)
|
||||
return None
|
||||
return True
|
||||
|
||||
feature = self._device.features[event.sub_id]
|
||||
if event.sub_id >= 0x40:
|
||||
# this can't possibly be an event, can it?
|
||||
if _log.isEnabledFor(_DEBUG):
|
||||
_log.debug("ignoring non-event %s", event)
|
||||
return False
|
||||
|
||||
if feature == _hidpp20.FEATURE.BATTERY:
|
||||
if event.address == 0x00:
|
||||
discharge = ord(event.data[:1])
|
||||
battery_status = ord(event.data[1:2])
|
||||
self[BATTERY_LEVEL] = discharge
|
||||
self[BATTERY_STATUS] = BATTERY_STATUS[battery_status]
|
||||
if _hidpp20.BATTERY_OK(battery_status):
|
||||
alert = ALERT.NONE
|
||||
reason = self[ERROR] = None
|
||||
else:
|
||||
alert = ALERT.MED
|
||||
reason = self[ERROR] = self[BATTERY_STATUS]
|
||||
self._changed(alert=alert, reason=reason)
|
||||
# this must be a feature event, assuming no device has more than 0x40 features
|
||||
if event.sub_id >= len(self._device.features):
|
||||
_log.warn("device %d got event from unknown feature index %02X", self._device.number, event.sub_id)
|
||||
return False
|
||||
|
||||
feature = self._device.features[event.sub_id]
|
||||
|
||||
if feature == _hidpp20.FEATURE.BATTERY:
|
||||
if event.address == 0x00:
|
||||
discharge = ord(event.data[:1])
|
||||
battery_status = ord(event.data[1:2])
|
||||
self[BATTERY_LEVEL] = discharge
|
||||
self[BATTERY_STATUS] = BATTERY_STATUS[battery_status]
|
||||
if _hidpp20.BATTERY_OK(battery_status):
|
||||
alert = ALERT.NONE
|
||||
reason = self[ERROR] = None
|
||||
else:
|
||||
_log.warn("don't know how to handle BATTERY event %s", event)
|
||||
|
||||
elif feature == _hidpp20.FEATURE.REPROGRAMMABLE_KEYS:
|
||||
if event.address == 0x00:
|
||||
_log.debug('reprogrammable key: %s', event)
|
||||
else:
|
||||
_log.warn("don't know how to handle REPROGRAMMABLE KEYS event %s", event)
|
||||
|
||||
elif feature == _hidpp20.FEATURE.WIRELESS:
|
||||
if event.address == 0x00:
|
||||
_log.debug("wireless status: %s", event)
|
||||
if event.data[0:3] == b'\x01\x01\x01':
|
||||
self._changed(alert=ALERT.LOW, reason='powered on')
|
||||
else:
|
||||
_log.warn("don't know how to handle WIRELESS event %s", event)
|
||||
|
||||
elif feature == _hidpp20.FEATURE.SOLAR_CHARGE:
|
||||
if event.data[5:9] == b'GOOD':
|
||||
charge, lux, adc = _unpack('!BHH', event.data[:5])
|
||||
self[BATTERY_LEVEL] = charge
|
||||
# guesstimate the battery voltage, emphasis on 'guess'
|
||||
self[BATTERY_STATUS] = '%1.2fV' % (adc * 2.67793237653 / 0x0672)
|
||||
if event.address == 0x00:
|
||||
self[LIGHT_LEVEL] = None
|
||||
self._changed()
|
||||
elif event.address == 0x10:
|
||||
self[LIGHT_LEVEL] = lux
|
||||
if lux > 200: # guesstimate
|
||||
self[BATTERY_STATUS] += ', charging'
|
||||
self._changed()
|
||||
elif event.address == 0x20:
|
||||
_log.debug("Solar key pressed")
|
||||
# first cancel any reporting
|
||||
self._device.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE)
|
||||
reports_count = 10
|
||||
reports_period = 3 # seconds
|
||||
self._changed(alert=ALERT.MED)
|
||||
# trigger a new report chain
|
||||
self._device.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE, 0x00, reports_count, reports_period)
|
||||
else:
|
||||
self._changed()
|
||||
else:
|
||||
_log.warn("SOLAR_CHARGE event not GOOD? %s", event)
|
||||
|
||||
elif feature == _hidpp20.FEATURE.TOUCH_MOUSE:
|
||||
if event.address == 0x00:
|
||||
_log.debug("TOUCH MOUSE points event: %s", event)
|
||||
elif event.address == 0x10:
|
||||
touch = ord(event.data[:1])
|
||||
button_down = bool(touch & 0x02)
|
||||
mouse_lifted = bool(touch & 0x01)
|
||||
_log.debug("TOUCH MOUSE status: button_down=%s mouse_lifted=%s", button_down, mouse_lifted)
|
||||
|
||||
alert = ALERT.MED
|
||||
reason = self[ERROR] = self[BATTERY_STATUS]
|
||||
self._changed(alert=alert, reason=reason)
|
||||
else:
|
||||
_log.warn("don't know how to handle event %s", event)
|
||||
_log.warn("don't know how to handle BATTERY event %s", event)
|
||||
return True
|
||||
|
||||
if feature == _hidpp20.FEATURE.REPROGRAMMABLE_KEYS:
|
||||
if event.address == 0x00:
|
||||
_log.debug('reprogrammable key: %s', event)
|
||||
else:
|
||||
_log.warn("don't know how to handle REPROGRAMMABLE KEYS event %s", event)
|
||||
return True
|
||||
|
||||
if feature == _hidpp20.FEATURE.WIRELESS:
|
||||
if event.address == 0x00:
|
||||
_log.debug("wireless status: %s", event)
|
||||
if event.data[0:3] == b'\x01\x01\x01':
|
||||
self._changed(alert=ALERT.LOW, reason='powered on')
|
||||
else:
|
||||
_log.warn("don't know how to handle WIRELESS event %s", event)
|
||||
return True
|
||||
|
||||
if feature == _hidpp20.FEATURE.SOLAR_CHARGE:
|
||||
if event.data[5:9] == b'GOOD':
|
||||
charge, lux, adc = _unpack('!BHH', event.data[:5])
|
||||
self[BATTERY_LEVEL] = charge
|
||||
# guesstimate the battery voltage, emphasis on 'guess'
|
||||
self[BATTERY_STATUS] = '%1.2fV' % (adc * 2.67793237653 / 0x0672)
|
||||
if event.address == 0x00:
|
||||
self[LIGHT_LEVEL] = None
|
||||
self._changed()
|
||||
elif event.address == 0x10:
|
||||
self[LIGHT_LEVEL] = lux
|
||||
if lux > 200: # guesstimate
|
||||
self[BATTERY_STATUS] += ', charging'
|
||||
self._changed()
|
||||
elif event.address == 0x20:
|
||||
_log.debug("Solar key pressed")
|
||||
# first cancel any reporting
|
||||
self._device.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE)
|
||||
reports_count = 10
|
||||
reports_period = 3 # seconds
|
||||
self._changed(alert=ALERT.MED)
|
||||
# trigger a new report chain
|
||||
self._device.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE, 0x00, reports_count, reports_period)
|
||||
else:
|
||||
self._changed()
|
||||
else:
|
||||
_log.warn("SOLAR_CHARGE event not GOOD? %s", event)
|
||||
return True
|
||||
|
||||
if feature == _hidpp20.FEATURE.TOUCH_MOUSE:
|
||||
if event.address == 0x00:
|
||||
_log.debug("TOUCH MOUSE points event: %s", event)
|
||||
elif event.address == 0x10:
|
||||
touch = ord(event.data[:1])
|
||||
button_down = bool(touch & 0x02)
|
||||
mouse_lifted = bool(touch & 0x01)
|
||||
_log.debug("TOUCH MOUSE status: button_down=%s mouse_lifted=%s", button_down, mouse_lifted)
|
||||
return True
|
||||
|
||||
_log.warn("don't know how to handle event %s", event)
|
||||
|
|
|
|||
Loading…
Reference in New Issue