def device_pairing_information(self, n): if self.receiver_kind == 'bolt': pair_info = self.read_register(_R.receiver_info, _IR.bolt_pairing_information + n) if pair_info: wpid = _strhex(pair_info[3:4]) + _strhex(pair_info[2:3]) kind = _hidpp10.DEVICE_KIND[ord(pair_info[1:2]) & 0x0F] return wpid, kind, 0 else: raise _base.NoSuchDevice(number=n, receiver=self, error='read Bolt wpid') pair_info = self.read_register(_R.receiver_info, _IR.pairing_information + n - 1) polling_rate = 0 if pair_info: # may be either a Unifying receiver, or an Unifying-ready receiver wpid = _strhex(pair_info[3:5]) kind = _hidpp10.DEVICE_KIND[ord(pair_info[7:8]) & 0x0F] polling_rate = ord(pair_info[2:3]) elif self.ex100_27mhz_wpid_fix: # 27Mhz receiver, fill extracting WPID from udev path wpid = _hid.find_paired_node_wpid(self.path, n) if not wpid: _log.error('Unable to get wpid from udev for device %d of %s', n, self) raise _base.NoSuchDevice(number=n, receiver=self, error='Not present 27Mhz device') kind = _hidpp10.DEVICE_KIND[self.get_kind_from_index(n, self)] else: # unifying protocol not supported, probably an old Nano receiver device_info = self.read_register(_R.receiver_info, 0x04) if device_info is None: _log.error('failed to read Nano wpid for device %d of %s', n, self) raise _base.NoSuchDevice(number=n, receiver=self, error='read Nano wpid') wpid = _strhex(device_info[3:5]) kind = _hidpp10.DEVICE_KIND[0x00] # unknown kind return wpid, kind, polling_rate
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)