def _open(args): device = args.device if args.hidpp and not device: for d in _hid.enumerate(vendor_id=0x046d): if d.driver == 'logitech-djreceiver': device = d.path break if not device: sys.exit("!! No HID++ receiver found.") if not device: sys.exit("!! Device path required.") print(".. Opening device", device) handle = _hid.open_path(device) if not handle: sys.exit("!! Failed to open %s, aborting." % device) print(".. Opened handle %r, vendor %r product %r serial %r." % (handle, _hid.get_manufacturer(handle), _hid.get_product(handle), _hid.get_serial(handle))) if args.hidpp: if _hid.get_manufacturer(handle) != b'Logitech': sys.exit("!! Only Logitech devices support the HID++ protocol.") print(".. HID++ validation enabled.") else: if (_hid.get_manufacturer(handle) == b'Logitech' and b'Receiver' in _hid.get_product(handle)): args.hidpp = True print(".. Logitech receiver detected, HID++ validation enabled.") return handle
def _open(device, hidpp): if hidpp and not device: for d in hidapi.enumerate(vendor_id=0x046d): if d.driver == 'logitech-djreceiver': device = d.path break if not device: sys.exit("!! No HID++ receiver found.") if not device: sys.exit("!! Device path required.") print (".. Opening device", device) handle = hidapi.open_path(device) if not handle: sys.exit("!! Failed to open %s, aborting." % device) print (".. Opened handle %r, vendor %r product %r serial %r." % ( handle, hidapi.get_manufacturer(handle), hidapi.get_product(handle), hidapi.get_serial(handle))) if hidpp: if hidapi.get_manufacturer(handle) != b'Logitech': sys.exit("!! Only Logitech devices support the HID++ protocol.") print (".. HID++ validation enabled.") return handle
def open_path(path): """Checks if the given Linux device path points to the right UR device. :param path: the Linux device path. The UR physical device may expose multiple linux devices with the same interface, so we have to check for the right one. At this moment the only way to distinguish betheen them is to do a test ping on an invalid (attached) device number (i.e., 0), expecting a 'ping failed' reply. :returns: an open receiver handle if this is the right Linux device, or ``None``. """ return _hid.open_path(path)
def __init__(self, receiver, number, link_notification=None, info=None): assert receiver or info self.receiver = receiver self.may_unpair = False self.isDevice = True # some devices act as receiver so we need a property to distinguish them if receiver: assert number > 0 and number <= receiver.max_devices else: assert number == 0 # Device number, 1..6 for unifying devices, 1 otherwise. self.number = number # 'device active' flag; requires manual management. self.online = None # the Wireless PID is unique per device model self.wpid = None self.descriptor = None # Bluetooth connections need long messages self.bluetooth = False # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND) self._kind = None # Unifying peripherals report a codename. self._codename = None # the full name of the model self._name = None # HID++ protocol version, 1.0 or 2.0 self._protocol = None # serial number (an 8-char hex string) self._serial = None # unit id (distinguishes within a model - the same as serial) self._unitId = None # model id (contains identifiers for the transports of the device) self._modelId = None # map from transports to product identifiers self._tid_map = None # persister holds settings self._persister = None self._firmware = None self._keys = None self._gestures = None self._registers = None self._settings = None self._feature_settings_checked = False # Misc stuff that's irrelevant to any functionality, but may be # displayed in the UI and caching it here helps. self._polling_rate = None self._power_switch = None # See `add_notification_handler` self._notification_handlers = {} self.handle = None self.path = None self.product_id = None # if _log.isEnabledFor(_DEBUG): # _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification) if receiver: if link_notification is not None: self.online = not bool(ord(link_notification.data[0:1]) & 0x40) self.wpid = _strhex(link_notification.data[2:3] + link_notification.data[1:2]) # assert link_notification.address == (0x04 if unifying else 0x03) kind = ord(link_notification.data[0:1]) & 0x0F # get 27Mhz wpid and set kind based on index if receiver.ex100_27mhz_wpid_fix: # 27 Mhz receiver self.wpid = '00' + _strhex(link_notification.data[2:3]) kind = self.get_kind_from_index(number, receiver) self._kind = _hidpp10.DEVICE_KIND[kind] else: # Not a notification, force a reading of the wpid pair_info = self.receiver.read_register( _R.receiver_info, 0x20 + number - 1) if pair_info: # may be either a Unifying receiver, or an Unifying-ready # receiver self.wpid = _strhex(pair_info[3:5]) kind = ord(pair_info[7:8]) & 0x0F self._kind = _hidpp10.DEVICE_KIND[kind] elif receiver.ex100_27mhz_wpid_fix: # 27Mhz receiver, fill extracting WPID from udev path self.wpid = _hid.find_paired_node_wpid( receiver.path, number) if not self.wpid: _log.error( 'Unable to get wpid from udev for device %d of %s', number, receiver) raise _base.NoSuchDevice( number=number, receiver=receiver, error='Not present 27Mhz device') kind = self.get_kind_from_index(number, receiver) self._kind = _hidpp10.DEVICE_KIND[kind] else: # unifying protocol not supported, must be a Nano receiver device_info = self.receiver.read_register( _R.receiver_info, 0x04) if device_info is None: _log.error( 'failed to read Nano wpid for device %d of %s', number, receiver) raise _base.NoSuchDevice(number=number, receiver=receiver, error='read Nano wpid') self.wpid = _strhex(device_info[3:5]) self._power_switch = '(' + _('unknown') + ')' # the wpid is necessary to properly identify wireless link on/off # notifications also it gets set to None on this object when the # device is unpaired assert self.wpid is not None, 'failed to read wpid: device %d of %s' % ( number, receiver) self.path = _hid.find_paired_node(receiver.path, number, _base.DEFAULT_TIMEOUT) try: self.handle = _hid.open_path(self.path) if self.path else None except Exception: # maybe the device wasn't set up try: import time time.sleep(1) self.handle = _hid.open_path(self.path) except Exception: # give up self.handle = None self.descriptor = _descriptors.get_wpid(self.wpid) if self.descriptor is None: # Last chance to correctly identify the device; many Nano # receivers do not support this call. codename = self.receiver.read_register(_R.receiver_info, 0x40 + self.number - 1) if codename: codename_length = ord(codename[1:2]) codename = codename[2:2 + codename_length] self._codename = codename.decode('ascii') self.descriptor = _descriptors.get_codename(self._codename) else: self.path = info.path self.handle = _hid.open_path(self.path) self.online = True self.product_id = info.product_id self.bluetooth = info.bus_id == 0x0005 self.descriptor = _descriptors.get_btid( self.product_id) if self.bluetooth else _descriptors.get_usbid( self.product_id) if self.descriptor: self._name = self.descriptor.name if self.descriptor.protocol: self._protocol = self.descriptor.protocol if self._codename is None: self._codename = self.descriptor.codename if self._kind is None: self._kind = self.descriptor.kind if self._protocol is not None: self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray( self) else: # may be a 2.0 device; if not, it will fix itself later self.features = _hidpp20.FeaturesArray(self)
def __init__(self, receiver, number, link_notification=None, info=None): assert receiver or info self.receiver = receiver self.may_unpair = False self.isDevice = True # some devices act as receiver so we need a property to distinguish them self.handle = None self.path = None self.product_id = None if receiver: assert number > 0 and number <= receiver.max_devices self.number = number # will be None at this point for directly connected devices # 'device active' flag; requires manual management. self.online = None # the Wireless PID is unique per device model self.wpid = None self.descriptor = None # Bluetooth connections need long messages self.bluetooth = False # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND) self._kind = None # Unifying peripherals report a codename. self._codename = None # the full name of the model self._name = None # HID++ protocol version, 1.0 or 2.0 self._protocol = None # serial number (an 8-char hex string) self._serial = None # unit id (distinguishes within a model - the same as serial) self._unitId = None # model id (contains identifiers for the transports of the device) self._modelId = None # map from transports to product identifiers self._tid_map = None # persister holds settings self._persister = None self._firmware = None self._keys = None self._remap_keys = None self._gestures = None self._gestures_lock = _threading.Lock() self._registers = None self._settings = None self._feature_settings_checked = False self._settings_lock = _threading.Lock() # Misc stuff that's irrelevant to any functionality, but may be # displayed in the UI and caching it here helps. self._polling_rate = None self._power_switch = None # See `add_notification_handler` self._notification_handlers = {} # if _log.isEnabledFor(_DEBUG): # _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification) if receiver: if link_notification is not None: self.online = not bool(ord(link_notification.data[0:1]) & 0x40) self.wpid = _strhex(link_notification.data[2:3] + link_notification.data[1:2]) # assert link_notification.address == (0x04 if unifying else 0x03) kind = ord(link_notification.data[0:1]) & 0x0F # get 27Mhz wpid and set kind based on index if receiver.ex100_27mhz_wpid_fix: # 27 Mhz receiver self.wpid = '00' + _strhex(link_notification.data[2:3]) kind = self.get_kind_from_index(number, receiver) self._kind = _hidpp10.DEVICE_KIND[kind] else: # Not a notification, force a reading of the wpid self.online = True self.update_pairing_information() # the wpid is necessary to properly identify wireless link on/off # notifications also it gets set to None on this object when the # device is unpaired assert self.wpid is not None, 'failed to read wpid: device %d of %s' % ( number, receiver) self.path = _hid.find_paired_node(receiver.path, number, 1) try: self.handle = _hid.open_path(self.path) if self.path else None except Exception: # maybe the device wasn't set up try: import time time.sleep(1) self.handle = _hid.open_path(self.path) except Exception: # give up self.handle = None self.descriptor = _descriptors.get_wpid(self.wpid) if self.descriptor is None: # Last chance to correctly identify the device; many Nano receivers do not support this call. codename = self.receiver.device_codename(self.number) if codename: self._codename = codename self.descriptor = _descriptors.get_codename(self._codename) else: self.path = info.path self.handle = _hid.open_path(self.path) self.online = None # a direct connected device might not be online (as reported by user) self.product_id = info.product_id self.bluetooth = info.bus_id == 0x0005 self.descriptor = _descriptors.get_btid(self.product_id) if self.bluetooth else \ _descriptors.get_usbid(self.product_id) if self.number is None: # for direct-connected devices get 'number' from descriptor protocol else use 0xFF self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF if self.descriptor: self._name = self.descriptor.name if self.descriptor.protocol: self._protocol = self.descriptor.protocol if self._codename is None: self._codename = self.descriptor.codename if self._kind is None: self._kind = self.descriptor.kind if self._protocol is not None: self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray( self) else: # may be a 2.0 device; if not, it will fix itself later self.features = _hidpp20.FeaturesArray(self)
def __init__(self, receiver, number, link_notification=None, info=None): assert receiver or info self.receiver = receiver if receiver: assert number > 0 and number <= receiver.max_devices else: assert number == 0 # Device number, 1..6 for unifying devices, 1 otherwise. self.number = number # 'device active' flag; requires manual management. self.online = None # the Wireless PID is unique per device model self.wpid = None self.descriptor = None # mouse, keyboard, etc (see _hidpp10.DEVICE_KIND) self._kind = None # Unifying peripherals report a codename. self._codename = None # the full name of the model self._name = None # HID++ protocol version, 1.0 or 2.0 self._protocol = None # serial number (an 8-char hex string) self._serial = None self._firmware = None self._keys = None self._gestures = None self._registers = None self._settings = None self._feature_settings_checked = False # Misc stuff that's irrelevant to any functionality, but may be # displayed in the UI and caching it here helps. self._polling_rate = None self._power_switch = None self.handle = None self.path = None self.product_id = None # if _log.isEnabledFor(_DEBUG): # _log.debug("new Device(%s, %s, %s)", receiver, number, link_notification) if receiver: if link_notification is not None: self.online = not bool(ord(link_notification.data[0:1]) & 0x40) self.wpid = _strhex(link_notification.data[2:3] + link_notification.data[1:2]) # assert link_notification.address == (0x04 if unifying else 0x03) kind = ord(link_notification.data[0:1]) & 0x0F self._kind = _hidpp10.DEVICE_KIND[kind] else: # force a reading of the wpid pair_info = self.receiver.read_register( _R.receiver_info, 0x20 + number - 1) if pair_info: # may be either a Unifying receiver, or an Unifying-ready # receiver self.wpid = _strhex(pair_info[3:5]) kind = ord(pair_info[7:8]) & 0x0F self._kind = _hidpp10.DEVICE_KIND[kind] elif receiver.ex100_wpid_fix: # ex100 receiver, fill fake device_info with known wpid's # accordingly to drivers/hid/hid-logitech-dj.c # index 1 or 2 always mouse, index 3 always the keyboard, # index 4 is used for an optional separate numpad if number == 1: # mouse self.wpid = '3F00' self._kind = _hidpp10.DEVICE_KIND[2] elif number == 3: # keyboard self.wpid = '6500' self._kind = _hidpp10.DEVICE_KIND[1] else: # unknown device number on EX100 _log.error( 'failed to set fake EX100 wpid for device %d of %s', number, receiver) raise _base.NoSuchDevice(number=number, receiver=receiver, error='Unknown EX100 device') else: # unifying protocol not supported, must be a Nano receiver device_info = self.receiver.read_register( _R.receiver_info, 0x04) if device_info is None: _log.error( 'failed to read Nano wpid for device %d of %s', number, receiver) raise _base.NoSuchDevice(number=number, receiver=receiver, error='read Nano wpid') self.wpid = _strhex(device_info[3:5]) self._power_switch = '(' + _('unknown') + ')' # the wpid is necessary to properly identify wireless link on/off # notifications also it gets set to None on this object when the # device is unpaired assert self.wpid is not None, 'failed to read wpid: device %d of %s' % ( number, receiver) self.path = _hid.find_paired_node(receiver.path, number, _base.DEFAULT_TIMEOUT) self.handle = _hid.open_path(self.path) if self.path else None self.descriptor = _DESCRIPTORS.get(self.wpid) if self.descriptor is None: # Last chance to correctly identify the device; many Nano # receivers do not support this call. codename = self.receiver.read_register(_R.receiver_info, 0x40 + self.number - 1) if codename: codename_length = ord(codename[1:2]) codename = codename[2:2 + codename_length] self._codename = codename.decode('ascii') self.descriptor = _DESCRIPTORS.get(self._codename) if self.descriptor: self._name = self.descriptor.name self._protocol = self.descriptor.protocol if self._codename is None: self._codename = self.descriptor.codename if self._kind is None: self._kind = self.descriptor.kind else: self.path = info.path self.handle = _hid.open_path(self.path) self.product_id = info.product_id self._serial = ''.join(info.serial.split('-')).upper() if self._protocol is not None: self.features = None if self._protocol < 2.0 else _hidpp20.FeaturesArray( self) else: # may be a 2.0 device; if not, it will fix itself later self.features = _hidpp20.FeaturesArray(self)