improved support for HID 1.0 devices
This commit is contained in:
parent
c9843e4408
commit
a59ad221a1
|
@ -11,7 +11,7 @@ from logitech.unifying_receiver import api as _api
|
||||||
from logitech.unifying_receiver.listener import EventsListener as _EventsListener
|
from logitech.unifying_receiver.listener import EventsListener as _EventsListener
|
||||||
from logitech.unifying_receiver.common import FallbackDict as _FallbackDict
|
from logitech.unifying_receiver.common import FallbackDict as _FallbackDict
|
||||||
from logitech import devices as _devices
|
from logitech import devices as _devices
|
||||||
from logitech.devices.constants import (STATUS, STATUS_NAME, PROPS, NAMES)
|
from logitech.devices.constants import (STATUS, STATUS_NAME, PROPS)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -107,17 +107,14 @@ class DeviceInfo(_api.PairedDevice):
|
||||||
"""
|
"""
|
||||||
def __init__(self, listener, number, status=STATUS.UNKNOWN):
|
def __init__(self, listener, number, status=STATUS.UNKNOWN):
|
||||||
super(DeviceInfo, self).__init__(listener.handle, number)
|
super(DeviceInfo, self).__init__(listener.handle, number)
|
||||||
|
self._features = _FeaturesArray(self)
|
||||||
|
|
||||||
self.LOG = _Logger("Device[%d]" % number)
|
self.LOG = _Logger("Device[%d]" % number)
|
||||||
self._listener = listener
|
self._listener = listener
|
||||||
self._serial = None
|
|
||||||
self._codename = None
|
|
||||||
|
|
||||||
self._status = status
|
self._status = status
|
||||||
self.props = {}
|
self.props = {}
|
||||||
|
|
||||||
self.features = _FeaturesArray(self)
|
|
||||||
|
|
||||||
# read them now, otherwise it it temporarily hang the UI
|
# read them now, otherwise it it temporarily hang the UI
|
||||||
# if status >= STATUS.CONNECTED:
|
# if status >= STATUS.CONNECTED:
|
||||||
# n, k, s, f = self.name, self.kind, self.serial, self.firmware
|
# n, k, s, f = self.name, self.kind, self.serial, self.firmware
|
||||||
|
@ -155,53 +152,6 @@ class DeviceInfo(_api.PairedDevice):
|
||||||
t.append('Light: %d lux' % self.props[PROPS.LIGHT_LEVEL])
|
t.append('Light: %d lux' % self.props[PROPS.LIGHT_LEVEL])
|
||||||
return ', '.join(t) if t else STATUS_NAME[STATUS.CONNECTED]
|
return ', '.join(t) if t else STATUS_NAME[STATUS.CONNECTED]
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
if self._name is None:
|
|
||||||
if self._status < STATUS.CONNECTED:
|
|
||||||
codename = self.codename
|
|
||||||
if codename in NAMES:
|
|
||||||
self._name, self._kind = NAMES[codename]
|
|
||||||
elif self.features:
|
|
||||||
self._name = _api.get_device_name(self.handle, self.number, self.features)
|
|
||||||
return self._name or self.codename
|
|
||||||
|
|
||||||
@property
|
|
||||||
def kind(self):
|
|
||||||
if self._kind is None:
|
|
||||||
if self._status < STATUS.CONNECTED:
|
|
||||||
codename = self.codename
|
|
||||||
if codename in NAMES:
|
|
||||||
self._name, self._kind = NAMES[codename]
|
|
||||||
elif self.features:
|
|
||||||
self._kind = _api.get_device_kind(self.handle, self.number, self.features)
|
|
||||||
return self._kind or '?'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def serial(self):
|
|
||||||
if self._serial is None:
|
|
||||||
prefix = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x20 + self.number - 1)
|
|
||||||
prefix = (_base._hex(prefix[3:5]) + '-') if prefix else ''
|
|
||||||
serial = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x30 + self.number - 1)
|
|
||||||
serial = _base._hex(serial[1:5]) if serial else '?'
|
|
||||||
self._serial = prefix + serial
|
|
||||||
return self._serial or '?'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def codename(self):
|
|
||||||
if self._codename is None:
|
|
||||||
codename = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x40 + self.number - 1)
|
|
||||||
if codename:
|
|
||||||
self._codename = codename[2:].rstrip(b'\x00').decode('ascii')
|
|
||||||
return self._codename or '?'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def firmware(self):
|
|
||||||
if self._firmware is None:
|
|
||||||
if self._status >= STATUS.CONNECTED and self.features:
|
|
||||||
self._firmware = _api.get_device_firmware(self.handle, self.number, self.features)
|
|
||||||
return self._firmware or ()
|
|
||||||
|
|
||||||
def process_event(self, code, data):
|
def process_event(self, code, data):
|
||||||
if code == 0x10 and data[:1] == b'\x8F':
|
if code == 0x10 and data[:1] == b'\x8F':
|
||||||
self.status = STATUS.UNAVAILABLE
|
self.status = STATUS.UNAVAILABLE
|
||||||
|
@ -229,7 +179,7 @@ class DeviceInfo(_api.PairedDevice):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'DeviceInfo(%d,%s,%d)' % (self.number, self._name or '?', self._status)
|
return '<DeviceInfo(%d,%s,%d)>' % (self.number, self._name or '?', self._status)
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
|
@ -89,7 +89,7 @@ if __name__ == '__main__':
|
||||||
def status_changed(receiver, device=None, urgent=False):
|
def status_changed(receiver, device=None, urgent=False):
|
||||||
ui.update(receiver, icon, window, device)
|
ui.update(receiver, icon, window, device)
|
||||||
if ui.notify.available and urgent:
|
if ui.notify.available and urgent:
|
||||||
ui.notify.show(device or receiver)
|
GObject.idle_add(ui.notify.show, device or receiver)
|
||||||
|
|
||||||
global listener
|
global listener
|
||||||
if not listener:
|
if not listener:
|
||||||
|
|
|
@ -22,8 +22,9 @@ def _info_text(dev):
|
||||||
(f.kind, f.name, ' ' if f.name else '', f.version) for f in dev.firmware])
|
(f.kind, f.name, ' ' if f.name else '', f.version) for f in dev.firmware])
|
||||||
return ('<small>'
|
return ('<small>'
|
||||||
'Serial \t\t<tt>%s</tt>\n'
|
'Serial \t\t<tt>%s</tt>\n'
|
||||||
|
'HID protocol\t<tt>%1.1f</tt>\n'
|
||||||
'%s'
|
'%s'
|
||||||
'</small>' % (dev.serial, fw_text))
|
'</small>' % (dev.serial, dev.protocol, fw_text))
|
||||||
|
|
||||||
def _toggle_info(action, label_widget, box_widget, frame):
|
def _toggle_info(action, label_widget, box_widget, frame):
|
||||||
if action.get_active():
|
if action.get_active():
|
||||||
|
|
|
@ -8,14 +8,22 @@ def print_receiver(receiver):
|
||||||
for f in receiver.firmware:
|
for f in receiver.firmware:
|
||||||
print (" %-10s: %s" % (f.kind, f.version))
|
print (" %-10s: %s" % (f.kind, f.version))
|
||||||
|
|
||||||
print ("--------")
|
|
||||||
|
|
||||||
|
|
||||||
def scan_devices(receiver):
|
def scan_devices(receiver):
|
||||||
for dev in receiver:
|
for dev in receiver:
|
||||||
|
print ("--------")
|
||||||
print (str(dev))
|
print (str(dev))
|
||||||
print ("Name: %s" % dev.name)
|
print ("Name : %s" % dev.name)
|
||||||
print ("Kind: %s" % dev.kind)
|
print ("Kind : %s" % dev.kind)
|
||||||
|
print ("Serial number: %s" % dev.serial)
|
||||||
|
if not dev.protocol:
|
||||||
|
print ("HID protocol : UNKNOWN")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print ("HID protocol : HID %01.1f" % dev.protocol)
|
||||||
|
if dev.protocol < 2.0:
|
||||||
|
print ("Features query not supported by this device")
|
||||||
|
continue
|
||||||
|
|
||||||
firmware = dev.firmware
|
firmware = dev.firmware
|
||||||
for fw in firmware:
|
for fw in firmware:
|
||||||
|
|
|
@ -32,32 +32,74 @@ class PairedDevice(object):
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
self.number = number
|
self.number = number
|
||||||
|
|
||||||
|
self._protocol = None
|
||||||
|
self._features = None
|
||||||
|
self._codename = None
|
||||||
self._name = None
|
self._name = None
|
||||||
self._kind = None
|
self._kind = None
|
||||||
|
self._serial = None
|
||||||
self._firmware = None
|
self._firmware = None
|
||||||
self.features = [FEATURE.ROOT]
|
|
||||||
|
@property
|
||||||
|
def protocol(self):
|
||||||
|
if self._protocol is None:
|
||||||
|
self._protocol = _base.ping(self.handle, self.number)
|
||||||
|
return 0 if self._protocol is None else self._protocol
|
||||||
|
|
||||||
|
@property
|
||||||
|
def features(self):
|
||||||
|
if self._features is None:
|
||||||
|
if self.protocol >= 2.0:
|
||||||
|
self._features = [FEATURE.ROOT]
|
||||||
|
return self._features
|
||||||
|
|
||||||
|
@property
|
||||||
|
def codename(self):
|
||||||
|
if self._codename is None:
|
||||||
|
codename = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x40 + self.number - 1)
|
||||||
|
if codename:
|
||||||
|
self._codename = codename[2:].rstrip(b'\x00').decode('ascii')
|
||||||
|
return self._codename or '?'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
if self._name is None:
|
if self._name is None:
|
||||||
|
if self.protocol < 2.0:
|
||||||
|
from ..devices.constants import NAMES as _DEVICE_NAMES
|
||||||
|
if self.codename in _DEVICE_NAMES:
|
||||||
|
self._name, self._kind = _DEVICE_NAMES[self._codename]
|
||||||
|
else:
|
||||||
self._name = get_device_name(self.handle, self.number, self.features)
|
self._name = get_device_name(self.handle, self.number, self.features)
|
||||||
return self._name or '?'
|
return self._name or self.codename
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kind(self):
|
def kind(self):
|
||||||
if self._kind is None:
|
if self._kind is None:
|
||||||
|
if self.protocol < 2.0:
|
||||||
|
from ..devices.constants import NAMES as _DEVICE_NAMES
|
||||||
|
if self.codename in _DEVICE_NAMES:
|
||||||
|
self._name, self._kind = _DEVICE_NAMES[self._codename]
|
||||||
|
else:
|
||||||
self._kind = get_device_kind(self.handle, self.number, self.features)
|
self._kind = get_device_kind(self.handle, self.number, self.features)
|
||||||
return self._kind or '?'
|
return self._kind or '?'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def firmware(self):
|
def firmware(self):
|
||||||
if self._firmware is None:
|
if self._firmware is None and self.protocol >= 2.0:
|
||||||
self._firmware = get_device_firmware(self.handle, self.number, self.features)
|
self._firmware = get_device_firmware(self.handle, self.number, self.features)
|
||||||
return self._firmware or ()
|
return self._firmware or ()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serial(self):
|
||||||
|
if self._serial is None:
|
||||||
|
prefix = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x20 + self.number - 1)
|
||||||
|
serial = _base.request(self.handle, 0xFF, b'\x83\xB5', 0x30 + self.number - 1)
|
||||||
|
if prefix and serial:
|
||||||
|
self._serial = _base._hex(prefix[3:5]) + '-' + _base._hex(serial[1:5])
|
||||||
|
return self._serial or '?'
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
reply = _base.request(self.handle, self.number, b'\x00\x10', b'\x00\x00\xAA')
|
return _base.ping(self.handle, self.number) is not None
|
||||||
return reply is not None and reply[2:3] == b'\xAA'
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '<PairedDevice(%X,%d,%s)>' % (self.handle, self.number, self._name or '?')
|
return '<PairedDevice(%X,%d,%s)>' % (self.handle, self.number, self._name or '?')
|
||||||
|
@ -148,8 +190,8 @@ class Receiver(object):
|
||||||
if self.handle == 0:
|
if self.handle == 0:
|
||||||
return False
|
return False
|
||||||
if type(dev) == int:
|
if type(dev) == int:
|
||||||
return (dev < 1 or dev > MAX_ATTACHED_DEVICES) and ping(self.handle, dev)
|
return dev > 0 and dev <= MAX_ATTACHED_DEVICES and _base.ping(self.handle, dev) is not None
|
||||||
return ping(self.handle, dev.number)
|
return dev.ping()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '<Receiver(%X,%s)>' % (self.handle, self.path)
|
return '<Receiver(%X,%s)>' % (self.handle, self.path)
|
||||||
|
@ -228,20 +270,12 @@ def request(handle, devnumber, feature, function=b'\x00', params=b'', features=N
|
||||||
return _base.request(handle, devnumber, feature_index + function, params)
|
return _base.request(handle, devnumber, feature_index + function, params)
|
||||||
|
|
||||||
|
|
||||||
def ping(handle, devnumber):
|
|
||||||
"""
|
|
||||||
:returns: True if the device is connected to the UR.
|
|
||||||
"""
|
|
||||||
reply = _base.request(handle, devnumber, b'\x00\x10', b'\x00\x00\xAA')
|
|
||||||
return reply is not None and reply[2:3] == b'\xAA'
|
|
||||||
|
|
||||||
|
|
||||||
def get_device(handle, devnumber, features=None):
|
def get_device(handle, devnumber, features=None):
|
||||||
"""Gets the complete info for a device (type, features).
|
"""Gets the complete info for a device (type, features).
|
||||||
|
|
||||||
:returns: a PairedDevice or ``None``.
|
:returns: a PairedDevice or ``None``.
|
||||||
"""
|
"""
|
||||||
if ping(handle, devnumber):
|
if _base.ping(handle, devnumber):
|
||||||
devinfo = PairedDevice(handle, devnumber)
|
devinfo = PairedDevice(handle, devnumber)
|
||||||
# _log.debug("found device %s", devinfo)
|
# _log.debug("found device %s", devinfo)
|
||||||
return devinfo
|
return devinfo
|
||||||
|
@ -291,6 +325,7 @@ def _get_feature_index(handle, devnumber, feature, features=None):
|
||||||
if len(features) <= index:
|
if len(features) <= index:
|
||||||
features += [None] * (index + 1 - len(features))
|
features += [None] * (index + 1 - len(features))
|
||||||
features[index] = feature
|
features[index] = feature
|
||||||
|
# _log.debug("%s: found feature %s at %d", features, _base._hex(feature), index)
|
||||||
return index
|
return index
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ class EventsListener(_Thread):
|
||||||
if task and task[-1] is None:
|
if task and task[-1] is None:
|
||||||
task_dev, task_data = task[:2]
|
task_dev, task_data = task[:2]
|
||||||
if event[1] == task_dev:
|
if event[1] == task_dev:
|
||||||
_log.debug("matching %s to (%d, %s)", event, task_dev, repr(task_data))
|
# _log.debug("matching %s to (%d, %s)", event, task_dev, repr(task_data))
|
||||||
matched = event[2][:2] == task_data[:2] or (event[2][:1] in b'\x8F\xFF' and event[2][1:3] == task_data[:2])
|
matched = event[2][:2] == task_data[:2] or (event[2][:1] in b'\x8F\xFF' and event[2][1:3] == task_data[:2])
|
||||||
|
|
||||||
if matched:
|
if matched:
|
||||||
|
|
Loading…
Reference in New Issue