load the configuration when the device is detected

and apply it every time the device comes online
This commit is contained in:
Daniel Pavel 2013-06-29 20:35:02 +02:00
parent 1d438f098f
commit 8d5718178f
5 changed files with 32 additions and 19 deletions

View File

@ -33,6 +33,7 @@ class _Setting(object):
self.persister = None
def __call__(self, device):
assert not hasattr(self, '_value')
o = _copy(self)
o._value = None
o._device = device # _proxy(device)
@ -43,12 +44,15 @@ class _Setting(object):
return self._validator.choices if self._validator.kind & KIND.choice else None
def read(self, cached=True):
if self._value is None and self.persister:
self._value = self.persister.get(self.name)
if cached and self._value is not None:
if self.persister and self.name not in self.persister:
self.persister[self.name] = self._value
return self._value
if self._device:
if self._device.online:
reply = self._rw.read(self._device)
if reply:
self._value = self._validator.validate_read(reply)
@ -66,6 +70,10 @@ class _Setting(object):
self.persister[self.name] = self._value
return self._value
def apply(self):
if self._value is not None:
self.write(self._value)
def __str__(self):
if hasattr(self, '_value'):
assert hasattr(self, '_device')
@ -73,6 +81,9 @@ class _Setting(object):
return '<Setting([%s:%s] %s)>' % (self._rw.kind, self._validator.kind, self.name)
__unicode__ = __repr__ = __str__
#
# read/write low-level operators
#
class _RegisterRW(object):
__slots__ = ['register']
@ -111,6 +122,10 @@ class _FeatureRW(object):
assert self.feature is not None
return device.feature_request(self.feature, self.write_fnid, data_bytes)
#
# value validators
# handle the conversion from read bytes, to setting value, and back
#
class _BooleanValidator(object):
__slots__ = ['true_value', 'false_value', 'mask', 'write_returns_value']
@ -118,6 +133,7 @@ class _BooleanValidator(object):
kind = KIND.toggle
default_true = 0x01
default_false = 0x00
# mask specifies all the affected bits in the value
default_mask = 0xFF
def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask, write_returns_value=False):
@ -191,7 +207,7 @@ class _ChoicesValidator(object):
return self.choices[value]
#
#
# pre-defined basic setting descriptors
#
def register_toggle(name, register,

View File

@ -136,9 +136,6 @@ class DeviceStatus(dict):
# timestamp of when this status object was last updated
self.updated = 0
# optional object able to persist device settings
self.configuration = None
def __str__(self):
def _item(name, format):
value = self.get(name)
@ -242,8 +239,11 @@ class DeviceStatus(dict):
# get cleared when the device is turned off (but not when the device
# goes idle, and we can't tell the difference right now).
self[KEYS.NOTIFICATION_FLAGS] = d.enable_notifications()
if self.configuration:
self.configuration.attach_to(d)
# Devices lose configuration when they are turned off,
# make sure they're up-to-date.
for s in self._device.settings:
s.apply()
else:
if was_active:
battery = self.get(KEYS.BATTERY_LEVEL)

View File

@ -105,7 +105,3 @@ def attach_to(device):
if s.persister is None:
s.persister = persister
assert s.persister == persister
if s.name in persister:
s.write(persister[s.name])
else:
persister[s.name] = s.read(cached=False)

View File

@ -171,8 +171,10 @@ class ReceiverListener(_listener.EventsListener):
if not already_known:
_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.
# They will be applied when the device is marked as online.
configuration.attach_to(dev)
dev.status = _status.DeviceStatus(dev, self._status_changed)
dev.status.configuration = configuration
# the receiver changed status as well
self._status_changed(self.receiver)

View File

@ -9,7 +9,8 @@ from gi.repository import Gtk, GLib
from logitech.unifying_receiver import settings as _settings
#
#
# a separate thread is used to read/write from the device
# so as not to block the main (GUI) thread
#
try:
@ -29,15 +30,16 @@ def _process_apply_queue():
while True:
task = _apply_queue.get()
assert isinstance(task, tuple)
device_is_online = True
# print ("task", *task)
if task[0] == 'write':
_, setting, value, sbox = task
GLib.idle_add(_write_start, sbox, priority=0)
value = setting.write(value)
elif task[0] == 'read':
_, setting, force_read, sbox = task
_, setting, force_read, sbox, device_is_online = task
value = setting.read(not force_read)
GLib.idle_add(_update_setting_item, sbox, value, priority=99)
GLib.idle_add(_update_setting_item, sbox, value, device_is_online, priority=99)
from threading import Thread as _Thread
_queue_processor = _Thread(name='SettingsProcessor', target=_process_apply_queue)
@ -190,10 +192,7 @@ def update(device, is_online=None):
sbox = _items[k] = _create_sbox(s)
_box.pack_start(sbox, False, False, 0)
if is_online:
_apply_queue.put(('read', s, False, sbox))
else:
_update_setting_item(sbox, None, False)
_apply_queue.put(('read', s, False, sbox, is_online))
_box.set_visible(True)