logitech_receiver: Move hidpp10 constants into new module
Related #1097
This commit is contained in:
parent
e8fdbeee8e
commit
2fcab65486
|
@ -24,8 +24,8 @@
|
||||||
# - the device uses a USB interface other than 2
|
# - the device uses a USB interface other than 2
|
||||||
# - the name or codename should be different from what the device reports
|
# - the name or codename should be different from what the device reports
|
||||||
|
|
||||||
from .hidpp10 import DEVICE_KIND as _DK
|
from .hidpp10_constants import DEVICE_KIND as _DK
|
||||||
from .hidpp10 import REGISTERS as _R
|
from .hidpp10_constants import REGISTERS as _R
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
|
@ -30,16 +30,18 @@ from . import base as _base
|
||||||
from . import descriptors as _descriptors
|
from . import descriptors as _descriptors
|
||||||
from . import exceptions
|
from . import exceptions
|
||||||
from . import hidpp10 as _hidpp10
|
from . import hidpp10 as _hidpp10
|
||||||
|
from . import hidpp10_constants as _hidpp10_constants
|
||||||
from . import hidpp20 as _hidpp20
|
from . import hidpp20 as _hidpp20
|
||||||
|
from . import hidpp20_constants as _hidpp20_constants
|
||||||
from .common import strhex as _strhex
|
from .common import strhex as _strhex
|
||||||
from .settings_templates import check_feature_settings as _check_feature_settings
|
from .settings_templates import check_feature_settings as _check_feature_settings
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_R = _hidpp10.REGISTERS
|
_R = _hidpp10_constants.REGISTERS
|
||||||
_IR = _hidpp10.INFO_SUBREGISTERS
|
_IR = _hidpp10_constants.INFO_SUBREGISTERS
|
||||||
|
|
||||||
KIND_MAP = {kind: _hidpp10.DEVICE_KIND[str(kind)] for kind in _hidpp20.DEVICE_KIND}
|
KIND_MAP = {kind: _hidpp10_constants.DEVICE_KIND[str(kind)] for kind in _hidpp20_constants.DEVICE_KIND}
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -124,14 +126,14 @@ class Device:
|
||||||
if receiver.receiver_kind == '27Mhz': # 27 Mhz receiver
|
if receiver.receiver_kind == '27Mhz': # 27 Mhz receiver
|
||||||
self.wpid = '00' + _strhex(link_notification.data[2:3])
|
self.wpid = '00' + _strhex(link_notification.data[2:3])
|
||||||
kind = receiver.get_kind_from_index(number)
|
kind = receiver.get_kind_from_index(number)
|
||||||
self._kind = _hidpp10.DEVICE_KIND[kind]
|
self._kind = _hidpp10_constants.DEVICE_KIND[kind]
|
||||||
elif receiver.receiver_kind == '27Mhz': # 27 Mhz receiver doesn't have pairing registers
|
elif receiver.receiver_kind == '27Mhz': # 27 Mhz receiver doesn't have pairing registers
|
||||||
self.wpid = _hid.find_paired_node_wpid(receiver.path, number)
|
self.wpid = _hid.find_paired_node_wpid(receiver.path, number)
|
||||||
if not self.wpid:
|
if not self.wpid:
|
||||||
logger.error('Unable to get wpid from udev for device %d of %s', number, receiver)
|
logger.error('Unable to get wpid from udev for device %d of %s', number, receiver)
|
||||||
raise exceptions.NoSuchDevice(number=number, receiver=receiver, error='Not present 27Mhz device')
|
raise exceptions.NoSuchDevice(number=number, receiver=receiver, error='Not present 27Mhz device')
|
||||||
kind = receiver.get_kind_from_index(number)
|
kind = receiver.get_kind_from_index(number)
|
||||||
self._kind = _hidpp10.DEVICE_KIND[kind]
|
self._kind = _hidpp10_constants.DEVICE_KIND[kind]
|
||||||
else: # get information from pairing registers
|
else: # get information from pairing registers
|
||||||
self.online = True
|
self.online = True
|
||||||
self.update_pairing_information()
|
self.update_pairing_information()
|
||||||
|
@ -415,10 +417,10 @@ class Device:
|
||||||
|
|
||||||
if enable:
|
if enable:
|
||||||
set_flag_bits = (
|
set_flag_bits = (
|
||||||
_hidpp10.NOTIFICATION_FLAG.battery_status
|
_hidpp10_constants.NOTIFICATION_FLAG.battery_status
|
||||||
| _hidpp10.NOTIFICATION_FLAG.keyboard_illumination
|
| _hidpp10_constants.NOTIFICATION_FLAG.keyboard_illumination
|
||||||
| _hidpp10.NOTIFICATION_FLAG.wireless
|
| _hidpp10_constants.NOTIFICATION_FLAG.wireless
|
||||||
| _hidpp10.NOTIFICATION_FLAG.software_present
|
| _hidpp10_constants.NOTIFICATION_FLAG.software_present
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
set_flag_bits = 0
|
set_flag_bits = 0
|
||||||
|
@ -427,7 +429,7 @@ class Device:
|
||||||
logger.warning('%s: failed to %s device notifications', self, 'enable' if enable else 'disable')
|
logger.warning('%s: failed to %s device notifications', self, 'enable' if enable else 'disable')
|
||||||
|
|
||||||
flag_bits = _hidpp10.get_notification_flags(self)
|
flag_bits = _hidpp10.get_notification_flags(self)
|
||||||
flag_names = None if flag_bits is None else tuple(_hidpp10.NOTIFICATION_FLAG.flag_names(flag_bits))
|
flag_names = None if flag_bits is None else tuple(_hidpp10_constants.NOTIFICATION_FLAG.flag_names(flag_bits))
|
||||||
if logger.isEnabledFor(logging.INFO):
|
if logger.isEnabledFor(logging.INFO):
|
||||||
logger.info('%s: device notifications %s %s', self, 'enabled' if enable else 'disabled', flag_names)
|
logger.info('%s: device notifications %s %s', self, 'enabled' if enable else 'disabled', flag_names)
|
||||||
return flag_bits if ok else None
|
return flag_bits if ok else None
|
||||||
|
|
|
@ -20,164 +20,14 @@ import logging
|
||||||
|
|
||||||
from .common import BATTERY_APPROX as _BATTERY_APPROX
|
from .common import BATTERY_APPROX as _BATTERY_APPROX
|
||||||
from .common import FirmwareInfo as _FirmwareInfo
|
from .common import FirmwareInfo as _FirmwareInfo
|
||||||
from .common import NamedInts as _NamedInts
|
|
||||||
from .common import bytes2int as _bytes2int
|
from .common import bytes2int as _bytes2int
|
||||||
from .common import int2bytes as _int2bytes
|
from .common import int2bytes as _int2bytes
|
||||||
from .common import strhex as _strhex
|
from .common import strhex as _strhex
|
||||||
from .hidpp20 import BATTERY_STATUS, FIRMWARE_KIND
|
from .hidpp20 import BATTERY_STATUS, FIRMWARE_KIND
|
||||||
|
from .hidpp10_constants import REGISTERS
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
#
|
|
||||||
# Constants - most of them as defined by the official Logitech HID++ 1.0
|
|
||||||
# documentation, some of them guessed.
|
|
||||||
#
|
|
||||||
|
|
||||||
DEVICE_KIND = _NamedInts(
|
|
||||||
unknown=0x00,
|
|
||||||
keyboard=0x01,
|
|
||||||
mouse=0x02,
|
|
||||||
numpad=0x03,
|
|
||||||
presenter=0x04,
|
|
||||||
remote=0x07,
|
|
||||||
trackball=0x08,
|
|
||||||
touchpad=0x09,
|
|
||||||
headset=0x0D, # not from Logitech documentation
|
|
||||||
remote_control=0x0E, # for compatibility with HID++ 2.0
|
|
||||||
receiver=0x0F # for compatibility with HID++ 2.0
|
|
||||||
)
|
|
||||||
|
|
||||||
POWER_SWITCH_LOCATION = _NamedInts(
|
|
||||||
base=0x01,
|
|
||||||
top_case=0x02,
|
|
||||||
edge_of_top_right_corner=0x03,
|
|
||||||
top_left_corner=0x05,
|
|
||||||
bottom_left_corner=0x06,
|
|
||||||
top_right_corner=0x07,
|
|
||||||
bottom_right_corner=0x08,
|
|
||||||
top_edge=0x09,
|
|
||||||
right_edge=0x0A,
|
|
||||||
left_edge=0x0B,
|
|
||||||
bottom_edge=0x0C
|
|
||||||
)
|
|
||||||
|
|
||||||
# Some flags are used both by devices and receivers. The Logitech documentation
|
|
||||||
# mentions that the first and last (third) byte are used for devices while the
|
|
||||||
# second is used for the receiver. In practise, the second byte is also used for
|
|
||||||
# some device-specific notifications (keyboard illumination level). Do not
|
|
||||||
# simply set all notification bits if the software does not support it. For
|
|
||||||
# example, enabling keyboard_sleep_raw makes the Sleep key a no-operation unless
|
|
||||||
# the software is updated to handle that event.
|
|
||||||
# Observations:
|
|
||||||
# - wireless and software present were seen on receivers, reserved_r1b4 as well
|
|
||||||
# - the rest work only on devices as far as we can tell right now
|
|
||||||
# In the future would be useful to have separate enums for receiver and device notification flags,
|
|
||||||
# but right now we don't know enough.
|
|
||||||
# additional flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing
|
|
||||||
NOTIFICATION_FLAG = _NamedInts(
|
|
||||||
numpad_numerical_keys=0x800000,
|
|
||||||
f_lock_status=0x400000,
|
|
||||||
roller_H=0x200000,
|
|
||||||
battery_status=0x100000, # send battery charge notifications (0x07 or 0x0D)
|
|
||||||
mouse_extra_buttons=0x080000,
|
|
||||||
roller_V=0x040000,
|
|
||||||
keyboard_sleep_raw=0x020000, # system control keys such as Sleep
|
|
||||||
keyboard_multimedia_raw=0x010000, # consumer controls such as Mute and Calculator
|
|
||||||
# reserved_r1b4= 0x001000, # unknown, seen on a unifying receiver
|
|
||||||
reserved5=0x008000,
|
|
||||||
reserved4=0x004000,
|
|
||||||
reserved3=0x002000,
|
|
||||||
reserved2=0x001000,
|
|
||||||
software_present=0x000800, # .. no idea
|
|
||||||
reserved1=0x000400,
|
|
||||||
keyboard_illumination=0x000200, # illumination brightness level changes (by pressing keys)
|
|
||||||
wireless=0x000100, # notify when the device wireless goes on/off-line
|
|
||||||
mx_air_3d_gesture=0x000001,
|
|
||||||
)
|
|
||||||
|
|
||||||
ERROR = _NamedInts(
|
|
||||||
invalid_SubID__command=0x01,
|
|
||||||
invalid_address=0x02,
|
|
||||||
invalid_value=0x03,
|
|
||||||
connection_request_failed=0x04,
|
|
||||||
too_many_devices=0x05,
|
|
||||||
already_exists=0x06,
|
|
||||||
busy=0x07,
|
|
||||||
unknown_device=0x08,
|
|
||||||
resource_error=0x09,
|
|
||||||
request_unavailable=0x0A,
|
|
||||||
unsupported_parameter_value=0x0B,
|
|
||||||
wrong_pin_code=0x0C
|
|
||||||
)
|
|
||||||
|
|
||||||
PAIRING_ERRORS = _NamedInts(device_timeout=0x01, device_not_supported=0x02, too_many_devices=0x03, sequence_timeout=0x06)
|
|
||||||
BOLT_PAIRING_ERRORS = _NamedInts(device_timeout=0x01, failed=0x02)
|
|
||||||
"""Known registers.
|
|
||||||
Devices usually have a (small) sub-set of these. Some registers are only
|
|
||||||
applicable to certain device kinds (e.g. smooth_scroll only applies to mice."""
|
|
||||||
REGISTERS = _NamedInts(
|
|
||||||
# only apply to receivers
|
|
||||||
receiver_connection=0x02,
|
|
||||||
receiver_pairing=0xB2,
|
|
||||||
devices_activity=0x2B3,
|
|
||||||
receiver_info=0x2B5,
|
|
||||||
bolt_device_discovery=0xC0,
|
|
||||||
bolt_pairing=0x2C1,
|
|
||||||
bolt_uniqueId=0x02FB,
|
|
||||||
|
|
||||||
# only apply to devices
|
|
||||||
mouse_button_flags=0x01,
|
|
||||||
keyboard_hand_detection=0x01,
|
|
||||||
battery_status=0x07,
|
|
||||||
keyboard_fn_swap=0x09,
|
|
||||||
battery_charge=0x0D,
|
|
||||||
keyboard_illumination=0x17,
|
|
||||||
three_leds=0x51,
|
|
||||||
mouse_dpi=0x63,
|
|
||||||
|
|
||||||
# apply to both
|
|
||||||
notifications=0x00,
|
|
||||||
firmware=0xF1,
|
|
||||||
|
|
||||||
# notifications
|
|
||||||
passkey_request_notification=0x4D,
|
|
||||||
passkey_pressed_notification=0x4E,
|
|
||||||
device_discovery_notification=0x4F,
|
|
||||||
discovery_status_notification=0x53,
|
|
||||||
pairing_status_notification=0x54,
|
|
||||||
)
|
|
||||||
# Subregisters for receiver_info register
|
|
||||||
INFO_SUBREGISTERS = _NamedInts(
|
|
||||||
serial_number=0x01, # not found on many receivers
|
|
||||||
fw_version=0x02,
|
|
||||||
receiver_information=0x03,
|
|
||||||
pairing_information=0x20, # 0x2N, by connected device
|
|
||||||
extended_pairing_information=0x30, # 0x3N, by connected device
|
|
||||||
device_name=0x40, # 0x4N, by connected device
|
|
||||||
bolt_pairing_information=0x50, # 0x5N, by connected device
|
|
||||||
bolt_device_name=0x60, # 0x6N01, by connected device,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing
|
|
||||||
DEVICE_FEATURES = _NamedInts(
|
|
||||||
reserved1=0x010000,
|
|
||||||
special_buttons=0x020000,
|
|
||||||
enhanced_key_usage=0x040000,
|
|
||||||
fast_fw_rev=0x080000,
|
|
||||||
reserved2=0x100000,
|
|
||||||
reserved3=0x200000,
|
|
||||||
scroll_accel=0x400000,
|
|
||||||
buttons_control_resolution=0x800000,
|
|
||||||
inhibit_lock_key_sound=0x000001,
|
|
||||||
reserved4=0x000002,
|
|
||||||
mx_air_3d_engine=0x000004,
|
|
||||||
host_control_leds=0x000008,
|
|
||||||
reserved5=0x000010,
|
|
||||||
reserved6=0x000020,
|
|
||||||
reserved7=0x000040,
|
|
||||||
reserved8=0x000080,
|
|
||||||
)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# functions
|
# functions
|
||||||
#
|
#
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
from .common import NamedInts
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constants - most of them as defined by the official Logitech HID++ 1.0
|
||||||
|
# documentation, some of them guessed.
|
||||||
|
#
|
||||||
|
|
||||||
|
DEVICE_KIND = NamedInts(
|
||||||
|
unknown=0x00,
|
||||||
|
keyboard=0x01,
|
||||||
|
mouse=0x02,
|
||||||
|
numpad=0x03,
|
||||||
|
presenter=0x04,
|
||||||
|
remote=0x07,
|
||||||
|
trackball=0x08,
|
||||||
|
touchpad=0x09,
|
||||||
|
headset=0x0D, # not from Logitech documentation
|
||||||
|
remote_control=0x0E, # for compatibility with HID++ 2.0
|
||||||
|
receiver=0x0F # for compatibility with HID++ 2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
POWER_SWITCH_LOCATION = NamedInts(
|
||||||
|
base=0x01,
|
||||||
|
top_case=0x02,
|
||||||
|
edge_of_top_right_corner=0x03,
|
||||||
|
top_left_corner=0x05,
|
||||||
|
bottom_left_corner=0x06,
|
||||||
|
top_right_corner=0x07,
|
||||||
|
bottom_right_corner=0x08,
|
||||||
|
top_edge=0x09,
|
||||||
|
right_edge=0x0A,
|
||||||
|
left_edge=0x0B,
|
||||||
|
bottom_edge=0x0C
|
||||||
|
)
|
||||||
|
|
||||||
|
# Some flags are used both by devices and receivers. The Logitech documentation
|
||||||
|
# mentions that the first and last (third) byte are used for devices while the
|
||||||
|
# second is used for the receiver. In practise, the second byte is also used for
|
||||||
|
# some device-specific notifications (keyboard illumination level). Do not
|
||||||
|
# simply set all notification bits if the software does not support it. For
|
||||||
|
# example, enabling keyboard_sleep_raw makes the Sleep key a no-operation unless
|
||||||
|
# the software is updated to handle that event.
|
||||||
|
# Observations:
|
||||||
|
# - wireless and software present were seen on receivers, reserved_r1b4 as well
|
||||||
|
# - the rest work only on devices as far as we can tell right now
|
||||||
|
# In the future would be useful to have separate enums for receiver and device notification flags,
|
||||||
|
# but right now we don't know enough.
|
||||||
|
# additional flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing
|
||||||
|
NOTIFICATION_FLAG = NamedInts(
|
||||||
|
numpad_numerical_keys=0x800000,
|
||||||
|
f_lock_status=0x400000,
|
||||||
|
roller_H=0x200000,
|
||||||
|
battery_status=0x100000, # send battery charge notifications (0x07 or 0x0D)
|
||||||
|
mouse_extra_buttons=0x080000,
|
||||||
|
roller_V=0x040000,
|
||||||
|
keyboard_sleep_raw=0x020000, # system control keys such as Sleep
|
||||||
|
keyboard_multimedia_raw=0x010000, # consumer controls such as Mute and Calculator
|
||||||
|
# reserved_r1b4= 0x001000, # unknown, seen on a unifying receiver
|
||||||
|
reserved5=0x008000,
|
||||||
|
reserved4=0x004000,
|
||||||
|
reserved3=0x002000,
|
||||||
|
reserved2=0x001000,
|
||||||
|
software_present=0x000800, # .. no idea
|
||||||
|
reserved1=0x000400,
|
||||||
|
keyboard_illumination=0x000200, # illumination brightness level changes (by pressing keys)
|
||||||
|
wireless=0x000100, # notify when the device wireless goes on/off-line
|
||||||
|
mx_air_3d_gesture=0x000001,
|
||||||
|
)
|
||||||
|
|
||||||
|
ERROR = NamedInts(
|
||||||
|
invalid_SubID__command=0x01,
|
||||||
|
invalid_address=0x02,
|
||||||
|
invalid_value=0x03,
|
||||||
|
connection_request_failed=0x04,
|
||||||
|
too_many_devices=0x05,
|
||||||
|
already_exists=0x06,
|
||||||
|
busy=0x07,
|
||||||
|
unknown_device=0x08,
|
||||||
|
resource_error=0x09,
|
||||||
|
request_unavailable=0x0A,
|
||||||
|
unsupported_parameter_value=0x0B,
|
||||||
|
wrong_pin_code=0x0C
|
||||||
|
)
|
||||||
|
|
||||||
|
PAIRING_ERRORS = NamedInts(device_timeout=0x01, device_not_supported=0x02, too_many_devices=0x03, sequence_timeout=0x06)
|
||||||
|
BOLT_PAIRING_ERRORS = NamedInts(device_timeout=0x01, failed=0x02)
|
||||||
|
"""Known registers.
|
||||||
|
Devices usually have a (small) sub-set of these. Some registers are only
|
||||||
|
applicable to certain device kinds (e.g. smooth_scroll only applies to mice."""
|
||||||
|
REGISTERS = NamedInts(
|
||||||
|
# only apply to receivers
|
||||||
|
receiver_connection=0x02,
|
||||||
|
receiver_pairing=0xB2,
|
||||||
|
devices_activity=0x2B3,
|
||||||
|
receiver_info=0x2B5,
|
||||||
|
bolt_device_discovery=0xC0,
|
||||||
|
bolt_pairing=0x2C1,
|
||||||
|
bolt_uniqueId=0x02FB,
|
||||||
|
|
||||||
|
# only apply to devices
|
||||||
|
mouse_button_flags=0x01,
|
||||||
|
keyboard_hand_detection=0x01,
|
||||||
|
battery_status=0x07,
|
||||||
|
keyboard_fn_swap=0x09,
|
||||||
|
battery_charge=0x0D,
|
||||||
|
keyboard_illumination=0x17,
|
||||||
|
three_leds=0x51,
|
||||||
|
mouse_dpi=0x63,
|
||||||
|
|
||||||
|
# apply to both
|
||||||
|
notifications=0x00,
|
||||||
|
firmware=0xF1,
|
||||||
|
|
||||||
|
# notifications
|
||||||
|
passkey_request_notification=0x4D,
|
||||||
|
passkey_pressed_notification=0x4E,
|
||||||
|
device_discovery_notification=0x4F,
|
||||||
|
discovery_status_notification=0x53,
|
||||||
|
pairing_status_notification=0x54,
|
||||||
|
)
|
||||||
|
# Subregisters for receiver_info register
|
||||||
|
INFO_SUBREGISTERS = NamedInts(
|
||||||
|
serial_number=0x01, # not found on many receivers
|
||||||
|
fw_version=0x02,
|
||||||
|
receiver_information=0x03,
|
||||||
|
pairing_information=0x20, # 0x2N, by connected device
|
||||||
|
extended_pairing_information=0x30, # 0x3N, by connected device
|
||||||
|
device_name=0x40, # 0x4N, by connected device
|
||||||
|
bolt_pairing_information=0x50, # 0x5N, by connected device
|
||||||
|
bolt_device_name=0x60, # 0x6N01, by connected device,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing
|
||||||
|
DEVICE_FEATURES = NamedInts(
|
||||||
|
reserved1=0x010000,
|
||||||
|
special_buttons=0x020000,
|
||||||
|
enhanced_key_usage=0x040000,
|
||||||
|
fast_fw_rev=0x080000,
|
||||||
|
reserved2=0x100000,
|
||||||
|
reserved3=0x200000,
|
||||||
|
scroll_accel=0x400000,
|
||||||
|
buttons_control_resolution=0x800000,
|
||||||
|
inhibit_lock_key_sound=0x000001,
|
||||||
|
reserved4=0x000002,
|
||||||
|
mx_air_3d_engine=0x000004,
|
||||||
|
host_control_leds=0x000008,
|
||||||
|
reserved5=0x000010,
|
||||||
|
reserved6=0x000020,
|
||||||
|
reserved7=0x000040,
|
||||||
|
reserved8=0x000080,
|
||||||
|
)
|
|
@ -173,7 +173,8 @@ class Receiver:
|
||||||
if not wpid:
|
if not wpid:
|
||||||
logger.error('Unable to get wpid from udev for device %d of %s', n, self)
|
logger.error('Unable to get wpid from udev for device %d of %s', n, self)
|
||||||
raise exceptions.NoSuchDevice(number=n, receiver=self, error='Not present 27Mhz device')
|
raise exceptions.NoSuchDevice(number=n, receiver=self, error='Not present 27Mhz device')
|
||||||
kind = _hidpp10.DEVICE_KIND[self.get_kind_from_index(n)]
|
kind = _hidpp10_constants.DEVICE_KIND[self.get_kind_from_index(n)]
|
||||||
|
|
||||||
elif not self.receiver_kind == 'unifying': # unifying protocol not supported, may be an old Nano receiver
|
elif not self.receiver_kind == 'unifying': # unifying protocol not supported, may be an old Nano receiver
|
||||||
device_info = self.read_register(_R.receiver_info, 0x04)
|
device_info = self.read_register(_R.receiver_info, 0x04)
|
||||||
if device_info:
|
if device_info:
|
||||||
|
@ -197,7 +198,7 @@ class Receiver:
|
||||||
return '?', power_switch
|
return '?', power_switch
|
||||||
pair_info = self.read_register(_R.receiver_info, _IR.extended_pairing_information + n - 1)
|
pair_info = self.read_register(_R.receiver_info, _IR.extended_pairing_information + n - 1)
|
||||||
if pair_info:
|
if pair_info:
|
||||||
power_switch = _hidpp10.POWER_SWITCH_LOCATION[ord(pair_info[9:10]) & 0x0F]
|
power_switch = _hidpp10_constants.POWER_SWITCH_LOCATION[ord(pair_info[9:10]) & 0x0F]
|
||||||
else: # some Nano receivers?
|
else: # some Nano receivers?
|
||||||
pair_info = self.read_register(0x2D5)
|
pair_info = self.read_register(0x2D5)
|
||||||
if pair_info:
|
if pair_info:
|
||||||
|
|
|
@ -26,7 +26,7 @@ from time import time as _time
|
||||||
from traceback import format_exc as _format_exc
|
from traceback import format_exc as _format_exc
|
||||||
|
|
||||||
from . import descriptors as _descriptors
|
from . import descriptors as _descriptors
|
||||||
from . import hidpp10 as _hidpp10
|
from . import hidpp10_constants as _hidpp10_constants
|
||||||
from . import hidpp20 as _hidpp20
|
from . import hidpp20 as _hidpp20
|
||||||
from . import special_keys as _special_keys
|
from . import special_keys as _special_keys
|
||||||
from .base import _HIDPP_Notification as _HIDPP_Notification
|
from .base import _HIDPP_Notification as _HIDPP_Notification
|
||||||
|
@ -58,8 +58,8 @@ from .special_keys import DISABLE as _DKEY
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_DK = _hidpp10.DEVICE_KIND
|
_DK = _hidpp10_constants.DEVICE_KIND
|
||||||
_R = _hidpp10.REGISTERS
|
_R = _hidpp10_constants.REGISTERS
|
||||||
_F = _hidpp20.FEATURE
|
_F = _hidpp20.FEATURE
|
||||||
|
|
||||||
_GG = _hidpp20.GESTURE
|
_GG = _hidpp20.GESTURE
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from . import hidpp10 as _hidpp10
|
from . import hidpp10 as _hidpp10
|
||||||
from . import hidpp20 as _hidpp20
|
from . import hidpp10_constants as _hidpp10_constants
|
||||||
|
from . import hidpp20_constants as _hidpp20_constants
|
||||||
from . import settings as _settings
|
from . import settings as _settings
|
||||||
from .common import BATTERY_APPROX as _BATTERY_APPROX
|
from .common import BATTERY_APPROX as _BATTERY_APPROX
|
||||||
from .common import NamedInt as _NamedInt
|
from .common import NamedInt as _NamedInt
|
||||||
|
@ -28,7 +29,7 @@ from .i18n import _, ngettext
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
_R = _hidpp10.REGISTERS
|
_R = _hidpp10_constants.REGISTERS
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -154,11 +155,11 @@ class DeviceStatus(dict):
|
||||||
# Some notifications may come with no battery level info, just
|
# Some notifications may come with no battery level info, just
|
||||||
# charging state info, so do our best to infer a level (even if it is just the last level)
|
# charging state info, so do our best to infer a level (even if it is just the last level)
|
||||||
# It is not always possible to do this well
|
# It is not always possible to do this well
|
||||||
if status == _hidpp20.BATTERY_STATUS.full:
|
if status == _hidpp20_constants.BATTERY_STATUS.full:
|
||||||
level = _BATTERY_APPROX.full
|
level = _BATTERY_APPROX.full
|
||||||
elif status in (_hidpp20.BATTERY_STATUS.almost_full, _hidpp20.BATTERY_STATUS.recharging):
|
elif status in (_hidpp20_constants.BATTERY_STATUS.almost_full, _hidpp20_constants.BATTERY_STATUS.recharging):
|
||||||
level = _BATTERY_APPROX.good
|
level = _BATTERY_APPROX.good
|
||||||
elif status == _hidpp20.BATTERY_STATUS.slow_recharge:
|
elif status == _hidpp20_constants.BATTERY_STATUS.slow_recharge:
|
||||||
level = _BATTERY_APPROX.low
|
level = _BATTERY_APPROX.low
|
||||||
else:
|
else:
|
||||||
level = self.get(KEYS.BATTERY_LEVEL)
|
level = self.get(KEYS.BATTERY_LEVEL)
|
||||||
|
@ -172,15 +173,15 @@ class DeviceStatus(dict):
|
||||||
old_voltage, self[KEYS.BATTERY_VOLTAGE] = self.get(KEYS.BATTERY_VOLTAGE), voltage
|
old_voltage, self[KEYS.BATTERY_VOLTAGE] = self.get(KEYS.BATTERY_VOLTAGE), voltage
|
||||||
|
|
||||||
charging = status in (
|
charging = status in (
|
||||||
_hidpp20.BATTERY_STATUS.recharging, _hidpp20.BATTERY_STATUS.almost_full, _hidpp20.BATTERY_STATUS.full,
|
_hidpp20_constants.BATTERY_STATUS.recharging, _hidpp20_constants.BATTERY_STATUS.almost_full, _hidpp20_constants.BATTERY_STATUS.full,
|
||||||
_hidpp20.BATTERY_STATUS.slow_recharge
|
_hidpp20_constants.BATTERY_STATUS.slow_recharge
|
||||||
)
|
)
|
||||||
old_charging, self[KEYS.BATTERY_CHARGING] = self.get(KEYS.BATTERY_CHARGING), charging
|
old_charging, self[KEYS.BATTERY_CHARGING] = self.get(KEYS.BATTERY_CHARGING), charging
|
||||||
|
|
||||||
changed = old_level != level or old_status != status or old_charging != charging or old_voltage != voltage
|
changed = old_level != level or old_status != status or old_charging != charging or old_voltage != voltage
|
||||||
alert, reason = ALERT.NONE, None
|
alert, reason = ALERT.NONE, None
|
||||||
|
|
||||||
if _hidpp20.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL):
|
if _hidpp20_constants.BATTERY_OK(status) and (level is None or level > _BATTERY_ATTENTION_LEVEL):
|
||||||
self[KEYS.ERROR] = None
|
self[KEYS.ERROR] = None
|
||||||
else:
|
else:
|
||||||
logger.warning('%s: battery %d%%, ALERT %s', self._device, level, status)
|
logger.warning('%s: battery %d%%, ALERT %s', self._device, level, status)
|
||||||
|
@ -238,7 +239,7 @@ class DeviceStatus(dict):
|
||||||
# when devices request software reconfiguration
|
# when devices request software reconfiguration
|
||||||
# and when devices become active if they don't have wireless device status feature,
|
# and when devices become active if they don't have wireless device status feature,
|
||||||
if was_active is None or push or not was_active and (
|
if was_active is None or push or not was_active and (
|
||||||
not d.features or _hidpp20.FEATURE.WIRELESS_DEVICE_STATUS not in d.features
|
not d.features or _hidpp20_constants.FEATURE.WIRELESS_DEVICE_STATUS not in d.features
|
||||||
):
|
):
|
||||||
if logger.isEnabledFor(logging.INFO):
|
if logger.isEnabledFor(logging.INFO):
|
||||||
logger.info('%s pushing device settings %s', d, d.settings)
|
logger.info('%s pushing device settings %s', d, d.settings)
|
||||||
|
|
|
@ -20,10 +20,11 @@ from time import time as _timestamp
|
||||||
|
|
||||||
from logitech_receiver import base as _base
|
from logitech_receiver import base as _base
|
||||||
from logitech_receiver import hidpp10 as _hidpp10
|
from logitech_receiver import hidpp10 as _hidpp10
|
||||||
|
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
||||||
from logitech_receiver import notifications as _notifications
|
from logitech_receiver import notifications as _notifications
|
||||||
from logitech_receiver import status as _status
|
from logitech_receiver import status as _status
|
||||||
|
|
||||||
_R = _hidpp10.REGISTERS
|
_R = _hidpp10_constants.REGISTERS
|
||||||
|
|
||||||
|
|
||||||
def run(receivers, args, find_receiver, _ignore):
|
def run(receivers, args, find_receiver, _ignore):
|
||||||
|
@ -42,8 +43,8 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
|
|
||||||
# check if it's necessary to set the notification flags
|
# check if it's necessary to set the notification flags
|
||||||
old_notification_flags = _hidpp10.get_notification_flags(receiver) or 0
|
old_notification_flags = _hidpp10.get_notification_flags(receiver) or 0
|
||||||
if not (old_notification_flags & _hidpp10.NOTIFICATION_FLAG.wireless):
|
if not (old_notification_flags & _hidpp10_constants.NOTIFICATION_FLAG.wireless):
|
||||||
_hidpp10.set_notification_flags(receiver, old_notification_flags | _hidpp10.NOTIFICATION_FLAG.wireless)
|
_hidpp10.set_notification_flags(receiver, old_notification_flags | _hidpp10_constants.NOTIFICATION_FLAG.wireless)
|
||||||
|
|
||||||
# get all current devices
|
# get all current devices
|
||||||
known_devices = [dev.number for dev in receiver]
|
known_devices = [dev.number for dev in receiver]
|
||||||
|
@ -85,7 +86,9 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
kind = receiver.status.device_kind
|
kind = receiver.status.device_kind
|
||||||
print(f'Bolt Pairing: discovered {name}')
|
print(f'Bolt Pairing: discovered {name}')
|
||||||
receiver.pair_device(
|
receiver.pair_device(
|
||||||
address=address, authentication=authentication, entropy=20 if kind == _hidpp10.DEVICE_KIND.keyboard else 10
|
address=address,
|
||||||
|
authentication=authentication,
|
||||||
|
entropy=20 if kind == _hidpp10_constants.DEVICE_KIND.keyboard else 10
|
||||||
)
|
)
|
||||||
pairing_start = _timestamp()
|
pairing_start = _timestamp()
|
||||||
patience = 5 # the discovering notification may come slightly later, so be patient
|
patience = 5 # the discovering notification may come slightly later, so be patient
|
||||||
|
@ -121,7 +124,7 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
if n:
|
if n:
|
||||||
receiver.handle.notifications_hook(n)
|
receiver.handle.notifications_hook(n)
|
||||||
|
|
||||||
if not (old_notification_flags & _hidpp10.NOTIFICATION_FLAG.wireless):
|
if not (old_notification_flags & _hidpp10_constants.NOTIFICATION_FLAG.wireless):
|
||||||
# only clear the flags if they weren't set before, otherwise a
|
# only clear the flags if they weren't set before, otherwise a
|
||||||
# concurrently running Solaar app might stop working properly
|
# concurrently running Solaar app might stop working properly
|
||||||
_hidpp10.set_notification_flags(receiver, old_notification_flags)
|
_hidpp10.set_notification_flags(receiver, old_notification_flags)
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
from logitech_receiver import base as _base
|
from logitech_receiver import base as _base
|
||||||
from logitech_receiver import hidpp10 as _hidpp10
|
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
||||||
from logitech_receiver.common import strhex as _strhex
|
from logitech_receiver.common import strhex as _strhex
|
||||||
from solaar.cli.show import _print_device, _print_receiver
|
from solaar.cli.show import _print_device, _print_receiver
|
||||||
|
|
||||||
_R = _hidpp10.REGISTERS
|
_R = _hidpp10_constants.REGISTERS
|
||||||
|
|
||||||
|
|
||||||
def run(receivers, args, find_receiver, _ignore):
|
def run(receivers, args, find_receiver, _ignore):
|
||||||
|
@ -90,9 +90,9 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
last = None
|
last = None
|
||||||
for sub in range(0, 0xFF):
|
for sub in range(0, 0xFF):
|
||||||
rgst = _base.request(receiver.handle, 0xFF, 0x8100 | reg, sub, return_error=True)
|
rgst = _base.request(receiver.handle, 0xFF, 0x8100 | reg, sub, return_error=True)
|
||||||
if isinstance(rgst, int) and rgst == _hidpp10.ERROR.invalid_address:
|
if isinstance(rgst, int) and rgst == _hidpp10_constants.ERROR.invalid_address:
|
||||||
break
|
break
|
||||||
elif isinstance(rgst, int) and rgst == _hidpp10.ERROR.invalid_value:
|
elif isinstance(rgst, int) and rgst == _hidpp10_constants.ERROR.invalid_value:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst:
|
if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst:
|
||||||
|
@ -104,9 +104,9 @@ def run(receivers, args, find_receiver, _ignore):
|
||||||
last = None
|
last = None
|
||||||
for sub in range(0, 0xFF):
|
for sub in range(0, 0xFF):
|
||||||
rgst = _base.request(receiver.handle, 0xFF, 0x8100 | (0x200 + reg), sub, return_error=True)
|
rgst = _base.request(receiver.handle, 0xFF, 0x8100 | (0x200 + reg), sub, return_error=True)
|
||||||
if isinstance(rgst, int) and rgst == _hidpp10.ERROR.invalid_address:
|
if isinstance(rgst, int) and rgst == _hidpp10_constants.ERROR.invalid_address:
|
||||||
break
|
break
|
||||||
elif isinstance(rgst, int) and rgst == _hidpp10.ERROR.invalid_value:
|
elif isinstance(rgst, int) and rgst == _hidpp10_constants.ERROR.invalid_value:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst:
|
if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst:
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
from logitech_receiver import exceptions
|
from logitech_receiver import exceptions
|
||||||
from logitech_receiver import hidpp10 as _hidpp10
|
from logitech_receiver import hidpp10 as _hidpp10
|
||||||
|
from logitech_receiver import hidpp10_constants as _hidpp10_constants
|
||||||
from logitech_receiver import hidpp20 as _hidpp20
|
from logitech_receiver import hidpp20 as _hidpp20
|
||||||
from logitech_receiver import receiver as _receiver
|
from logitech_receiver import receiver as _receiver
|
||||||
from logitech_receiver import settings_templates as _settings_templates
|
from logitech_receiver import settings_templates as _settings_templates
|
||||||
|
@ -46,12 +47,12 @@ def _print_receiver(receiver):
|
||||||
notification_flags = _hidpp10.get_notification_flags(receiver)
|
notification_flags = _hidpp10.get_notification_flags(receiver)
|
||||||
if notification_flags is not None:
|
if notification_flags is not None:
|
||||||
if notification_flags:
|
if notification_flags:
|
||||||
notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags)
|
notification_names = _hidpp10_constants.NOTIFICATION_FLAG.flag_names(notification_flags)
|
||||||
print(' Notifications: %s (0x%06X)' % (', '.join(notification_names), notification_flags))
|
print(' Notifications: %s (0x%06X)' % (', '.join(notification_names), notification_flags))
|
||||||
else:
|
else:
|
||||||
print(' Notifications: (none)')
|
print(' Notifications: (none)')
|
||||||
|
|
||||||
activity = receiver.read_register(_hidpp10.REGISTERS.devices_activity)
|
activity = receiver.read_register(_hidpp10_constants.REGISTERS.devices_activity)
|
||||||
if activity:
|
if activity:
|
||||||
activity = [(d, ord(activity[d - 1:d])) for d in range(1, receiver.max_devices)]
|
activity = [(d, ord(activity[d - 1:d])) for d in range(1, receiver.max_devices)]
|
||||||
activity_text = ', '.join(('%d=%d' % (d, a)) for d, a in activity if a > 0)
|
activity_text = ', '.join(('%d=%d' % (d, a)) for d, a in activity if a > 0)
|
||||||
|
@ -122,14 +123,14 @@ def _print_device(dev, num=None):
|
||||||
notification_flags = _hidpp10.get_notification_flags(dev)
|
notification_flags = _hidpp10.get_notification_flags(dev)
|
||||||
if notification_flags is not None:
|
if notification_flags is not None:
|
||||||
if notification_flags:
|
if notification_flags:
|
||||||
notification_names = _hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags)
|
notification_names = _hidpp10_constants.NOTIFICATION_FLAG.flag_names(notification_flags)
|
||||||
print(' Notifications: %s (0x%06X).' % (', '.join(notification_names), notification_flags))
|
print(' Notifications: %s (0x%06X).' % (', '.join(notification_names), notification_flags))
|
||||||
else:
|
else:
|
||||||
print(' Notifications: (none).')
|
print(' Notifications: (none).')
|
||||||
device_features = _hidpp10.get_device_features(dev)
|
device_features = _hidpp10.get_device_features(dev)
|
||||||
if device_features is not None:
|
if device_features is not None:
|
||||||
if device_features:
|
if device_features:
|
||||||
device_features_names = _hidpp10.DEVICE_FEATURES.flag_names(device_features)
|
device_features_names = _hidpp10_constants.DEVICE_FEATURES.flag_names(device_features)
|
||||||
print(' Features: %s (0x%06X)' % (', '.join(device_features_names), device_features))
|
print(' Features: %s (0x%06X)' % (', '.join(device_features_names), device_features))
|
||||||
else:
|
else:
|
||||||
print(' Features: (none)')
|
print(' Features: (none)')
|
||||||
|
|
Loading…
Reference in New Issue