Exemplo n.º 1
0
 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
Exemplo n.º 2
0
    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)