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.common import FallbackDict as _FallbackDict
|
||||
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):
|
||||
super(DeviceInfo, self).__init__(listener.handle, number)
|
||||
self._features = _FeaturesArray(self)
|
||||
|
||||
self.LOG = _Logger("Device[%d]" % number)
|
||||
self._listener = listener
|
||||
self._serial = None
|
||||
self._codename = None
|
||||
|
||||
self._status = status
|
||||
self.props = {}
|
||||
|
||||
self.features = _FeaturesArray(self)
|
||||
|
||||
# read them now, otherwise it it temporarily hang the UI
|
||||
# if status >= STATUS.CONNECTED:
|
||||
# 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])
|
||||
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):
|
||||
if code == 0x10 and data[:1] == b'\x8F':
|
||||
self.status = STATUS.UNAVAILABLE
|
||||
|
@ -229,7 +179,7 @@ class DeviceInfo(_api.PairedDevice):
|
|||
return False
|
||||
|
||||
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):
|
||||
ui.update(receiver, icon, window, device)
|
||||
if ui.notify.available and urgent:
|
||||
ui.notify.show(device or receiver)
|
||||
GObject.idle_add(ui.notify.show, device or receiver)
|
||||
|
||||
global 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])
|
||||
return ('<small>'
|
||||
'Serial \t\t<tt>%s</tt>\n'
|
||||
'HID protocol\t<tt>%1.1f</tt>\n'
|
||||
'%s'
|
||||
'</small>' % (dev.serial, fw_text))
|
||||
'</small>' % (dev.serial, dev.protocol, fw_text))
|
||||
|
||||
def _toggle_info(action, label_widget, box_widget, frame):
|
||||
if action.get_active():
|
||||
|
|
|
@ -8,18 +8,26 @@ def print_receiver(receiver):
|
|||
for f in receiver.firmware:
|
||||
print (" %-10s: %s" % (f.kind, f.version))
|
||||
|
||||
print ("--------")
|
||||
|
||||
|
||||
def scan_devices(receiver):
|
||||
for dev in receiver:
|
||||
print ("--------")
|
||||
print (str(dev))
|
||||
print ("Name: %s" % dev.name)
|
||||
print ("Kind: %s" % dev.kind)
|
||||
print ("Name : %s" % dev.name)
|
||||
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
|
||||
for fw in firmware:
|
||||
print (" %-10s: %s %s" % (fw.kind, fw.name, fw.version))
|
||||
print (" %-10s: %s %s" % (fw.kind, fw.name, fw.version))
|
||||
|
||||
all_features = api.get_device_features(dev.handle, dev.number)
|
||||
for index in range(0, len(all_features)):
|
||||
|
|
|
@ -32,32 +32,74 @@ class PairedDevice(object):
|
|||
self.handle = handle
|
||||
self.number = number
|
||||
|
||||
self._protocol = None
|
||||
self._features = None
|
||||
self._codename = None
|
||||
self._name = None
|
||||
self._kind = None
|
||||
self._serial = 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
|
||||
def name(self):
|
||||
if self._name is None:
|
||||
self._name = get_device_name(self.handle, self.number, self.features)
|
||||
return self._name or '?'
|
||||
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)
|
||||
return self._name or self.codename
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
if self._kind is None:
|
||||
self._kind = get_device_kind(self.handle, self.number, self.features)
|
||||
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)
|
||||
return self._kind or '?'
|
||||
|
||||
@property
|
||||
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)
|
||||
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):
|
||||
reply = _base.request(self.handle, self.number, b'\x00\x10', b'\x00\x00\xAA')
|
||||
return reply is not None and reply[2:3] == b'\xAA'
|
||||
return _base.ping(self.handle, self.number) is not None
|
||||
|
||||
def __str__(self):
|
||||
return '<PairedDevice(%X,%d,%s)>' % (self.handle, self.number, self._name or '?')
|
||||
|
@ -148,8 +190,8 @@ class Receiver(object):
|
|||
if self.handle == 0:
|
||||
return False
|
||||
if type(dev) == int:
|
||||
return (dev < 1 or dev > MAX_ATTACHED_DEVICES) and ping(self.handle, dev)
|
||||
return ping(self.handle, dev.number)
|
||||
return dev > 0 and dev <= MAX_ATTACHED_DEVICES and _base.ping(self.handle, dev) is not None
|
||||
return dev.ping()
|
||||
|
||||
def __str__(self):
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
"""Gets the complete info for a device (type, features).
|
||||
|
||||
:returns: a PairedDevice or ``None``.
|
||||
"""
|
||||
if ping(handle, devnumber):
|
||||
if _base.ping(handle, devnumber):
|
||||
devinfo = PairedDevice(handle, devnumber)
|
||||
# _log.debug("found device %s", devinfo)
|
||||
return devinfo
|
||||
|
@ -291,6 +325,7 @@ def _get_feature_index(handle, devnumber, feature, features=None):
|
|||
if len(features) <= index:
|
||||
features += [None] * (index + 1 - len(features))
|
||||
features[index] = feature
|
||||
# _log.debug("%s: found feature %s at %d", features, _base._hex(feature), index)
|
||||
return index
|
||||
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class EventsListener(_Thread):
|
|||
if task and task[-1] is None:
|
||||
task_dev, task_data = task[:2]
|
||||
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])
|
||||
|
||||
if matched:
|
||||
|
|
Loading…
Reference in New Issue