expanded devices database, commented out some unnecessary logging

This commit is contained in:
Daniel Pavel 2012-10-12 04:21:25 +03:00
parent bc9f39873e
commit 5da2d43b1c
8 changed files with 105 additions and 70 deletions

View File

@ -18,11 +18,6 @@ from watcher import Watcher
APP_TITLE = 'Solaar'
def _notify(status_code, title, text=''):
if text:
ui.notify.show(status_code, title, text)
if __name__ == '__main__':
import argparse
arg_parser = argparse.ArgumentParser(prog=APP_TITLE)
@ -41,7 +36,7 @@ if __name__ == '__main__':
GObject.threads_init()
args.notifications = args.notifications and args.systray
args.notifications &= args.systray
if args.notifications:
ui.notify.init(APP_TITLE)
@ -57,7 +52,7 @@ if __name__ == '__main__':
if window:
GObject.idle_add(ui.window.update, window, rstatus, devices, icon_name)
watcher = Watcher(_status_changed, _notify if args.notifications else None)
watcher = Watcher(_status_changed, ui.notify.show if args.notifications else None)
watcher.start()
window = ui.window.create(APP_TITLE, watcher.rstatus, args.systray)

View File

@ -72,7 +72,7 @@ try:
n.update(title, text, icon or title)
n.timestamp = timestamp()
try:
logging.debug("showing notification %s", n)
# logging.debug("showing notification %s", n)
n.show()
except Exception:
logging.exception("showing notification %s", n)

View File

@ -104,7 +104,6 @@ class Watcher(Thread):
if self.listener:
self.listener.stop()
api.close(self.listener.receiver)
self.listener = None
def stop(self):

View File

@ -9,22 +9,53 @@ from . import constants as C
from ..unifying_receiver import api as _api
#
#
#
_REQUEST_STATUS_FUNCTIONS = {
C.NAME.K750: k750.request_status,
}
_PROCESS_EVENT_FUNCTIONS = {
C.NAME.K750: k750.process_event,
}
#
#
#
def ping(devinfo, listener=None):
if listener is None:
reply = _api.ping(devinfo.number)
elif listener:
reply = listener.request(_api.ping, devinfo.number)
else:
return None
def ping(devinfo, listener):
reply = listener.request(_api.ping, devinfo.number)
return C.STATUS.CONNECTED if reply else C.STATUS.UNAVAILABLE
def default_request_status(devinfo, listener):
def default_request_status(devinfo, listener=None):
if _api.C.FEATURE.BATTERY in devinfo.features:
reply = listener.request(_api.get_device_battery_level, devinfo.number, features=devinfo.features)
if listener is None:
reply = _api.get_device_battery_level(devinfo.handle, devinfo.number, features=devinfo.features)
elif listener:
reply = listener.request(_api.get_device_battery_level, devinfo.number, features=devinfo.features)
else:
reply = None
if reply:
discharge, dischargeNext, status = reply
return C.STATUS.CONNECTED, {C.PROPS.BATTERY_LEVEL: discharge}
def default_process_event(devinfo, data):
def default_process_event(devinfo, data, listener=None):
feature_index = ord(data[0:1])
if feature_index >= len(devinfo.features):
logging.warn("mistery event %s for %s", repr(data), devinfo)
return None
feature = devinfo.features[feature_index]
feature_function = ord(data[1:2]) & 0xF0
@ -48,39 +79,27 @@ def default_process_event(devinfo, data):
# ?
_REQUEST_STATUS_FUNCTIONS = {
k750.NAME: k750.request_status
}
def request_status(devinfo, listener):
def request_status(devinfo, listener=None):
"""Trigger a status request for a device.
:param devinfo: the device info tuple.
:param listener: the EventsListener that will be used to send the request,
and which will receive the status events from the device.
"""
if listener:
if devinfo.name in _REQUEST_STATUS_FUNCTIONS:
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener)
return default_request_status(devinfo, listener) or ping(devinfo, listener)
if devinfo.name in _REQUEST_STATUS_FUNCTIONS:
return _REQUEST_STATUS_FUNCTIONS[devinfo.name](devinfo, listener)
return default_request_status(devinfo, listener) or ping(devinfo, listener)
_PROCESS_EVENT_FUNCTIONS = {
k750.NAME: k750.process_event
}
def process_event(devinfo, data):
def process_event(devinfo, data, listener=None):
"""Process an event received for a device.
When using an EventsListener, it is assumed this event was received through
its callback, where you may call LUR APIs directly.
:param devinfo: the device info tuple.
:param data: the event data (event packet sans the first two bytes: reply code and device number)
"""
default_result = default_process_event(devinfo, data)
default_result = default_process_event(devinfo, data, listener)
if default_result is not None:
return default_result
if devinfo.name in _PROCESS_EVENT_FUNCTIONS:
return _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, data)
return _PROCESS_EVENT_FUNCTIONS[devinfo.name](devinfo, data, listener)

View File

@ -24,3 +24,34 @@ PROPS = type('PROPS', (),
BATTERY_STATUS='battery_status',
LIGHT_LEVEL='light_level',
))
NAME = type('NAME', (),
dict(
M315='Wireless Mouse M315',
M325='Wireless Mouse M325',
M510='Wireless Mouse M510',
M515='Couch Mouse M515',
M570='Wireless Trackball M570',
K270='Wireless Keyboard K270',
K350='Wireless Keyboard K350',
K750='Wireless Solar Keyboard K750',
K800='Wireless Illuminated Keyboard K800',
))
from ..unifying_receiver.common import FallbackDict
FULL_NAME = FallbackDict(lambda x: x,
dict(
M315=NAME.M315,
M325=NAME.M325,
M510=NAME.M510,
M515=NAME.M515,
M570=NAME.M570,
K270=NAME.K270,
K350=NAME.K350,
K750=NAME.K750,
K800=NAME.K800,
))
del FallbackDict

View File

@ -12,18 +12,6 @@ from . import constants as C
#
#
NAME = 'Wireless Solar Keyboard K750'
#
#
#
def _trigger_solar_charge_events(handle, devinfo):
return _api.request(handle, devinfo.number,
feature=_api.C.FEATURE.SOLAR_CHARGE, function=b'\x03', params=b'\x78\x01',
features=devinfo.features)
def _charge_status(data, hasLux=False):
charge, lux = _unpack('!BH', data[2:5])
@ -47,16 +35,25 @@ def _charge_status(data, hasLux=False):
return 0x10 << charge_index, d
def request_status(devinfo, listener):
if listener:
def request_status(devinfo, listener=None):
def _trigger_solar_charge_events(handle, devinfo):
return _api.request(handle, devinfo.number,
feature=_api.C.FEATURE.SOLAR_CHARGE, function=b'\x03', params=b'\x78\x01',
features=devinfo.features)
if listener is None:
reply = _trigger_solar_charge_events(devinfo.handle, devinfo)
elif listener:
reply = listener.request(_trigger_solar_charge_events, devinfo)
if reply is None:
return C.STATUS.UNAVAILABLE
else:
reply = 0
if reply is None:
return C.STATUS.UNAVAILABLE
def process_event(devinfo, data):
def process_event(devinfo, data, listener=None):
if data[:2] == b'\x09\x00' and data[7:11] == b'GOOD':
# usually sent after the keyboard is turned on
# usually sent after the keyboard is turned on or just connected
return _charge_status(data)
if data[:2] == b'\x09\x10' and data[7:11] == b'GOOD':
@ -65,9 +62,7 @@ def process_event(devinfo, data):
if data[:2] == b'\x09\x20' and data[7:11] == b'GOOD':
logging.debug("Solar key pressed")
if _trigger_solar_charge_events(devinfo.handle, devinfo) is None:
return C.STATUS.UNAVAILABLE
return _charge_status(data)
return request_status(devinfo, listener) or _charge_status(data)
if data[:2] == b'\x05\x00':
# wireless device status

View File

@ -254,7 +254,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, _hexlify(reply_data))
# _l.log(_LOG_LEVEL, "(%d) request got reply for unexpected device %d: [%s]", devnumber, reply_devnumber, _hexlify(reply_data))
# worst case scenario, this is a reply for a concurrent request
# on this receiver
if unhandled_hook:
@ -290,6 +290,6 @@ def request(handle, devnumber, feature_index_function, params=b'', features=None
# _l.log(_LOG_LEVEL, "(%d) matched reply with feature-index-function [%s]", devnumber, _hexlify(reply_data[2:]))
return reply_data[2:]
_l.log(_LOG_LEVEL, "(%d) unmatched reply {%s} (expected {%s})", devnumber, _hexlify(reply_data[:2]), _hexlify(feature_index_function))
# _l.log(_LOG_LEVEL, "(%d) unmatched reply {%s} (expected {%s})", devnumber, _hexlify(reply_data[:2]), _hexlify(feature_index_function))
if unhandled_hook:
unhandled_hook(reply_code, reply_devnumber, reply_data)

View File

@ -20,16 +20,15 @@ _LOG_LEVEL = 4
_l = _Logger('lur.listener')
_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT / 4) # ms
_IDLE_SLEEP = _base.DEFAULT_TIMEOUT / 4 # ms
_READ_EVENT_TIMEOUT = int(_base.DEFAULT_TIMEOUT / 5) # ms
_IDLE_SLEEP = _base.DEFAULT_TIMEOUT / 5 # ms
def _callback_caller(listener, callback):
# _l.log(_LOG_LEVEL, "%s starting callback caller", listener)
while listener._active:
event = listener.events.get()
if _l.isEnabledFor(_LOG_LEVEL):
_l.log(_LOG_LEVEL, "%s delivering event %s", listener, event)
_l.log(_LOG_LEVEL, "%s delivering event %s", listener, event)
try:
callback.__call__(*event)
except:
@ -41,12 +40,11 @@ class EventsListener(Thread):
"""Listener thread for events from the Unifying Receiver.
Incoming events (reply_code, devnumber, data) will be passed to the callback
function. The callback is called in a separate thread.
function in sequence, by a separate thread.
While this listener is running, you should use the request() method to make
regular UR API calls, otherwise the replies are very likely to be captured
by the listener and delivered as events to the callback. As an exception,
you can make API calls in the events callback.
regular UR API calls, otherwise the expected API replies are most likely to
be captured by the listener and delivered as events to the callback.
"""
def __init__(self, receiver, events_callback):
super(EventsListener, self).__init__(group='Unifying Receiver', name='Events-%x' % receiver)
@ -97,6 +95,7 @@ class EventsListener(Thread):
self.task_reply = self._make_request(*self.task)
self.task_done.set()
_base.close(self.receiver)
self.__str_cached = 'Events(%x)' % self.receiver
_base.unhandled_hook = last_hook
@ -113,8 +112,7 @@ class EventsListener(Thread):
The api_function must have a receiver handle as a first agument, all
other passed args and kwargs will follow.
"""
# if _l.isEnabledFor(_LOG_LEVEL):
# _l.log(_LOG_LEVEL, "%s request '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
# _l.log(_LOG_LEVEL, "%s request '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
self.task_processing.acquire()
self.task_done.clear()
@ -125,15 +123,13 @@ class EventsListener(Thread):
self.task = self.task_reply = None
self.task_processing.release()
# if _l.isEnabledFor(_LOG_LEVEL):
# _l.log(_LOG_LEVEL, "%s request '%s.%s' => %s", self, api_function.__module__, api_function.__name__, repr(reply))
# _l.log(_LOG_LEVEL, "%s request '%s.%s' => %s", self, api_function.__module__, api_function.__name__, repr(reply))
if isinstance(reply, Exception):
raise reply
return reply
def _make_request(self, api_function, args, kwargs):
if _l.isEnabledFor(_LOG_LEVEL):
_l.log(_LOG_LEVEL, "%s calling '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
_l.log(_LOG_LEVEL, "%s calling '%s.%s' with %s, %s", self, api_function.__module__, api_function.__name__, args, kwargs)
try:
return api_function.__call__(self.receiver, *args, **kwargs)
except E.NoReceiver as nr: